Repository: OneKeyHQ/app-monorepo
Pull request #7198: Feat/optimize device cancel OK-37727 OK-31526 OK-30988 OK-33731
Author: login: ByteZhang1024
Created: 2025-04-23T12:34:07Z | Merged: 2025-04-24T01:33:35Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
  - Added improved handling and messaging for Bluetooth device bonding failures.
  - Enhanced modal exit prevention during firmware updates with a new cancellation action.

- **Bug Fixes**
  - Improved Bluetooth permission handling for Android devices on SDK version 30 or below.

- **Refactor**
  - Simplified Bluetooth management and hardware connection error handling for better reliability and maintainability.
  - Streamlined code for device connection and BLE state checking.

- **Chores**
  - Updated and replaced several Bluetooth-related dependencies and hardware SDK packages.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/apps/mobile/android/app/src/main/AndroidManifest.xml b/apps/mobile/android/app/src/main/AndroidManifest.xml
index 1625b23f647b..92ca46d2dd7e 100644
--- a/apps/mobile/android/app/src/main/AndroidManifest.xml
+++ b/apps/mobile/android/app/src/main/AndroidManifest.xml
@@ -4,7 +4,11 @@
         tools:node="remove" />
   <uses-permission
         android:name="android.permission.ACCESS_COARSE_LOCATION"
-        tools:node="remove" />
+        android:maxSdkVersion="30" />
+  <uses-permission
+        android:name="android.permission.ACCESS_FINE_LOCATION"
+        android:maxSdkVersion="30" />
+
   <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" tools:node="remove" />
   <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" tools:node="remove" />
 
diff --git a/apps/mobile/ios/Podfile.lock b/apps/mobile/ios/Podfile.lock
index 41285eb3dde3..ffc0b6cd1738 100644
--- a/apps/mobile/ios/Podfile.lock
+++ b/apps/mobile/ios/Podfile.lock
@@ -1,4 +1,8 @@
 PODS:
+  - BleUtils (0.1.4):
+    - glog
+    - RCT-Folly (= 2022.05.16.00)
+    - React-Core
   - boost (1.83.0)
   - Burnt (0.12.2):
     - ExpoModulesCore
@@ -127,7 +131,7 @@ PODS:
   - MMKV (1.3.1):
     - MMKVCore (~> 1.3.1)
   - MMKVCore (1.3.1)
-  - MultiplatformBleAdapter (0.1.9)
+  - MultiplatformBleAdapter (0.2.0)
   - PurchasesHybridCommon (13.14.0):
     - RevenueCat (= 5.14.0)
   - RCT-Folly (2022.05.16.00):
@@ -1001,10 +1005,10 @@ PODS:
   - React-Mapbuffer (0.73.7):
     - glog
     - React-debug
-  - react-native-ble-manager (10.1.5):
-    - React-Core
-  - react-native-ble-plx (3.0.0):
-    - MultiplatformBleAdapter (= 0.1.9)
+  - react-native-ble-plx (3.5.0):
+    - glog
+    - MultiplatformBleAdapter (= 0.2.0)
+    - RCT-Folly (= 2022.05.16.00)
     - React-Core
   - react-native-cloud-fs (2.6.3):
     - React
@@ -1324,6 +1328,7 @@ PODS:
     - ZXingObjC/Core
 
 DEPENDENCIES:
+  - BleUtils (from `../../../node_modules/react-native-ble-utils`)
   - boost (from `../../../node_modules/react-native/third-party-podspecs/boost.podspec`)
   - Burnt (from `../../../node_modules/burnt/ios`)
   - CheckBiometricAuthChanged (from `../../../node_modules/react-native-check-biometric-auth-changed`)
@@ -1388,8 +1393,7 @@ DEPENDENCIES:
   - React-jsinspector (from `../../../node_modules/react-native/ReactCommon/jsinspector-modern`)
   - React-logger (from `../../../node_modules/react-native/ReactCommon/logger`)
   - React-Mapbuffer (from `../../../node_modules/react-native/ReactCommon`)
-  - react-native-ble-manager (from `../../../node_modules/react-native-ble-manager`)
-  - "react-native-ble-plx (from `../../../node_modules/@onekeyfe/react-native-ble-plx`)"
+  - react-native-ble-plx (from `../../../node_modules/react-native-ble-plx`)
   - react-native-cloud-fs (from `../../../node_modules/react-native-cloud-fs`)
   - "react-native-compat (from `../../../node_modules/@walletconnect/react-native-compat`)"
   - react-native-get-random-values (from `../../../node_modules/react-native-get-random-values`)
@@ -1478,6 +1482,8 @@ SPEC REPOS:
     - ZXingObjC
 
 EXTERNAL SOURCES:
+  BleUtils:
+    :path: "../../../node_modules/react-native-ble-utils"
   boost:
     :podspec: "../../../node_modules/react-native/third-party-podspecs/boost.podspec"
   Burnt:
@@ -1601,10 +1607,8 @@ EXTERNAL SOURCES:
     :path: "../../../node_modules/react-native/ReactCommon/logger"
   React-Mapbuffer:
     :path: "../../../node_modules/react-native/ReactCommon"
-  react-native-ble-manager:
-    :path: "../../../node_modules/react-native-ble-manager"
   react-native-ble-plx:
-    :path: "../../../node_modules/@onekeyfe/react-native-ble-plx"
+    :path: "../../../node_modules/react-native-ble-plx"
   react-native-cloud-fs:
     :path: "../../../node_modules/react-native-cloud-fs"
   react-native-compat:
@@ -1723,6 +1727,7 @@ EXTERNAL SOURCES:
     :path: "../../../node_modules/react-native/ReactCommon/yoga"
 
 SPEC CHECKSUMS:
+  BleUtils: 06add4249b37bf9ef520ade8de0b6cf3fc8d9259
   boost: d3f49c53809116a5d38da093a8aa78bf551aed09
   Burnt: e3a3397e26172fca31a59bb27421475a58068836
   CheckBiometricAuthChanged: 3a1cda0319a8b4825aeacbdc1fc195c9acee307f
@@ -1774,9 +1779,9 @@ SPEC CHECKSUMS:
   lottie-react-native: 925b18f0275e811a98264da10cc2762d65980f1b
   MMKV: 5a07930c70c70b86cd87761a42c8f3836fb681d7
   MMKVCore: e50135dbd33235b6ab390635991bab437ab873c0
-  MultiplatformBleAdapter: 5a6a897b006764392f9cef785e4360f54fb9477d
+  MultiplatformBleAdapter: b1fddd0d499b96b607e00f0faa8e60648343dc1d
   PurchasesHybridCommon: ea662e5a551e6fc79c1eb17feb0478c01c59f3e6
-  RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0
+  RCT-Folly: cd21f1661364f975ae76b3308167ad66b09f53f5
   RCTRequired: 77f73950d15b8c1a2b48ba5b79020c3003d1c9b5
   RCTTypeSafety: ede1e2576424d89471ef553b2aed09fbbcc038e3
   React: 2ddb437e599df2f1bffa9b248de2de4cfa0227f0
@@ -1797,8 +1802,7 @@ SPEC CHECKSUMS:
   React-jsinspector: f356e49aa086380d3a4892708ca173ad31ac69c1
   React-logger: 3017d7c365f7df9a4575f13e98c1ef1d96b85ba5
   React-Mapbuffer: 385706f2ccd18b1096e12434bab765d7cc6ce7ef
-  react-native-ble-manager: b7ce735a9a79123a5e5af567b164d9918cf688e2
-  react-native-ble-plx: 25cf530d23fa20ca50e47a3e24e4e5fbfeb670e6
+  react-native-ble-plx: d2a4639679e8c1c2bcd539c3cf36b5460c834cc4
   react-native-cloud-fs: c86a54591a932e41d94b0965f16d0713150b1fd0
   react-native-compat: 6e7fd7799e8b4b0744b3e8c35e4d4e8d09af0335
   react-native-get-random-values: 419569b6ed3d15bfb9b6781b2f2e058f8e8d2698
diff --git a/apps/mobile/package.json b/apps/mobile/package.json
index 783437aafce2..8290223028ea 100644
--- a/apps/mobile/package.json
+++ b/apps/mobile/package.json
@@ -37,7 +37,7 @@
     "@formatjs/intl-pluralrules": "^4.3.3",
     "@notifee/react-native": "9.0.0",
     "@onekeyfe/react-native-animated-charts": "1.0.0",
-    "@onekeyfe/react-native-ble-plx": "3.0.0",
+    "@onekeyfe/react-native-ble-utils": "0.1.3",
     "@onekeyfe/react-native-lite-card": "1.0.12",
     "@onekeyfe/react-native-tab-page-view": "1.0.18",
     "@onekeyfe/react-native-text-input": "0.2.4",
@@ -91,7 +91,7 @@
     "path-browserify": "^1.0.1",
     "react": "18.2.0",
     "react-native": "0.73.7",
-    "react-native-ble-manager": "^10.0.2",
+    "react-native-ble-plx": "3.5.0",
     "react-native-camera-kit": "14.0.0-beta15",
     "react-native-canvas": "^0.1.39",
     "react-native-check-biometric-auth-changed": "0.1.1",
diff --git a/package.json b/package.json
index 4e4d42ee24ef..23a06c7e533a 100644
--- a/package.json
+++ b/package.json
@@ -68,11 +68,11 @@
     "@onekeyfe/cross-inpage-provider-injected": "2.2.23",
     "@onekeyfe/cross-inpage-provider-types": "2.2.23",
     "@onekeyfe/extension-bridge-hosted": "2.2.23",
-    "@onekeyfe/hd-ble-sdk": "1.0.25-alpha.10",
-    "@onekeyfe/hd-core": "1.0.25-alpha.10",
-    "@onekeyfe/hd-shared": "1.0.25-alpha.10",
-    "@onekeyfe/hd-transport": "1.0.25-alpha.10",
-    "@onekeyfe/hd-web-sdk": "1.0.25-alpha.10",
+    "@onekeyfe/hd-ble-sdk": "1.0.26-alpha.0",
+    "@onekeyfe/hd-core": "1.0.26-alpha.0",
+    "@onekeyfe/hd-shared": "1.0.26-alpha.0",
+    "@onekeyfe/hd-transport": "1.0.26-alpha.0",
+    "@onekeyfe/hd-web-sdk": "1.0.26-alpha.0",
     "@onekeyfe/onekey-cross-webview": "2.2.23",
     "@polkadot/extension-inject": "0.46.6",
     "@polkadot/types": "11.3.1",
diff --git a/packages/kit-bg/src/services/ServiceHardware/ServiceHardware.ts b/packages/kit-bg/src/services/ServiceHardware/ServiceHardware.ts
index 2b5d3fcd677a..bb922a539b7b 100644
--- a/packages/kit-bg/src/services/ServiceHardware/ServiceHardware.ts
+++ b/packages/kit-bg/src/services/ServiceHardware/ServiceHardware.ts
@@ -517,36 +517,10 @@ class ServiceHardware extends ServiceBase {
       connectId,
     });
 
-  private handlerConnectError = async (
-    e: any,
-    options?: {
-      connectId?: string;
-      awaitBonded?: boolean;
-      reconnect?: boolean;
-    },
-  ): Promise<Features | undefined> => {
+  private handlerConnectError = (e: any) => {
     const error: deviceErrors.OneKeyHardwareError | undefined =
       e as deviceErrors.OneKeyHardwareError;
 
-    const connectId = options?.connectId;
-    if (
-      platformEnv.isNativeAndroid &&
-      error instanceof deviceErrors.DeviceNotBonded &&
-      options?.awaitBonded &&
-      connectId
-    ) {
-      const checkBonded = await deviceUtils.checkDeviceBonded(connectId);
-      if (checkBonded) {
-        console.log('Android device was bonded, will connect');
-        try {
-          return await this.connectDevice(connectId);
-        } catch (innerError: any) {
-          // only handler error
-          return this.handlerConnectError(innerError);
-        }
-      }
-    }
-
     if (
       error instanceof deviceErrors.OneKeyHardwareError &&
       !error?.reconnect
@@ -573,11 +547,7 @@ class ServiceHardware extends ServiceBase {
       try {
         return await this.connectDevice(connectId);
       } catch (e: any) {
-        return this.handlerConnectError(e, {
-          connectId,
-          reconnect: false,
-          awaitBonded,
-        });
+        this.handlerConnectError(e);
       }
     } else {
       /**
@@ -641,15 +611,6 @@ class ServiceHardware extends ServiceBase {
       //
     }
 
-    if (!connectId) {
-      return;
-    }
-
-    if (this.isLastCancelLessThanMsAgo(connectId, 3000)) {
-      console.log('sdk.cancel too frequent, skip');
-      return;
-    }
-
     const fn = async () => {
       const sdk = await this.getSDKInstance();
       // sdk.cancel() always cause device re-emit UI_EVENT:  ui-close_window
@@ -657,9 +618,6 @@ class ServiceHardware extends ServiceBase {
       // cancel the hardware process
       // (cancel not working on enter pin on device mode, use getFeatures() later)
       try {
-        if (connectId) {
-          this.lastCancelAt[connectId] = Date.now();
-        }
         sdk.cancel(connectId);
       } catch (e: any) {
         const { message } = e || {};
@@ -667,23 +625,6 @@ class ServiceHardware extends ServiceBase {
       }
 
       console.log('sdk.cancel device: ', connectId);
-
-      // mute getFeatures error
-      try {
-        // force hardware drop process
-        if (forceDeviceResetToHome) {
-          console.log('sdk.cancel device getFeatures: ', connectId);
-          await this.getFeaturesWithoutCache({
-            connectId,
-            params: {
-              retryCount: 0,
-              skipWebDevicePrompt: true,
-            },
-          }); // TODO move to sdk.cancel()
-        }
-      } catch (error) {
-        // ignore
-      }
     };
 
     clearTimeout(this.cancelTimer);
diff --git a/packages/kit-bg/src/services/ServiceHardwareUI/ServiceHardwareUI.ts b/packages/kit-bg/src/services/ServiceHardwareUI/ServiceHardwareUI.ts
index e7a680d9b26f..0b36a787c40b 100644
--- a/packages/kit-bg/src/services/ServiceHardwareUI/ServiceHardwareUI.ts
+++ b/packages/kit-bg/src/services/ServiceHardwareUI/ServiceHardwareUI.ts
@@ -303,17 +303,6 @@ class ServiceHardwareUI extends ServiceBase {
         params,
       );
 
-      const waitForCancelDone = async () => {
-        if (
-          this.backgroundApi.serviceHardware.isLastCancelLessThanMsAgo(
-            connectId,
-            2000,
-          )
-        ) {
-          await timerUtils.wait(2000);
-        }
-      };
-
       if (connectId) {
         // The device update detection is postponed for two hours
         // and the automatic detection is resumed after the device communication is completed
@@ -334,7 +323,7 @@ class ServiceHardwareUI extends ServiceBase {
           });
         }
 
-        await waitForCancelDone();
+        // await waitForCancelDone();
 
         defaultLogger.account.accountCreatePerf.cancelDeviceBeforeProcessing({
           message: 'cancelableDelay',
@@ -353,7 +342,7 @@ class ServiceHardwareUI extends ServiceBase {
           },
         );
       } else {
-        await waitForCancelDone();
+        // await waitForCancelDone();
       }
 
       // test delay
diff --git a/packages/kit/src/views/FirmwareUpdate/components/FirmwareUpdateExitPrevent.ts b/packages/kit/src/views/FirmwareUpdate/components/FirmwareUpdateExitPrevent.ts
index 7b3c167646aa..6706f4071180 100644
--- a/packages/kit/src/views/FirmwareUpdate/components/FirmwareUpdateExitPrevent.ts
+++ b/packages/kit/src/views/FirmwareUpdate/components/FirmwareUpdateExitPrevent.ts
@@ -1,8 +1,11 @@
+import { useCallback } from 'react';
+
 import { useKeepAwake } from 'expo-keep-awake';
 import { useIntl } from 'react-intl';
 
 import { ETranslations } from '@onekeyhq/shared/src/locale';
 
+import backgroundApiProxy from '../../../background/instance/backgroundApiProxy';
 import {
   useAppExitPrevent,
   useExtensionUpdatingFromExpandTab,
@@ -26,6 +29,10 @@ export function FirmwareUpdateExitPrevent({
     id: ETranslations.update_quit_update_desc,
   });
 
+  const onConfirmCallback = useCallback(() => {
+    void backgroundApiProxy.serviceHardware.cancel({});
+  }, []);
+
   // Prevents screen locking
   useKeepAwake();
 
@@ -34,6 +41,7 @@ export function FirmwareUpdateExitPrevent({
     shouldPreventRemove,
     title,
     message,
+    onConfirm: onConfirmCallback,
   });
 
   // Prevent App exit
diff --git a/packages/kit/src/views/FirmwareUpdate/hooks/useFirmwareUpdateHooks.ts b/packages/kit/src/views/FirmwareUpdate/hooks/useFirmwareUpdateHooks.ts
index db06895ae5c1..5faef58d4ea5 100644
--- a/packages/kit/src/views/FirmwareUpdate/hooks/useFirmwareUpdateHooks.ts
+++ b/packages/kit/src/views/FirmwareUpdate/hooks/useFirmwareUpdateHooks.ts
@@ -22,10 +22,12 @@ export function useModalExitPrevent({
   title,
   message,
   shouldPreventRemove = true,
+  onConfirm,
 }: {
   title: string;
   message: string;
   shouldPreventRemove?: boolean;
+  onConfirm?: () => void;
 }) {
   const intl = useIntl();
   const navigation = useAppNavigation();
@@ -52,6 +54,7 @@ export function useModalExitPrevent({
         onConfirmText: intl.formatMessage({ id: ETranslations.global_quit }),
         onConfirm: () => {
           navigation.dispatch(data.action);
+          onConfirm?.();
         },
         onCancelText: intl.formatMessage({ id: ETranslations.global_cancel }),
         onClose: () => {
@@ -59,7 +62,7 @@ export function useModalExitPrevent({
         },
       });
     },
-    [message, navigation, title, intl],
+    [message, navigation, title, intl, onConfirm],
   );
   usePreventRemove(shouldPreventRemove, navPreventRemoveCallback);
 }
diff --git a/packages/kit/src/views/Onboarding/pages/ConnectHardwareWallet/ConnectYourDevice.tsx b/packages/kit/src/views/Onboarding/pages/ConnectHardwareWallet/ConnectYourDevice.tsx
index d51e3800b7a7..232143e54052 100644
--- a/packages/kit/src/views/Onboarding/pages/ConnectHardwareWallet/ConnectYourDevice.tsx
+++ b/packages/kit/src/views/Onboarding/pages/ConnectHardwareWallet/ConnectYourDevice.tsx
@@ -161,6 +161,17 @@ type IConnectYourDeviceItem = {
 
 function DeviceListItem({ item }: { item: IConnectYourDeviceItem }) {
   const [isLoading, setIsLoading] = useState(false);
+
+  const onPress = useCallback(async () => {
+    if (isLoading) return;
+    try {
+      setIsLoading(true);
+      await item.onPress();
+    } finally {
+      setIsLoading(false);
+    }
+  }, [item, isLoading]);
+
   return (
     <ListItem
       opacity={item.opacity ?? 0.5}
@@ -176,15 +187,7 @@ function DeviceListItem({ item }: { item: IConnectYourDeviceItem }) {
       title={item.title}
       drillIn
       isLoading={isLoading}
-      // TODO add loading for onPress
-      onPress={async () => {
-        try {
-          setIsLoading(true);
-          await item.onPress();
-        } finally {
-          setIsLoading(false);
-        }
-      }}
+      onPress={onPress}
     />
   );
 }
@@ -849,11 +852,7 @@ function ConnectByUSBOrBLE() {
   );
 
   const checkBLEState = useCallback(async () => {
-    // hack missing getBleManager.
-    await bleManagerInstance.getBleManager();
-    await timerUtils.wait(100);
-    const bleManager = await bleManagerInstance.getBleManager();
-    const checkState = await bleManager?.checkState();
+    const checkState = await bleManagerInstance.checkState();
     return checkState === 'on';
   }, []);
 
diff --git a/packages/shared/src/errors/errors/hardwareErrors.ts b/packages/shared/src/errors/errors/hardwareErrors.ts
index 77a23f40ed7d..6d8c67c7f5c6 100644
--- a/packages/shared/src/errors/errors/hardwareErrors.ts
+++ b/packages/shared/src/errors/errors/hardwareErrors.ts
@@ -295,6 +295,20 @@ export class DeviceNotBonded extends OneKeyHardwareError {
   override code = HardwareErrorCode.BleDeviceNotBonded;
 }
 
+// 设备没有配对成功
+export class BleDeviceBondedCanceled extends OneKeyHardwareError {
+  constructor(props?: IOneKeyErrorHardwareProps) {
+    super(
+      normalizeErrorProps(props, {
+        defaultMessage: 'BleDeviceBondedCanceled',
+        defaultKey: ETranslations.feedback_bluetooth_pairing_failed,
+      }),
+    );
+  }
+
+  override code = HardwareErrorCode.BleDeviceNotBonded;
+}
+
 // 设备配对失败
 export class DeviceBondError extends OneKeyHardwareError {
   constructor(props?: IOneKeyErrorHardwareProps) {
diff --git a/packages/shared/src/errors/utils/deviceErrorUtils.ts b/packages/shared/src/errors/utils/deviceErrorUtils.ts
index b11348fb993b..fc6ecce6fc8a 100644
--- a/packages/shared/src/errors/utils/deviceErrorUtils.ts
+++ b/packages/shared/src/errors/utils/deviceErrorUtils.ts
@@ -120,6 +120,8 @@ export function convertDeviceError(
       return new HardwareErrors.BleLocationServiceError({ payload });
     case HardwareErrorCode.BleDeviceNotBonded:
       return new HardwareErrors.DeviceNotBonded({ payload });
+    case HardwareErrorCode.BleDeviceBondedCanceled:
+      return new HardwareErrors.DeviceNotBonded({ payload });
     case HardwareErrorCode.BleDeviceBondError:
       return new HardwareErrors.DeviceBondError({ payload });
     case HardwareErrorCode.BleWriteCharacteristicError:
diff --git a/packages/shared/src/hardware/bleManager/index.native.ts b/packages/shared/src/hardware/bleManager/index.native.ts
index 137189acd940..4133c92b16b7 100644
--- a/packages/shared/src/hardware/bleManager/index.native.ts
+++ b/packages/shared/src/hardware/bleManager/index.native.ts
@@ -1,66 +1,10 @@
-import BleManager from 'react-native-ble-manager';
-
-import platformEnv from '../../platformEnv';
-import { equalsIgnoreCase } from '../../utils/stringUtils';
-
-type IPollFn<T> = (time?: number, index?: number, rate?: number) => T;
-const POLL_INTERVAL = 1000;
-const POLL_INTERVAL_RATE = 1.5;
+import BleManager from '@onekeyfe/react-native-ble-utils';
 
 class BleManagerInstance {
-  bleManager?: typeof BleManager;
-
-  async getBleManager() {
-    if (!platformEnv.isNative) return null;
-    if (this.bleManager) {
-      return Promise.resolve(this.bleManager);
-    }
-    await BleManager.start({ showAlert: false });
-    this.bleManager = BleManager;
-  }
-
-  /**
-   * get bonded devices (only android)
-   * @returns Bound device
-   */
-  async getBondedDevices() {
-    const bleManager = await this.getBleManager();
-    if (!bleManager) {
-      return [];
-    }
-    const peripherals = await bleManager.getBondedPeripherals();
-    return peripherals.map((peripheral) => {
-      const { id, name, advertising = {} } = peripheral;
-      return { id, name, ...advertising };
-    });
-  }
-
-  async checkDeviceBonded(connectId: string) {
-    let retry = 0;
-    const maxRetryCount = 5;
-    const poll: IPollFn<Promise<boolean | undefined>> = async (
-      time = POLL_INTERVAL,
-    ) => {
-      retry += 1;
-      const bondedDevices = await this.getBondedDevices();
-
-      const hasBonded = !!bondedDevices.find((bondedDevice) =>
-        equalsIgnoreCase(bondedDevice.id, connectId),
-      );
-
-      if (hasBonded) {
-        return Promise.resolve(true);
-      }
-
-      if (retry > maxRetryCount) {
-        return Promise.resolve(false);
-      }
-
-      return new Promise((resolve: (p: Promise<boolean | undefined>) => void) =>
-        setTimeout(() => resolve(poll(3000 * POLL_INTERVAL_RATE)), time),
-      );
-    };
-    return poll();
+  checkState(): Promise<'on' | 'off'> {
+    return BleManager.checkState().then((state) =>
+      state === 'on' ? 'on' : 'off',
+    );
   }
 }
 
diff --git a/packages/shared/src/hardware/bleManager/index.ts b/packages/shared/src/hardware/bleManager/index.ts
index 50be6d0697bd..452b2fe3d461 100644
--- a/packages/shared/src/hardware/bleManager/index.ts
+++ b/packages/shared/src/hardware/bleManager/index.ts
@@ -1,22 +1,6 @@
-type IBleManager = {
-  checkState(): Promise<'on' | 'off'>;
-};
 class BleManagerInstance {
-  async getBleManager(): Promise<IBleManager | undefined> {
-    return undefined;
-  }
-
-  /**
-   * get bonded devices (only android)
-   * @returns Bound device
-   */
-  async getBondedDevices() {
-    return [];
-  }
-
-  // eslint-disable-next-line @typescript-eslint/no-unused-vars
-  async checkDeviceBonded(connectId: string) {
-    return Promise.resolve(false);
+  checkState(): Promise<'on' | 'off'> {
+    return Promise.resolve('on');
   }
 }
 
diff --git a/packages/shared/src/utils/deviceUtils.ts b/packages/shared/src/utils/deviceUtils.ts
index f6423b150c05..dff176effe88 100644
--- a/packages/shared/src/utils/deviceUtils.ts
+++ b/packages/shared/src/utils/deviceUtils.ts
@@ -12,7 +12,6 @@ import {
   EFirmwareVerifyType,
   EOneKeyDeviceMode,
 } from '../../types/device';
-import bleManagerInstance from '../hardware/bleManager';
 import { CoreSDKLoader } from '../hardware/instance';
 import platformEnv from '../platformEnv';
 
@@ -210,10 +209,6 @@ function getUpdatingConnectId({
   return platformEnv.isNative ? connectId : undefined;
 }
 
-async function checkDeviceBonded(connectId: string) {
-  return bleManagerInstance.checkDeviceBonded(connectId);
-}
-
 async function buildDeviceLabel({
   features,
   buildModelName,
@@ -463,7 +458,6 @@ export default {
   getDeviceScanner,
   getUpdatingConnectId,
   isConfirmOnDeviceAction,
-  checkDeviceBonded,
   buildDeviceLabel,
   buildDeviceName,
   buildDeviceBleName,
diff --git a/yarn.lock b/yarn.lock
index c041b1e4c6be..746df72b5ede 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6354,23 +6354,23 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@onekeyfe/hd-ble-sdk@npm:1.0.25-alpha.10":
-  version: 1.0.25-alpha.10
-  resolution: "@onekeyfe/hd-ble-sdk@npm:1.0.25-alpha.10"
+"@onekeyfe/hd-ble-sdk@npm:1.0.26-alpha.0":
+  version: 1.0.26-alpha.0
+  resolution: "@onekeyfe/hd-ble-sdk@npm:1.0.26-alpha.0"
   dependencies:
-    "@onekeyfe/hd-core": "npm:^1.0.25-alpha.10"
-    "@onekeyfe/hd-shared": "npm:^1.0.25-alpha.10"
-    "@onekeyfe/hd-transport-react-native": "npm:^1.0.25-alpha.10"
-  checksum: 10/79080e8f2fc97160719f8a2c399c5bf88c1bf755d6418377f2c63460fed51d4fd331af4f247b4c324c1df73c4d671a0a52c714df4efb697121af2ee8edd3a858
+    "@onekeyfe/hd-core": "npm:^1.0.26-alpha.0"
+    "@onekeyfe/hd-shared": "npm:^1.0.26-alpha.0"
+    "@onekeyfe/hd-transport-react-native": "npm:^1.0.26-alpha.0"
+  checksum: 10/93fe11564bec12f2b9482602973e41d53d8a24de06ba7d9423b44593c658ea9846abf653f940a172e63d9a325dbd18d30e474e5f6cac9d3ad6cba8dd1ebd0b64
   languageName: node
   linkType: hard
 
-"@onekeyfe/hd-core@npm:1.0.25-alpha.10, @onekeyfe/hd-core@npm:^1.0.25-alpha.10":
-  version: 1.0.25-alpha.10
-  resolution: "@onekeyfe/hd-core@npm:1.0.25-alpha.10"
+"@onekeyfe/hd-core@npm:1.0.26-alpha.0, @onekeyfe/hd-core@npm:^1.0.26-alpha.0":
+  version: 1.0.26-alpha.0
+  resolution: "@onekeyfe/hd-core@npm:1.0.26-alpha.0"
   dependencies:
-    "@onekeyfe/hd-shared": "npm:^1.0.25-alpha.10"
-    "@onekeyfe/hd-transport": "npm:^1.0.25-alpha.10"
+    "@onekeyfe/hd-shared": "npm:^1.0.26-alpha.0"
+    "@onekeyfe/hd-transport": "npm:^1.0.26-alpha.0"
     axios: "npm:^0.27.2"
     bignumber.js: "npm:^9.0.2"
     bytebuffer: "npm:^5.0.1"
@@ -6380,71 +6380,71 @@ __metadata:
   peerDependencies:
     "@noble/hashes": ^1.1.3
     ripple-keypairs: ^1.1.4
-  checksum: 10/1fcc8b124f9816b20141210472f4ddb326d9cb17094213e09941bf431ae54e764a7344267f5210a1f3c427f9538455e5565ba8d154ac3ad9adf314ac4685a59e
+  checksum: 10/ce59654bdbaea0a2884049ec5115c16713f42c1430c4a618b236d881a29e6fa6fc36f8c80ac3680f95f867abf75f7b1c69c1d7f6da22fc4b74dadf9034bb90e0
   languageName: node
   linkType: hard
 
-"@onekeyfe/hd-shared@npm:1.0.25-alpha.10, @onekeyfe/hd-shared@npm:^1.0.25-alpha.10":
-  version: 1.0.25-alpha.10
-  resolution: "@onekeyfe/hd-shared@npm:1.0.25-alpha.10"
-  checksum: 10/77d3dd70057e84ed4b935e16d41579bbcd6a31ee6ed254b2ab6c8b3002e603eea1572c50a79f01284cdbdd4f54e5ed9201bba5526c7e098df52775ee2d63959c
+"@onekeyfe/hd-shared@npm:1.0.26-alpha.0, @onekeyfe/hd-shared@npm:^1.0.26-alpha.0":
+  version: 1.0.26-alpha.0
+  resolution: "@onekeyfe/hd-shared@npm:1.0.26-alpha.0"
+  checksum: 10/85093f928d9366d180b4e1709629e6b9e7f49bd35d90c47b41093de8c98789446556f94b8a61b15f3fd63672cd76d2ce78b28ce1eec6ff58ca0509124375cae4
   languageName: node
   linkType: hard
 
-"@onekeyfe/hd-transport-http@npm:^1.0.25-alpha.10":
-  version: 1.0.25-alpha.10
-  resolution: "@onekeyfe/hd-transport-http@npm:1.0.25-alpha.10"
+"@onekeyfe/hd-transport-http@npm:^1.0.26-alpha.0":
+  version: 1.0.26-alpha.0
+  resolution: "@onekeyfe/hd-transport-http@npm:1.0.26-alpha.0"
   dependencies:
-    "@onekeyfe/hd-shared": "npm:^1.0.25-alpha.10"
-    "@onekeyfe/hd-transport": "npm:^1.0.25-alpha.10"
+    "@onekeyfe/hd-shared": "npm:^1.0.26-alpha.0"
+    "@onekeyfe/hd-transport": "npm:^1.0.26-alpha.0"
     axios: "npm:^0.27.2"
-  checksum: 10/ff8d16d1546a57f52d384b0ca980f32695264870f39b912c6f671054c56761c4e1e9c0aa68118a34f80f48db403eab88c9f2fa5fe85466d81aed39605e8a666b
+  checksum: 10/7e09343f905f69a2fe5a8b994a41b8790823fd4954b47cb300cdc684c074c9dcd37a2958d0a1b69e425897b539b5f32c312c1908776b26c5c19657d217b88fa5
   languageName: node
   linkType: hard
 
-"@onekeyfe/hd-transport-react-native@npm:^1.0.25-alpha.10":
-  version: 1.0.25-alpha.10
-  resolution: "@onekeyfe/hd-transport-react-native@npm:1.0.25-alpha.10"
+"@onekeyfe/hd-transport-react-native@npm:^1.0.26-alpha.0":
+  version: 1.0.26-alpha.0
+  resolution: "@onekeyfe/hd-transport-react-native@npm:1.0.26-alpha.0"
   dependencies:
-    "@onekeyfe/hd-shared": "npm:^1.0.25-alpha.10"
-    "@onekeyfe/hd-transport": "npm:^1.0.25-alpha.10"
-    "@onekeyfe/react-native-ble-plx": "npm:3.0.1"
-    react-native-ble-manager: "npm:^8.1.0"
-  checksum: 10/4ea15d48818c6245f124140cc6d2e87ce659232676abef7fbb38c76876d054134c843ccc892b0b0ac12ab9a4a3d9d82e5240b56a0a2f05087f8687a4b30da4f9
+    "@onekeyfe/hd-shared": "npm:^1.0.26-alpha.0"
+    "@onekeyfe/hd-transport": "npm:^1.0.26-alpha.0"
+    "@onekeyfe/react-native-ble-utils": "npm:^0.1.3"
+    react-native-ble-plx: "npm:3.5.0"
+  checksum: 10/a85b163915536b979a137507eec2c59276a45ad9d15111a0cafbda02d566843e920f8205dfd586eac9c88a5b55449b6f949927a422d80e58878b3b4df479d28a
   languageName: node
   linkType: hard
 
-"@onekeyfe/hd-transport-webusb@npm:^1.0.25-alpha.10":
-  version: 1.0.25-alpha.10
-  resolution: "@onekeyfe/hd-transport-webusb@npm:1.0.25-alpha.10"
+"@onekeyfe/hd-transport-webusb@npm:^1.0.26-alpha.0":
+  version: 1.0.26-alpha.0
+  resolution: "@onekeyfe/hd-transport-webusb@npm:1.0.26-alpha.0"
   dependencies:
-    "@onekeyfe/hd-shared": "npm:^1.0.25-alpha.10"
-    "@onekeyfe/hd-transport": "npm:^1.0.25-alpha.10"
-  checksum: 10/985cd027bba1a509dff8c80e2a0e4ea9f85027828434be577d96fa5fae7feaaa6e812999b9717fb6feb36a9dcc4f6e1b2c8937591854fb3f53fb503676035756
+    "@onekeyfe/hd-shared": "npm:^1.0.26-alpha.0"
+    "@onekeyfe/hd-transport": "npm:^1.0.26-alpha.0"
+  checksum: 10/2f4014c9315440cb51686cb77d2c2e648a935daf6943aa497d8cdf3b5ff77fccd05e4f21ce0c0a28b490e7bc1b343dd3d6fc593eec75cad6a647d85d61514462
   languageName: node
   linkType: hard
 
-"@onekeyfe/hd-transport@npm:1.0.25-alpha.10, @onekeyfe/hd-transport@npm:^1.0.25-alpha.10":
-  version: 1.0.25-alpha.10
-  resolution: "@onekeyfe/hd-transport@npm:1.0.25-alpha.10"
+"@onekeyfe/hd-transport@npm:1.0.26-alpha.0, @onekeyfe/hd-transport@npm:^1.0.26-alpha.0":
+  version: 1.0.26-alpha.0
+  resolution: "@onekeyfe/hd-transport@npm:1.0.26-alpha.0"
   dependencies:
     bytebuffer: "npm:^5.0.1"
     long: "npm:^4.0.0"
     protobufjs: "npm:^6.11.2"
-  checksum: 10/c4de5763b6aa6df4b9a72ccfea6ea21c16b76a7bbf8fd390bf47debd98f5888ef3c3ae61146671133846c152e08e86e81408e4fdef7ccf8a6ac39410ddd8b8ef
+  checksum: 10/1f837fa7188477b9c87dc330ed4e53beab9e7924fb78160d4298c626e4978adc7e1c60d859280f95ba4680aaf8c3d404daebf1121b43013c18d129ccccdb502e
   languageName: node
   linkType: hard
 
-"@onekeyfe/hd-web-sdk@npm:1.0.25-alpha.10":
-  version: 1.0.25-alpha.10
-  resolution: "@onekeyfe/hd-web-sdk@npm:1.0.25-alpha.10"
+"@onekeyfe/hd-web-sdk@npm:1.0.26-alpha.0":
+  version: 1.0.26-alpha.0
+  resolution: "@onekeyfe/hd-web-sdk@npm:1.0.26-alpha.0"
   dependencies:
     "@onekeyfe/cross-inpage-provider-core": "npm:^0.0.17"
-    "@onekeyfe/hd-core": "npm:^1.0.25-alpha.10"
-    "@onekeyfe/hd-shared": "npm:^1.0.25-alpha.10"
-    "@onekeyfe/hd-transport-http": "npm:^1.0.25-alpha.10"
-    "@onekeyfe/hd-transport-webusb": "npm:^1.0.25-alpha.10"
-  checksum: 10/fe30035581cf726af053b1ede89534d26441b29e63ebd4e23489128eee60e81318c26a8898aca69121e344ce274ba176b474e63e86bee0b0f6292231ea725718
+    "@onekeyfe/hd-core": "npm:^1.0.26-alpha.0"
+    "@onekeyfe/hd-shared": "npm:^1.0.26-alpha.0"
+    "@onekeyfe/hd-transport-http": "npm:^1.0.26-alpha.0"
+    "@onekeyfe/hd-transport-webusb": "npm:^1.0.26-alpha.0"
+  checksum: 10/faa5c14ab409eeccf263b17ee5b312ec9e29d25080f12351856eb9e6776a0845a67868e22890707475e83e56529fd090119b4cb2284e137adf3aa25ab5321eee
   languageName: node
   linkType: hard
 
@@ -6810,17 +6810,13 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@onekeyfe/react-native-ble-plx@npm:3.0.0":
-  version: 3.0.0
-  resolution: "@onekeyfe/react-native-ble-plx@npm:3.0.0"
-  checksum: 10/df7deed77e7756eb3a99595e475b9c9b7c7edf20aa7a162cc751ddd6440d0d56ff2572dad4850e8b02628893598db3d303a830263ba5866f48664b85bbd12dfb
-  languageName: node
-  linkType: hard
-
-"@onekeyfe/react-native-ble-plx@npm:3.0.1":
-  version: 3.0.1
-  resolution: "@onekeyfe/react-native-ble-plx@npm:3.0.1"
-  checksum: 10/a7764e87a107c8060c39f0643d905cc16e82f6c0ffe1a86bd54d906b55b0d9141f5105106d99bc293f7ed5f4aad601bd999fc0dda5fdd788eaf2900bc1504eaa
+"@onekeyfe/react-native-ble-utils@npm:0.1.3, @onekeyfe/react-native-ble-utils@npm:^0.1.3":
+  version: 0.1.3
+  resolution: "@onekeyfe/react-native-ble-utils@npm:0.1.3"
+  peerDependencies:
+    react: "*"
+    react-native: "*"
+  checksum: 10/03c4f5584dddf6e10f236eda5d56d87c56171454b3b43dc750aadf6f9d3f7a8981a911fe0a5f4a19651d1cb74efd5fe10319ace62d241eabaae8a56c6d38a409
   languageName: node
   linkType: hard
 
@@ -6882,11 +6878,11 @@ __metadata:
     "@onekeyfe/cross-inpage-provider-injected": "npm:2.2.23"
     "@onekeyfe/cross-inpage-provider-types": "npm:2.2.23"
     "@onekeyfe/extension-bridge-hosted": "npm:2.2.23"
-    "@onekeyfe/hd-ble-sdk": "npm:1.0.25-alpha.10"
-    "@onekeyfe/hd-core": "npm:1.0.25-alpha.10"
-    "@onekeyfe/hd-shared": "npm:1.0.25-alpha.10"
-    "@onekeyfe/hd-transport": "npm:1.0.25-alpha.10"
-    "@onekeyfe/hd-web-sdk": "npm:1.0.25-alpha.10"
+    "@onekeyfe/hd-ble-sdk": "npm:1.0.26-alpha.0"
+    "@onekeyfe/hd-core": "npm:1.0.26-alpha.0"
+    "@onekeyfe/hd-shared": "npm:1.0.26-alpha.0"
+    "@onekeyfe/hd-transport": "npm:1.0.26-alpha.0"
+    "@onekeyfe/hd-web-sdk": "npm:1.0.26-alpha.0"
     "@onekeyfe/onekey-cross-webview": "npm:2.2.23"
     "@open-wc/webpack-import-meta-loader": "npm:^0.4.7"
     "@pmmmwh/react-refresh-webpack-plugin": "npm:^0.5.11"
@@ -7241,7 +7237,7 @@ __metadata:
     "@formatjs/intl-pluralrules": "npm:^4.3.3"
     "@notifee/react-native": "npm:9.0.0"
     "@onekeyfe/react-native-animated-charts": "npm:1.0.0"
-    "@onekeyfe/react-native-ble-plx": "npm:3.0.0"
+    "@onekeyfe/react-native-ble-utils": "npm:0.1.3"
     "@onekeyfe/react-native-lite-card": "npm:1.0.12"
     "@onekeyfe/react-native-tab-page-view": "npm:1.0.18"
     "@onekeyfe/react-native-text-input": "npm:0.2.4"
@@ -7296,7 +7292,7 @@ __metadata:
     path-browserify: "npm:^1.0.1"
     react: "npm:18.2.0"
     react-native: "npm:0.73.7"
-    react-native-ble-manager: "npm:^10.0.2"
+    react-native-ble-plx: "npm:3.5.0"
     react-native-bundle-visualizer: "npm:^3.1.3"
     react-native-camera-kit: "npm:14.0.0-beta15"
     react-native-canvas: "npm:^0.1.39"
@@ -35133,19 +35129,13 @@ __metadata:
   languageName: node
   linkType: hard
 
-"react-native-ble-manager@npm:^10.0.2":
-  version: 10.1.5
-  resolution: "react-native-ble-manager@npm:10.1.5"
+"react-native-ble-plx@npm:3.5.0":
+  version: 3.5.0
+  resolution: "react-native-ble-plx@npm:3.5.0"
   peerDependencies:
-    react-native: ">=0.60.0"
-  checksum: 10/af2819ac1ebfcad4d1efafa1d494881a5cf00e71e1bfcfcc93e95083a3a1e65d852eb9b4f0be8df9c5584591c2afd2cae453a192485cf382f63c0c8aaa0123b9
-  languageName: node
-  linkType: hard
-
-"react-native-ble-manager@npm:^8.1.0":
-  version: 8.8.0
-  resolution: "react-native-ble-manager@npm:8.8.0"
-  checksum: 10/4cac80578a398268ea628489c9e43f12413a91a847571b8630bc33d532566b8042725ffed352b0979d61d256f1f1e52a2dbc4254d222daaf38383fc515725c4f
+    react: "*"
+    react-native: "*"
+  checksum: 10/f807e82d45220eeb5ba3aacaf13fddd9e11395337b8b2b99fe468cc154fefdce501efefcb1421b6bcf0f0e602e82ce535ff8dc3b1d1e57aca85fd6507bc7ea2e
   languageName: node
   linkType: hard
 


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>🔭 Outside diff range comments (3)</summary><blockquote>

<details>
<summary>packages/kit-bg/src/services/ServiceHardware/ServiceHardware.ts (3)</summary><blockquote>

`520-531`: _🛠️ Refactor suggestion_

_⚠️ Potential issue_

**`handlerConnectError` silently swallows recoverable errors**  

The new implementation only re‑throws `OneKeyHardwareError`s that have `reconnect === false`.  
For every other case the function exits without returning or throwing, causing the caller to believe the operation succeeded while the connection has actually failed. This leads to confusing “undefined” results downstream.

```diff
-private handlerConnectError = (e: any) => {
-  const error: deviceErrors.OneKeyHardwareError | undefined =
-    e as deviceErrors.OneKeyHardwareError;
-
-  if (
-    error instanceof deviceErrors.OneKeyHardwareError &&
-    !error?.reconnect
-  ) {
-    throw error;
-  }
-  // TODO handle reconnect?
-};
+private handlerConnectError = (raw: unknown): never => {
+  const error =
+    raw instanceof Error
+      ? raw
+      : new Error(typeof raw === 'string' ? raw : 'Unknown hardware error');
+
+  // Propagate non‑reconnectable hardware errors.
+  if (error instanceof deviceErrors.OneKeyHardwareError && !error.reconnect) {
+    throw error;
+  }
+
+  // All other cases should still bubble up so the caller can decide.
+  throw error;
+}
```

Benefits  
• Guarantees callers never get a false “success”.  
• Keeps stack‑trace intact.  
• Removes the `any` type.

---

`546-552`: _⚠️ Potential issue_

**Error is lost in `connect()` native path**  

After the refactor, `handlerConnectError(e)` is invoked but its result is ignored.  
Because the helper now returns `void`, the `catch` block finishes normally and the method falls through returning `undefined`, leaving the UI unaware that the connection failed.

```diff
-      } catch (e: any) {
-        this.handlerConnectError(e);
+      } catch (e: unknown) {
+        this.handlerConnectError(e); // may throw
+        // If it didn’t, re‑throw to keep the behaviour explicit
+        throw e;
       }
```

This keeps behaviour predictable and removes the silent‑failure path.

---

`574-585`: _🧹 Nitpick (assertive)_

**Dead code: `lastCancelAt` helpers are no longer used**  

`lastCancelAt` and `isLastCancelLessThanMsAgo()` became orphaned after throttling logic was removed. Keeping unused state invites confusion and future merge conflicts.  
Please delete them or wire them back if throttling is still planned.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 32d7b37f9a6f26a4d5d87d16145a45589fc59448 and 0803f599598ca8410c744438ae0c7c14081e0525.

</details>

<details>
<summary>⛔ Files ignored due to path filters (2)</summary>

* `apps/mobile/ios/Podfile.lock` is excluded by `!**/*.lock`
* `yarn.lock` is excluded by `!**/yarn.lock`, `!**/*.lock`

</details>

<details>
<summary>📒 Files selected for processing (13)</summary>

* `apps/mobile/android/app/src/main/AndroidManifest.xml` (1 hunks)
* `apps/mobile/package.json` (2 hunks)
* `package.json` (1 hunks)
* `packages/kit-bg/src/services/ServiceHardware/ServiceHardware.ts` (2 hunks)
* `packages/kit-bg/src/services/ServiceHardwareUI/ServiceHardwareUI.ts` (2 hunks)
* `packages/kit/src/views/FirmwareUpdate/components/FirmwareUpdateExitPrevent.ts` (3 hunks)
* `packages/kit/src/views/FirmwareUpdate/hooks/useFirmwareUpdateHooks.ts` (2 hunks)
* `packages/kit/src/views/Onboarding/pages/ConnectHardwareWallet/ConnectYourDevice.tsx` (3 hunks)
* `packages/shared/src/errors/errors/hardwareErrors.ts` (1 hunks)
* `packages/shared/src/errors/utils/deviceErrorUtils.ts` (1 hunks)
* `packages/shared/src/hardware/bleManager/index.native.ts` (1 hunks)
* `packages/shared/src/hardware/bleManager/index.ts` (1 hunks)
* `packages/shared/src/utils/deviceUtils.ts` (0 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* packages/shared/src/utils/deviceUtils.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>packages/kit/src/views/Onboarding/pages/ConnectHardwareWallet/ConnectYourDevice.tsx (2)</summary><blockquote>

<details>
<summary>packages/shared/src/hardware/bleManager/index.native.ts (1)</summary>

* `checkState` (4-8)

</details>
<details>
<summary>packages/shared/src/hardware/bleManager/index.ts (1)</summary>

* `checkState` (2-4)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: unittest (20.x)
* GitHub Check: lint (20.x)
* GitHub Check: Analyze (javascript-typescript)

</details>

<details>
<summary>🔇 Additional comments (16)</summary><blockquote>

<details>
<summary>package.json (1)</summary>

`70-75`: **Version bump for hardware SDK packages.**

The versions of five hardware-related SDK packages have been updated from `1.0.25-alpha.10` to `1.0.26-alpha.0`. These updates likely contain the BLE bonding and device cancellation improvements described in the PR.

</details>
<details>
<summary>apps/mobile/package.json (2)</summary>

`40-40`: **Bluetooth library change.**

Replaced `@onekeyfe/react-native-ble-plx` with `@onekeyfe/react-native-ble-utils`. This is part of the BLE library restructuring to simplify device connection management.

---

`94-94`: **Updated BLE library.**

Replaced `react-native-ble-manager` with `react-native-ble-plx` version 3.5.0. This matches with other BLE-related changes in the PR.

</details>
<details>
<summary>packages/shared/src/errors/utils/deviceErrorUtils.ts (1)</summary>

`123-124`: **Added handler for BLE bonding cancellation.**

Added support for the new `BleDeviceBondedCanceled` error code, mapping it to the existing `DeviceNotBonded` error. This properly handles user-initiated cancellations during BLE bonding.

</details>
<details>
<summary>apps/mobile/android/app/src/main/AndroidManifest.xml (1)</summary>

`6-10`: <details>
<summary>✅ Verification successful</summary>

**Updated Android location permissions.**

Added `maxSdkVersion="30"` to location permissions to restrict them to Android 11 and below. This aligns with Android's changing permission requirements for Bluetooth scanning.


---

🏁 Script executed:

```shell
#!/bin/bash
# Verify that the BLE library is compatible with the permission changes

# Check if the new BLE library requires specific permissions
rg -A 2 -B 2 "permission" packages/shared/src/hardware/bleManager

# Confirm if the code correctly handles permission requests on Android 12+
rg "BLUETOOTH_SCAN|BLUETOOTH_CONNECT" --type ts
```

Length of output: 538

---



</details>

**Confirmed Bluetooth permissions on Android 12+**  
- blePermissions.ts declares and checks both BLUETOOTH_SCAN and BLUETOOTH_CONNECT.  
- It verifies RESULTS.GRANTED for each.  
- Limiting location perms to maxSdkVersion=30 only affects Android 11 and below.  

No further changes needed.

</details>
<details>
<summary>packages/kit/src/views/FirmwareUpdate/hooks/useFirmwareUpdateHooks.ts (3)</summary>

`25-30`: **Added new optional callback parameter.**

The function now accepts an optional `onConfirm` callback that runs after navigation action dispatch. This enhances the hook's flexibility by allowing custom actions when users confirm exit.

---

`57-57`: **Added callback execution.**

The implementation correctly uses the optional chaining operator `?.()` to safely invoke the callback only when it exists.

---

`65-65`: **Updated dependency array.**

The dependency array now includes `onConfirm`, preventing stale closure issues and ensuring the callback reference stays current.

</details>
<details>
<summary>packages/kit/src/views/FirmwareUpdate/components/FirmwareUpdateExitPrevent.ts (4)</summary>

`1-2`: **Added useCallback import.**

Now importing the useCallback hook for the new cancellation functionality.

---

`8-8`: **Added background API import.**

Imports the proxy needed to call hardware services.

---

`32-34`: **Added hardware cancel callback.**

Created a memoized callback that cancels hardware operations when the user confirms exiting. This improves user experience by properly cleaning up hardware connections.

---

`44-44`: **Connected cancel callback to modal exit.**

Passes the cancellation callback to the modal exit prevention hook, completing the feature implementation.

</details>
<details>
<summary>packages/kit-bg/src/services/ServiceHardwareUI/ServiceHardwareUI.ts (2)</summary>

`326-326`: **Removed unnecessary delay.**

Commented out the call to `waitForCancelDone()`, removing an artificial delay in the hardware processing flow. This will make the UI more responsive when canceling operations.

---

`345-345`: **Removed unnecessary delay in nested processing.**

Removed another delay call in the nested processing path, ensuring consistent behavior throughout the component hierarchy.

</details>
<details>
<summary>packages/shared/src/errors/errors/hardwareErrors.ts (1)</summary>

`298-310`: **Added new BLE bonding cancellation error class.**

Created a dedicated error class for Bluetooth pairing cancellation scenarios. This improves error handling by providing a specific, user-friendly error message when Bluetooth pairing fails.


The error uses the same code as `DeviceNotBonded` (line 309) but with a different message context, which helps maintain consistent error categorization while providing more specific user feedback.

</details>
<details>
<summary>packages/kit-bg/src/services/ServiceHardware/ServiceHardware.ts (1)</summary>

`588-632`: **Verify removal of cancel‑throttling won’t hurt UX**  

`cancel()` now fires on every call with only a 100 ms debounce. Rapid successive cancels could spam the transport layer and, on some devices, trigger firmware “busy” errors.  
Make sure:

1. The underlying SDK gracefully handles rapid `cancel` calls.  
2. No UI elements auto‑fire `cancel` in tight loops.

If issues appear, consider reinstating a lightweight debounce using the existing `lastCancelAt` helper.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T12:41:19Z
user: login: originalix
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-23T14:35:57Z
user: login: limichange
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T01:27:15Z

Review comments:
diff_hunk: @@ -849,11 +852,7 @@ function ConnectByUSBOrBLE() {
   );
 
   const checkBLEState = useCallback(async () => {
-    // hack missing getBleManager.
-    await bleManagerInstance.getBleManager();
-    await timerUtils.wait(100);
-    const bleManager = await bleManagerInstance.getBleManager();
-    const checkState = await bleManager?.checkState();
+    const checkState = await bleManagerInstance.checkState();
     return checkState === 'on';
   }, []);
path: packages/kit/src/views/Onboarding/pages/ConnectHardwareWallet/ConnectYourDevice.tsx
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Tighten naming for clarity.**

Inside `checkBLEState`, the intermediate variable is also called `checkState`, which reads oddly:

```ts
const state = await bleManagerInstance.checkState();
return state === 'on';
```

A tiny rename improves readability with zero runtime cost.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-23T12:41:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -161,6 +161,17 @@ type IConnectYourDeviceItem = {
 
 function DeviceListItem({ item }: { item: IConnectYourDeviceItem }) {
   const [isLoading, setIsLoading] = useState(false);
+
+  const onPress = useCallback(async () => {
+    if (isLoading) return;
+    try {
+      setIsLoading(true);
+      await item.onPress();
+    } finally {
+      setIsLoading(false);
+    }
+  }, [item, isLoading]);
+
path: packages/kit/src/views/Onboarding/pages/ConnectHardwareWallet/ConnectYourDevice.tsx
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Cut down needless re‑renders in `onPress`.**

`isLoading` sits in the dependency array, so React rebuilds the callback every time the flag flips.  
That cancels the memoization benefit and forces `ListItem` to reconcile more often.

A tiny ref keeps the guard without churning the function:

```diff
-const [isLoading, setIsLoading] = useState(false);
-const onPress = useCallback(async () => {
-  if (isLoading) return;
-  try {
-    setIsLoading(true);
-    await item.onPress();
-  } finally {
-    setIsLoading(false);
-  }
-}, [item, isLoading]);
+const [isLoading, setIsLoading] = useState(false);
+const isLoadingRef = useRef(false);
+
+const onPress = useCallback(async () => {
+  if (isLoadingRef.current) return;
+  isLoadingRef.current = true;
+  setIsLoading(true);
+  try {
+    await item.onPress();
+  } finally {
+    isLoadingRef.current = false;
+    setIsLoading(false);
+  }
+}, [item]);
```

Bonus: this also avoids `setState` on an unmounted component if navigation occurs while the promise is pending.  



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  const [isLoading, setIsLoading] = useState(false);
  const isLoadingRef = useRef(false);

  const onPress = useCallback(async () => {
    if (isLoadingRef.current) return;
    isLoadingRef.current = true;
    setIsLoading(true);
    try {
      await item.onPress();
    } finally {
      isLoadingRef.current = false;
      setIsLoading(false);
    }
  }, [item]);
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-23T12:41:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,22 +1,6 @@
-type IBleManager = {
-  checkState(): Promise<'on' | 'off'>;
-};
 class BleManagerInstance {
-  async getBleManager(): Promise<IBleManager | undefined> {
-    return undefined;
-  }
-
-  /**
-   * get bonded devices (only android)
-   * @returns Bound device
-   */
-  async getBondedDevices() {
-    return [];
-  }
-
-  // eslint-disable-next-line @typescript-eslint/no-unused-vars
-  async checkDeviceBonded(connectId: string) {
-    return Promise.resolve(false);
+  checkState(): Promise<'on' | 'off'> {
+    return Promise.resolve('on');
   }
path: packages/shared/src/hardware/bleManager/index.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**`checkState` always says `'on'` — this hides real errors.**

Right now web / desktop builds will believe Bluetooth is enabled even if the host has no BLE adapter or it’s switched off. That short‑circuits the UX that should prompt the user to turn Bluetooth on or plug a dongle.

At minimum, detect capability and report `'off'` when BLE is unavailable:

```diff
-  checkState(): Promise<'on' | 'off'> {
-    return Promise.resolve('on');
+  checkState(): Promise<'on' | 'off'> {
+    if (typeof navigator !== 'undefined' && navigator.bluetooth) {
+      // Web Bluetooth API guarantees `getAvailability`
+      return navigator.bluetooth.getAvailability().then((ok) => (ok ? 'on' : 'off'));
+    }
+    return Promise.resolve('off');
   }
```

This keeps the API simple but prevents false positives.  



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  checkState(): Promise<'on' | 'off'> {
    if (typeof navigator !== 'undefined' && navigator.bluetooth) {
      // Web Bluetooth API guarantees `getAvailability`
      return navigator.bluetooth
        .getAvailability()
        .then((ok) => (ok ? 'on' : 'off'));
    }
    return Promise.resolve('off');
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-23T12:41:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,66 +1,10 @@
-import BleManager from 'react-native-ble-manager';
-
-import platformEnv from '../../platformEnv';
-import { equalsIgnoreCase } from '../../utils/stringUtils';
-
-type IPollFn<T> = (time?: number, index?: number, rate?: number) => T;
-const POLL_INTERVAL = 1000;
-const POLL_INTERVAL_RATE = 1.5;
+import BleManager from '@onekeyfe/react-native-ble-utils';
 
 class BleManagerInstance {
-  bleManager?: typeof BleManager;
-
-  async getBleManager() {
-    if (!platformEnv.isNative) return null;
-    if (this.bleManager) {
-      return Promise.resolve(this.bleManager);
-    }
-    await BleManager.start({ showAlert: false });
-    this.bleManager = BleManager;
-  }
-
-  /**
-   * get bonded devices (only android)
-   * @returns Bound device
-   */
-  async getBondedDevices() {
-    const bleManager = await this.getBleManager();
-    if (!bleManager) {
-      return [];
-    }
-    const peripherals = await bleManager.getBondedPeripherals();
-    return peripherals.map((peripheral) => {
-      const { id, name, advertising = {} } = peripheral;
-      return { id, name, ...advertising };
-    });
-  }
-
-  async checkDeviceBonded(connectId: string) {
-    let retry = 0;
-    const maxRetryCount = 5;
-    const poll: IPollFn<Promise<boolean | undefined>> = async (
-      time = POLL_INTERVAL,
-    ) => {
-      retry += 1;
-      const bondedDevices = await this.getBondedDevices();
-
-      const hasBonded = !!bondedDevices.find((bondedDevice) =>
-        equalsIgnoreCase(bondedDevice.id, connectId),
-      );
-
-      if (hasBonded) {
-        return Promise.resolve(true);
-      }
-
-      if (retry > maxRetryCount) {
-        return Promise.resolve(false);
-      }
-
-      return new Promise((resolve: (p: Promise<boolean | undefined>) => void) =>
-        setTimeout(() => resolve(poll(3000 * POLL_INTERVAL_RATE)), time),
-      );
-    };
-    return poll();
+  checkState(): Promise<'on' | 'off'> {
+    return BleManager.checkState().then((state) =>
+      state === 'on' ? 'on' : 'off',
+    );
path: packages/shared/src/hardware/bleManager/index.native.ts
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Normalise all platform return values.**

`BleManager.checkState()` may emit `poweredOn`, `poweredOff`, `unauthorized`, etc.  
Today any string other than `'on'` comes back as `'off'`, which is fine, but we still rely on the library’s exact wording. Consider a small mapper for future‑proofing:

```ts
const mapState = (s: string) => (s.toLowerCase().includes('on') ? 'on' : 'off');
return BleManager.checkState().then(mapState);
```

This guards against upstream changes like a switch to `powered_on`.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-23T12:41:18Z
author_association: CONTRIBUTOR

PR comments:
user: login: codesandbox[bot]
created_at: 2025-04-23T12:34:10Z
body: #### Review or Edit in CodeSandbox

Open the branch in <a href="https://codesandbox.io/p/github/OneKeyHQ/app-monorepo/feat/optimizeDeviceCancel?mode=review&utm_source=gh_app">Web Editor</a> &bull; <a href="https://codesandbox.io/p/vscode?owner=OneKeyHQ&repo=app-monorepo&branch=feat/optimizeDeviceCancel&utm_source=gh_app">VS Code</a> &bull; <a href="https://codesandbox.io/p/vscode?owner=OneKeyHQ&repo=app-monorepo&branch=feat/optimizeDeviceCancel&insiders=true&utm_source=gh_app">Insiders</a><br>
Open <a href="https://codesandbox.io/p/devtool/preview/OneKeyHQ/app-monorepo/feat/optimizeDeviceCancel?task=preview&port=51423&redirect=true&utm_source=gh_app">Preview</a>

<!-- open-in-codesandbox:complete -->

author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-04-23T12:34:15Z
body: <!-- This is an auto-generated comment: review paused by coderabbit.ai -->

> [!NOTE]
> ## Reviews paused
> 
> Use the following commands to manage reviews:
> - `@coderabbitai resume` to resume automatic reviews.
> - `@coderabbitai review` to trigger a single review.

<!-- end of auto-generated comment: review paused by coderabbit.ai -->
<!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

This update replaces the Bluetooth library in the mobile app, switching to `@onekeyfe/react-native-ble-utils` and updating related dependencies. It removes old BLE bonding and cancel throttling logic, simplifies BLE state checks, and streamlines error handling for hardware connections. Android location permissions are updated to match SDK requirements. The firmware update modal now sends a cancel command when closed. Several utility functions and classes related to BLE bonding are removed or refactored, and a new hardware error type is added for BLE bonding cancellation.

## Changes

| Files/Paths                                                                                           | Change Summary                                                                                                                      |
|-------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| apps/mobile/android/app/src/main/AndroidManifest.xml                                                  | Updated location permissions for BLE, restricting to SDK ≤ 30 and adding ACCESS_FINE_LOCATION.                                      |
| apps/mobile/package.json, package.json                                                                | Swapped and updated BLE-related dependencies; bumped `@onekeyfe/hd-*` packages to `1.0.26-alpha.0`.                                |
| packages/shared/src/hardware/bleManager/index.native.ts, index.ts                                     | Replaced BLE manager implementation; removed bonding/device checks; now only provides `checkState()`.                               |
| packages/shared/src/utils/deviceUtils.ts                                                              | Removed BLE bonding check function and related exports.                                                                              |
| packages/kit-bg/src/services/ServiceHardware/ServiceHardware.ts                                       | Simplified error handler and cancel logic; removed Android bonding reconnects and cancel throttling.                                 |
| packages/kit-bg/src/services/ServiceHardwareUI/ServiceHardwareUI.ts                                   | Removed cancel delay logic; commented out wait calls in hardware processing.                                                         |
| packages/kit/src/views/FirmwareUpdate/components/FirmwareUpdateExitPrevent.ts, .../useFirmwareUpdateHooks.ts | Added cancel command on modal exit; extended hook to accept `onConfirm` callback.                                                   |
| packages/kit/src/views/Onboarding/pages/ConnectHardwareWallet/ConnectYourDevice.tsx                   | Refactored BLE state check and button handler for clarity and efficiency.                                                            |
| packages/shared/src/errors/errors/hardwareErrors.ts, .../utils/deviceErrorUtils.ts                    | Added new error class for BLE bonding cancellation; updated error conversion logic.                                                  |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant App
    participant BLEManager
    participant HardwareDevice

    User->>App: Initiate hardware connection
    App->>BLEManager: checkState()
    BLEManager-->>App: 'on' or 'off'
    App->>HardwareDevice: Connect (if BLE is 'on')
    HardwareDevice-->>App: Connection result or error
    App->>App: Handle errors (simplified, no bonding retry)
    User->>App: Cancel operation (e.g., closes modal)
    App->>HardwareDevice: Send cancel command
```

## Assessment against linked issues

| Objective                                                                                                   | Addressed | Explanation                                                                                   |
|-------------------------------------------------------------------------------------------------------------|-----------|-----------------------------------------------------------------------------------------------|
| Optimize hardware cancel flow, replace BLE library, improve Android pairing logic (OK-37727)                | ✅        |                                                                                               |
| Android: Fix slow hardware interaction and ensure cancel exits device prompt quickly (OK-31526)              | ✅        |                                                                                               |
| Firmware update: Send cancel command when closing upgrade modal (OK-30988)                                   | ✅        |                                                                                               |
| PIN verification: Fix USB connection failure after PIN cancel (OK-33731)                                     | ✅        |                                                                                               |

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=OneKeyHQ/app-monorepo&utm_content=7198):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` or `Summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: socket-security[bot]
created_at: 2025-04-23T12:37:25Z
body: **Review the following changes in direct dependencies.** Learn more about [Socket for GitHub](https://socket.dev?utm_medium=gh).

<table>
<thead>
<tr>
<th>Diff</th>
<th width="200px">Package</th>
<th align="center" width="100px">Supply Chain<br/>Security</th>
<th align="center" width="100px">Vulnerability</th>
<th align="center" width="100px">Quality</th>
<th align="center" width="100px">Maintenance</th>
<th align="center" width="100px">License</th>
</tr>
</thead>
<tbody>
<tr><td align="center"><a href="https://socket.dev/dashboard/org/OneKeyHQ/diff/ac5a5f9a-6473-4f8b-bc9e-1c62e60866ea/99a610da-7a8b-4924-ba0e-3debd6a6ca7c?tab=dependencies&dependency_item_key=15052629558"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/OneKeyHQ/diff/ac5a5f9a-6473-4f8b-bc9e-1c62e60866ea/99a610da-7a8b-4924-ba0e-3debd6a6ca7c?tab=dependencies&dependency_item_key=15052629558">@​walletconnect/​logger@​2.1.2</a></td><td align="center"><a href="https://socket.dev/dashboard/org/OneKeyHQ/diff/ac5a5f9a-6473-4f8b-bc9e-1c62e60866ea/99a610da-7a8b-4924-ba0e-3debd6a6ca7c?tab=dependencies&dependency_item_key=15052629558"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/OneKeyHQ/diff/ac5a5f9a-6473-4f8b-bc9e-1c62e60866ea/99a610da-7a8b-4924-ba0e-3debd6a6ca7c?tab=dependencies&dependency_item_key=15052629558"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/OneKeyHQ/diff/ac5a5f9a-6473-4f8b-bc9e-1c62e60866ea/99a610da-7a8b-4924-ba0e-3debd6a6ca7c?tab=dependencies&dependency_item_key=15052629558"><img src="https://github-app-statics.socket.dev/score-65.svg" title="Quality" width="40" height="40" alt="65"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/OneKeyHQ/diff/ac5a5f9a-6473-4f8b-bc9e-1c62e60866ea/99a610da-7a8b-4924-ba0e-3debd6a6ca7c?tab=dependencies&dependency_item_key=15052629558"><img src="https://github-app-statics.socket.dev/score-81.svg" title="Maintenance" width="40" height="40" alt="81"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/OneKeyHQ/diff/ac5a5f9a-6473-4f8b-bc9e-1c62e60866ea/99a610da-7a8b-4924-ba0e-3debd6a6ca7c?tab=dependencies&dependency_item_key=15052629558"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr>
</tbody>
</table>

[View full report](https://socket.dev/dashboard/org/OneKeyHQ/diff/ac5a5f9a-6473-4f8b-bc9e-1c62e60866ea/99a610da-7a8b-4924-ba0e-3debd6a6ca7c?tab=dependencies)

<!-- overview-comment -->
author_association: NONE
user: login: limichange
created_at: 2025-04-24T01:26:27Z
body: @coderabbitai stop
author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-04-24T01:26:41Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
@limichange I'll stop the automated reviews for this PR as requested.

<details>
<summary>:white_check_mark: Actions performed</summary>

Reviews paused.

</details>
author_association: CONTRIBUTOR