@onekeyfe/hd-transport-react-native 1.1.27-alpha.37 → 1.1.27-alpha.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"BleManager.d.ts","sourceRoot":"","sources":["../src/BleManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAWnE,eAAO,MAAM,qBAAqB,iBAAkB,MAAM,EAAE,0BACZ,CAAC;AAEjD,eAAO,MAAM,gBAAgB,6BAAwC,CAAC;AAEtE,eAAO,MAAM,UAAU,eAAgB,MAAM;;;EAAoC,CAAC;AAElF,eAAO,MAAM,iBAAiB,kBAAmB,MAAM,KAAG,QAAQ,UAAU,GAAG,SAAS,CAmCpF,CAAC"}
1
+ {"version":3,"file":"BleManager.d.ts","sourceRoot":"","sources":["../src/BleManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAWnE,eAAO,MAAM,qBAAqB,iBAAkB,MAAM,EAAE,0BACZ,CAAC;AAEjD,eAAO,MAAM,gBAAgB,6BAAwC,CAAC;AAEtE,eAAO,MAAM,UAAU,eAAgB,MAAM;;;EAAoC,CAAC;AAElF,eAAO,MAAM,iBAAiB,kBAAmB,MAAM,KAAG,QAAQ,UAAU,GAAG,SAAS,CAkCpF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"BleTransport.d.ts","sourceRoot":"","sources":["../src/BleTransport.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAMjF,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,SAA6B;IAEjC,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,SAAM;IAEb,mBAAmB,EAAE,cAAc,CAAC;IAEpC,oBAAoB,EAAE,cAAc,CAAC;IAErC,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAElC,sBAAsB,CAAC,EAAE,YAAY,CAAC;IAEtC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,MAAM,CAAC,WAAW,SAAK;IAEvB,MAAM,CAAC,WAAW,SAAQ;gBAGxB,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,cAAc,EACnC,oBAAoB,EAAE,cAAc;IAehC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,SAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;CA2BzF"}
1
+ {"version":3,"file":"BleTransport.d.ts","sourceRoot":"","sources":["../src/BleTransport.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAMjF,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,SAA6B;IAEjC,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,SAAM;IAEb,mBAAmB,EAAE,cAAc,CAAC;IAEpC,oBAAoB,EAAE,cAAc,CAAC;IAErC,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAElC,sBAAsB,CAAC,EAAE,YAAY,CAAC;IAEtC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,MAAM,CAAC,WAAW,SAAK;IAEvB,MAAM,CAAC,WAAW,SAAQ;gBAGxB,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,cAAc,EACnC,oBAAoB,EAAE,cAAc;IAchC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,SAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;CA2BzF"}
@@ -0,0 +1,15 @@
1
+ export type BlePlatform = 'ios' | 'android' | string;
2
+ export type BleWriteCapability = {
3
+ isWritableWithResponse?: boolean | null;
4
+ isWritableWithoutResponse?: boolean | null;
5
+ };
6
+ export type BleWriteMode = 'withResponse' | 'withoutResponse';
7
+ export declare function hasWritableCapability(characteristic: BleWriteCapability): boolean;
8
+ export declare function resolveBleWriteMode(characteristic: BleWriteCapability, preferredMode?: BleWriteMode): BleWriteMode;
9
+ export declare function resolveProtocolV2PacketCapacity({ platform, iosPacketLength, androidPacketLength, mtu, }: {
10
+ platform: BlePlatform;
11
+ iosPacketLength?: number;
12
+ androidPacketLength?: number;
13
+ mtu?: number | null;
14
+ }): number;
15
+ //# sourceMappingURL=bleStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bleStrategy.d.ts","sourceRoot":"","sources":["../src/bleStrategy.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sBAAsB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAE9D,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,kBAAkB,WAIvE;AAED,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,kBAAkB,EAClC,aAAa,GAAE,YAAgC,GAC9C,YAAY,CAkBd;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,QAAQ,EACR,eAAmC,EACnC,mBAA2C,EAC3C,GAAG,GACJ,EAAE;IACD,QAAQ,EAAE,WAAW,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,UAWA"}
@@ -1,5 +1,6 @@
1
1
  export declare const IOS_PACKET_LENGTH = 128;
2
2
  export declare const ANDROID_PACKET_LENGTH = 192;
3
+ export declare const ANDROID_DEFAULT_MTU = 23;
3
4
  export declare const getBluetoothServiceUuids: () => string[];
4
5
  export declare const getInfosForServiceUuid: (serviceUuid: string, deviceType: 'classic') => {
5
6
  serviceUuid: string;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AA8BzC,eAAO,MAAM,wBAAwB,gBAA0B,CAAC;AAChE,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,cAAc,SAAS;iBA1BhE,MAAM;;;QAyCtB,CAAC;AAEF,eAAO,MAAM,gBAAgB,UAAW,MAAM,GAAG,IAAI,WACP,CAAC;AAE/C,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,IAAI,WAGjD,CAAC;AAEF,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,IAAI,UAAU,MAAM,GAAG,IAAI,YAQxE,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AA8BtC,eAAO,MAAM,wBAAwB,gBAA0B,CAAC;AAChE,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,cAAc,SAAS;iBA1BhE,MAAM;;;QAyCtB,CAAC;AAEF,eAAO,MAAM,gBAAgB,UAAW,MAAM,GAAG,IAAI,WACP,CAAC;AAE/C,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,IAAI,WAGjD,CAAC;AAEF,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,IAAI,UAAU,MAAM,GAAG,IAAI,YAQxE,CAAC"}
package/dist/index.d.ts CHANGED
@@ -63,7 +63,7 @@ declare class ReactNativeBleTransport {
63
63
  protocolType: ProtocolType;
64
64
  }>;
65
65
  _monitorCharacteristic(characteristic: Characteristic, uuid: string, monitorToken: number, notifyTransactionId: string): Subscription;
66
- release(uuid: string): Promise<boolean>;
66
+ release(uuid: string, onclose?: boolean): Promise<boolean>;
67
67
  post(session: string, name: string, data: Record<string, unknown>): Promise<void>;
68
68
  call(uuid: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<transport.MessageFromOneKey>;
69
69
  private callProtocolV1;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -61,84 +61,41 @@ const getConnectedDeviceIds = (serviceUuids) => BleUtils__default["default"].get
61
61
  const pairDevice = (macAddress) => BleUtils__default["default"].pairDevice(macAddress);
62
62
  const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
63
63
  let timeout;
64
- const cleanup = (cleanupListener) => {
64
+ let cleanupListener;
65
+ const cleanup = () => {
65
66
  if (timeout) {
66
67
  clearTimeout(timeout);
67
68
  }
68
69
  if (cleanupListener)
69
70
  cleanupListener();
70
71
  };
71
- const cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
72
+ timeout = setTimeout(() => {
73
+ cleanup();
74
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
75
+ }, 60 * 1000);
76
+ cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
72
77
  var _a;
73
78
  if (((_a = peripheral.id) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== bleMacAddress.toLowerCase()) {
74
79
  return;
75
80
  }
76
81
  const { bondState } = peripheral;
77
- if (bondState.preState === 'BOND_NONE' && bondState.state === 'BOND_BONDING') {
78
- timeout = setTimeout(() => {
79
- cleanup(cleanupListener);
80
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
81
- }, 60 * 1000);
82
- }
83
82
  const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
84
83
  const hasCanceled = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
85
84
  Logger.debug('onDeviceBondState bondState:', bondState);
86
85
  if (hasBonded) {
87
- cleanup(cleanupListener);
86
+ cleanup();
88
87
  resolve(peripheral);
89
88
  }
90
89
  else if (hasCanceled) {
91
- cleanup(cleanupListener);
90
+ cleanup();
92
91
  reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'bonding canceled'));
93
92
  }
94
93
  });
95
94
  });
96
95
 
97
- const timer = process.env.NODE_ENV === 'development'
98
- ? {
99
- timeout: (fn, ms) => {
100
- const startTime = Date.now();
101
- const interval = setInterval(() => {
102
- if (Date.now() - startTime >= ms) {
103
- clearInterval(interval);
104
- fn();
105
- }
106
- }, 100);
107
- return () => {
108
- clearInterval(interval);
109
- };
110
- },
111
- }
112
- : {
113
- timeout: (fn, ms) => {
114
- const timeout = setTimeout(fn, ms);
115
- return () => clearTimeout(timeout);
116
- },
117
- };
118
-
119
- const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject) => {
120
- let done = false;
121
- const subscription = bleManager.onStateChange(state => {
122
- console.log('ble state -> ', state);
123
- if (state === 'PoweredOn') {
124
- if (done)
125
- return;
126
- clearTimeout();
127
- done = true;
128
- subscription.remove();
129
- resolve();
130
- }
131
- }, true);
132
- const clearTimeout = timer.timeout(() => {
133
- if (done)
134
- return;
135
- subscription.remove();
136
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
137
- }, ms);
138
- });
139
-
140
96
  const IOS_PACKET_LENGTH = 128;
141
97
  const ANDROID_PACKET_LENGTH = 192;
98
+ const ANDROID_DEFAULT_MTU = 23;
142
99
  const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
143
100
  const OneKeyServices = {
144
101
  classic: {
@@ -180,6 +137,78 @@ const isSameBleUuid = (left, right) => {
180
137
  (getBleUuidKey(left) !== '' && getBleUuidKey(left) === getBleUuidKey(right)));
181
138
  };
182
139
 
140
+ function hasWritableCapability(characteristic) {
141
+ return !!(characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse);
142
+ }
143
+ function resolveBleWriteMode(characteristic, preferredMode = 'withoutResponse') {
144
+ if (preferredMode === 'withoutResponse' && characteristic.isWritableWithoutResponse) {
145
+ return 'withoutResponse';
146
+ }
147
+ if (preferredMode === 'withResponse' && characteristic.isWritableWithResponse) {
148
+ return 'withResponse';
149
+ }
150
+ if (characteristic.isWritableWithoutResponse) {
151
+ return 'withoutResponse';
152
+ }
153
+ if (characteristic.isWritableWithResponse) {
154
+ return 'withResponse';
155
+ }
156
+ return preferredMode;
157
+ }
158
+ function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PACKET_LENGTH, androidPacketLength = ANDROID_PACKET_LENGTH, mtu, }) {
159
+ if (platform === 'ios') {
160
+ return iosPacketLength;
161
+ }
162
+ if (platform === 'android') {
163
+ const payloadLength = Math.max((mtu !== null && mtu !== void 0 ? mtu : ANDROID_DEFAULT_MTU) - 3, 1);
164
+ return Math.min(androidPacketLength, payloadLength);
165
+ }
166
+ return androidPacketLength;
167
+ }
168
+
169
+ const timer = process.env.NODE_ENV === 'development'
170
+ ? {
171
+ timeout: (fn, ms) => {
172
+ const startTime = Date.now();
173
+ const interval = setInterval(() => {
174
+ if (Date.now() - startTime >= ms) {
175
+ clearInterval(interval);
176
+ fn();
177
+ }
178
+ }, 100);
179
+ return () => {
180
+ clearInterval(interval);
181
+ };
182
+ },
183
+ }
184
+ : {
185
+ timeout: (fn, ms) => {
186
+ const timeout = setTimeout(fn, ms);
187
+ return () => clearTimeout(timeout);
188
+ },
189
+ };
190
+
191
+ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject) => {
192
+ let done = false;
193
+ const subscription = bleManager.onStateChange(state => {
194
+ console.log('ble state -> ', state);
195
+ if (state === 'PoweredOn') {
196
+ if (done)
197
+ return;
198
+ clearTimeout();
199
+ done = true;
200
+ subscription.remove();
201
+ resolve();
202
+ }
203
+ }, true);
204
+ const clearTimeout = timer.timeout(() => {
205
+ if (done)
206
+ return;
207
+ subscription.remove();
208
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
209
+ }, ms);
210
+ });
211
+
183
212
  const isHeaderChunk = (chunk) => {
184
213
  if (chunk.length < 9)
185
214
  return false;
@@ -196,12 +225,11 @@ const Log$1 = bleLogger;
196
225
  class BleTransport {
197
226
  constructor(device, writeCharacteristic, notifyCharacteristic) {
198
227
  this.name = 'ReactNativeBleTransport';
199
- this.mtuSize = 20;
228
+ this.mtuSize = 23;
200
229
  this.id = device.id;
201
230
  this.device = device;
202
231
  this.writeCharacteristic = writeCharacteristic;
203
232
  this.notifyCharacteristic = notifyCharacteristic;
204
- console.log(`BleTransport(${String(this.id)}) new instance`);
205
233
  }
206
234
  writeWithRetry(data, retryCount = BleTransport.MAX_RETRIES) {
207
235
  return __awaiter(this, void 0, void 0, function* () {
@@ -240,9 +268,10 @@ const Log = bleLogger;
240
268
  const transportCache = {};
241
269
  const BLE_RESPONSE_TIMEOUT_MS = 30000;
242
270
  const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
243
- const PROTOCOL_V2_PROBE_TIMEOUT_MS = 5000;
271
+ const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
244
272
  const DEVICE_SCAN_TIMEOUT_MS = 8000;
245
273
  const IOS_NOTIFY_READY_DELAY_MS = 150;
274
+ const ANDROID_NOTIFY_READY_DELAY_MS = 300;
246
275
  const HIGH_VOLUME_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 6;
247
276
  const HIGH_VOLUME_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 6 : 2;
248
277
  const HIGH_VOLUME_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 20 : 8;
@@ -296,7 +325,7 @@ function hasKnownOneKeyService(device) {
296
325
  var _a;
297
326
  return ((_a = device === null || device === void 0 ? void 0 : device.serviceUUIDs) !== null && _a !== void 0 ? _a : []).some(serviceUuid => getInfosForServiceUuid(serviceUuid, 'classic'));
298
327
  }
299
- let connectOptions = {
328
+ const connectOptions = {
300
329
  requestMTU: 256,
301
330
  timeout: 3000,
302
331
  refreshGatt: 'OnConnected',
@@ -482,11 +511,20 @@ class ReactNativeBleTransport {
482
511
  if (!uuid) {
483
512
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
484
513
  }
485
- let device = null;
486
- if (transportCache[uuid]) {
487
- Log === null || Log === void 0 ? void 0 : Log.debug('transport not be released, will release: ', uuid);
488
- yield this.release(uuid);
514
+ const cachedTransport = transportCache[uuid];
515
+ if (cachedTransport) {
516
+ const cachedProtocol = this.deviceProtocol.get(uuid);
517
+ const isCachedDeviceConnected = yield cachedTransport.device.isConnected().catch(() => false);
518
+ if (isCachedDeviceConnected &&
519
+ cachedProtocol &&
520
+ (!expectedProtocol || cachedProtocol === expectedProtocol)) {
521
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
522
+ return { uuid, protocolType: cachedProtocol };
523
+ }
524
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
525
+ yield this.release(uuid, true);
489
526
  }
527
+ let device = null;
490
528
  if (forceCleanRunPromise && this.runPromise) {
491
529
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
492
530
  this.runPromise.reject(error);
@@ -508,6 +546,9 @@ class ReactNativeBleTransport {
508
546
  if (bondState.bonding) {
509
547
  yield onDeviceBondState(uuid);
510
548
  }
549
+ else if (!bondState.bonded) {
550
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
551
+ }
511
552
  }
512
553
  if (!device) {
513
554
  const devices = yield blePlxManager.devices([uuid]);
@@ -528,7 +569,6 @@ class ReactNativeBleTransport {
528
569
  Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
529
570
  if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
530
571
  e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
531
- connectOptions = {};
532
572
  Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
533
573
  device = yield blePlxManager.connectToDevice(uuid);
534
574
  }
@@ -553,7 +593,6 @@ class ReactNativeBleTransport {
553
593
  Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
554
594
  if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
555
595
  e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
556
- connectOptions = {};
557
596
  Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
558
597
  try {
559
598
  device = yield device.connect();
@@ -639,7 +678,7 @@ class ReactNativeBleTransport {
639
678
  if (!notifyCharacteristic) {
640
679
  throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
641
680
  }
642
- if (!writeCharacteristic.isWritableWithResponse) {
681
+ if (!hasWritableCapability(writeCharacteristic)) {
643
682
  throw hdShared.ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
644
683
  }
645
684
  if (!notifyCharacteristic.isNotifiable) {
@@ -648,11 +687,14 @@ class ReactNativeBleTransport {
648
687
  const protocolHint = expectedProtocol
649
688
  ? undefined
650
689
  : (_e = this.deviceProtocolHints.get(uuid)) !== null && _e !== void 0 ? _e : inferProtocolHintFromDeviceName(getDeviceDisplayName(device));
651
- yield this.release(uuid);
690
+ yield this.release(uuid, true);
652
691
  if (protocolHint) {
653
692
  this.deviceProtocolHints.set(uuid, protocolHint);
654
693
  }
655
694
  const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
695
+ if (reactNative.Platform.OS === 'android') {
696
+ transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport$1.mtuSize;
697
+ }
656
698
  const monitorToken = this.nextMonitorToken;
657
699
  this.nextMonitorToken += 1;
658
700
  const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
@@ -667,6 +709,9 @@ class ReactNativeBleTransport {
667
709
  setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
668
710
  });
669
711
  }
712
+ else if (reactNative.Platform.OS === 'android') {
713
+ yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
714
+ }
670
715
  const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
671
716
  (_f = this.emitter) === null || _f === void 0 ? void 0 : _f.emit('device-connect', {
672
717
  name: device.name,
@@ -696,7 +741,7 @@ class ReactNativeBleTransport {
696
741
  Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect error: ', e);
697
742
  }
698
743
  finally {
699
- this.release(uuid);
744
+ this.release(uuid, true);
700
745
  }
701
746
  });
702
747
  return { uuid, protocolType };
@@ -781,8 +826,8 @@ class ReactNativeBleTransport {
781
826
  }, notifyTransactionId);
782
827
  return subscription;
783
828
  }
784
- release(uuid) {
785
- var _a, _b, _c, _d, _e, _f;
829
+ release(uuid, onclose = false) {
830
+ var _a, _b, _c, _d, _e, _f, _g, _h;
786
831
  return __awaiter(this, void 0, void 0, function* () {
787
832
  const transport = transportCache[uuid];
788
833
  if (this.runPromise) {
@@ -795,19 +840,27 @@ class ReactNativeBleTransport {
795
840
  else {
796
841
  this.resetProtocolV2Frames(uuid);
797
842
  }
843
+ if (reactNative.Platform.OS === 'android' && !onclose && transport) {
844
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
845
+ this.resetProtocolV2Frames(uuid);
846
+ if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
847
+ this.activeProtocolV2Call = null;
848
+ }
849
+ return Promise.resolve(true);
850
+ }
798
851
  if (transport) {
799
852
  if (this.monitorTokens.get(uuid) === transport.monitorToken) {
800
853
  this.monitorTokens.delete(uuid);
801
854
  }
802
855
  Log === null || Log === void 0 ? void 0 : Log.debug('release: removing disconnect subscription for device: ', uuid);
803
- (_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
856
+ (_c = transport.disconnectSubscription) === null || _c === void 0 ? void 0 : _c.remove();
804
857
  transport.disconnectSubscription = undefined;
805
- Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (_b = transport.notifyCharacteristic) === null || _b === void 0 ? void 0 : _b.uuid);
806
- (_c = transport.notifySubscription) === null || _c === void 0 ? void 0 : _c.remove();
858
+ Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (_d = transport.notifyCharacteristic) === null || _d === void 0 ? void 0 : _d.uuid);
859
+ (_e = transport.notifySubscription) === null || _e === void 0 ? void 0 : _e.remove();
807
860
  transport.notifySubscription = undefined;
808
861
  if (transport.notifyTransactionId) {
809
862
  try {
810
- yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelTransaction(transport.notifyTransactionId));
863
+ yield ((_f = this.blePlxManager) === null || _f === void 0 ? void 0 : _f.cancelTransaction(transport.notifyTransactionId));
811
864
  }
812
865
  catch (e) {
813
866
  Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel notify transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
@@ -817,11 +870,11 @@ class ReactNativeBleTransport {
817
870
  }
818
871
  this.deviceProtocol.delete(uuid);
819
872
  this.deviceProtocolHints.delete(uuid);
820
- (_e = this.protocolV2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
873
+ (_g = this.protocolV2Assemblers.get(uuid)) === null || _g === void 0 ? void 0 : _g.reset();
821
874
  this.protocolV2Assemblers.delete(uuid);
822
875
  this.resetProtocolV2Frames(uuid);
823
876
  try {
824
- yield ((_f = this.blePlxManager) === null || _f === void 0 ? void 0 : _f.cancelTransaction(uuid));
877
+ yield ((_h = this.blePlxManager) === null || _h === void 0 ? void 0 : _h.cancelTransaction(uuid));
825
878
  }
826
879
  catch (e) {
827
880
  Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
@@ -1091,10 +1144,13 @@ class ReactNativeBleTransport {
1091
1144
  }
1092
1145
  throw this.createProtocolMismatchError(expectedProtocol);
1093
1146
  }
1094
- if (protocolHint === 'V2' && (yield this.probeProtocolV2(uuid))) {
1095
- this.deviceProtocol.set(uuid, 'V2');
1096
- Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (hint)`);
1097
- return 'V2';
1147
+ if (protocolHint === 'V2') {
1148
+ if (yield this.probeProtocolV2(uuid)) {
1149
+ this.deviceProtocol.set(uuid, 'V2');
1150
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (hint)`);
1151
+ return 'V2';
1152
+ }
1153
+ throw this.createProtocolMismatchError('V2');
1098
1154
  }
1099
1155
  if (this.deviceProtocol.get(uuid) === 'V2' && (yield this.probeProtocolV2(uuid))) {
1100
1156
  this.deviceProtocol.set(uuid, 'V2');
@@ -1282,15 +1338,21 @@ class ReactNativeBleTransport {
1282
1338
  writeProtocolV2Frame(transport, frame, options) {
1283
1339
  return __awaiter(this, void 0, void 0, function* () {
1284
1340
  const tuning = getProtocolV2BleTuning();
1285
- const packetCapacity = reactNative.Platform.OS === 'ios' ? tuning.iosPacketLength : tuning.androidPacketLength;
1341
+ const packetCapacity = resolveProtocolV2PacketCapacity({
1342
+ platform: reactNative.Platform.OS,
1343
+ iosPacketLength: tuning.iosPacketLength,
1344
+ androidPacketLength: tuning.androidPacketLength,
1345
+ mtu: reactNative.Platform.OS === 'android' ? transport.mtuSize : undefined,
1346
+ });
1286
1347
  const writeWithResponse = !!(options === null || options === void 0 ? void 0 : options.writeWithResponse) || (!!(options === null || options === void 0 ? void 0 : options.highVolume) && tuning.highVolumeWriteWithResponse);
1287
- const shouldThrottle = !!(options === null || options === void 0 ? void 0 : options.highVolume) && !writeWithResponse;
1348
+ const writeMode = resolveBleWriteMode(transport.writeCharacteristic, writeWithResponse ? 'withResponse' : 'withoutResponse');
1349
+ const shouldThrottle = !!(options === null || options === void 0 ? void 0 : options.highVolume) && writeMode === 'withoutResponse';
1288
1350
  let packetsWritten = 0;
1289
1351
  try {
1290
1352
  for (let offset = 0; offset < frame.length; offset += packetCapacity) {
1291
1353
  const chunk = frame.slice(offset, offset + packetCapacity);
1292
1354
  const base64 = buffer.Buffer.from(chunk).toString('base64');
1293
- if (writeWithResponse) {
1355
+ if (writeMode === 'withResponse') {
1294
1356
  yield transport.writeCharacteristic.writeWithResponse(base64);
1295
1357
  }
1296
1358
  else {
@@ -1365,7 +1427,11 @@ class ReactNativeBleTransport {
1365
1427
  protocolV2: this._messagesV2,
1366
1428
  },
1367
1429
  router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
1368
- writeFrame: (frame) => this.writeProtocolV2Frame(transport$1, frame, { highVolume: highVolumeWrite }),
1430
+ writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
1431
+ yield this.writeProtocolV2Frame(transport$1, frame, {
1432
+ highVolume: highVolumeWrite,
1433
+ });
1434
+ }),
1369
1435
  readFrame: () => __awaiter(this, void 0, void 0, function* () {
1370
1436
  const rxFrame = yield this.readProtocolV2Frame(uuid);
1371
1437
  if (!(rxFrame instanceof Uint8Array)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-react-native",
3
- "version": "1.1.27-alpha.37",
3
+ "version": "1.1.27-alpha.39",
4
4
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -19,11 +19,11 @@
19
19
  "lint:fix": "eslint . --fix"
20
20
  },
21
21
  "dependencies": {
22
- "@onekeyfe/hd-core": "1.1.27-alpha.37",
23
- "@onekeyfe/hd-shared": "1.1.27-alpha.37",
24
- "@onekeyfe/hd-transport": "1.1.27-alpha.37",
22
+ "@onekeyfe/hd-core": "1.1.27-alpha.39",
23
+ "@onekeyfe/hd-shared": "1.1.27-alpha.39",
24
+ "@onekeyfe/hd-transport": "1.1.27-alpha.39",
25
25
  "@onekeyfe/react-native-ble-utils": "^0.1.4",
26
26
  "react-native-ble-plx": "3.5.1"
27
27
  },
28
- "gitHead": "ff58ceb1249ba3f3f673b39f1c175093fab40a8b"
28
+ "gitHead": "e439aa105f1a898a8050037430ba23a5e31203b1"
29
29
  }
package/src/BleManager.ts CHANGED
@@ -21,36 +21,35 @@ export const pairDevice = (macAddress: string) => BleUtils.pairDevice(macAddress
21
21
 
22
22
  export const onDeviceBondState = (bleMacAddress: string): Promise<Peripheral | undefined> =>
23
23
  new Promise((resolve, reject) => {
24
- let timeout: any | undefined;
24
+ let timeout: ReturnType<typeof setTimeout> | undefined;
25
+ let cleanupListener: (() => void) | undefined;
25
26
 
26
- const cleanup = (cleanupListener: (() => void) | undefined) => {
27
+ const cleanup = () => {
27
28
  if (timeout) {
28
29
  clearTimeout(timeout);
29
30
  }
30
31
  if (cleanupListener) cleanupListener();
31
32
  };
32
33
 
33
- const cleanupListener = BleUtils.onDeviceBondState(peripheral => {
34
+ timeout = setTimeout(() => {
35
+ cleanup();
36
+ reject(ERRORS.TypedError(HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
37
+ }, 60 * 1000);
38
+
39
+ cleanupListener = BleUtils.onDeviceBondState(peripheral => {
34
40
  if (peripheral.id?.toLowerCase() !== bleMacAddress.toLowerCase()) {
35
41
  return;
36
42
  }
37
43
  const { bondState } = peripheral;
38
44
 
39
- if (bondState.preState === 'BOND_NONE' && bondState.state === 'BOND_BONDING') {
40
- timeout = setTimeout(() => {
41
- cleanup(cleanupListener);
42
- reject(ERRORS.TypedError(HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
43
- }, 60 * 1000);
44
- }
45
-
46
45
  const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
47
46
  const hasCanceled = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
48
47
  Logger.debug('onDeviceBondState bondState:', bondState);
49
48
  if (hasBonded) {
50
- cleanup(cleanupListener);
49
+ cleanup();
51
50
  resolve(peripheral);
52
51
  } else if (hasCanceled) {
53
- cleanup(cleanupListener);
52
+ cleanup();
54
53
  reject(ERRORS.TypedError(HardwareErrorCode.BleDeviceBondedCanceled, 'bonding canceled'));
55
54
  }
56
55
  });
@@ -14,7 +14,7 @@ export default class BleTransport {
14
14
 
15
15
  device: Device;
16
16
 
17
- mtuSize = 20;
17
+ mtuSize = 23;
18
18
 
19
19
  writeCharacteristic: Characteristic;
20
20
 
@@ -41,7 +41,6 @@ export default class BleTransport {
41
41
  this.device = device;
42
42
  this.writeCharacteristic = writeCharacteristic;
43
43
  this.notifyCharacteristic = notifyCharacteristic;
44
- console.log(`BleTransport(${String(this.id)}) new instance`);
45
44
  }
46
45
 
47
46
  /**
@@ -0,0 +1,47 @@
1
+ import {
2
+ hasWritableCapability,
3
+ resolveBleWriteMode,
4
+ resolveProtocolV2PacketCapacity,
5
+ } from '../bleStrategy';
6
+
7
+ describe('React Native BLE strategy', () => {
8
+ test('accepts writeWithoutResponse-only characteristics', () => {
9
+ const characteristic = {
10
+ isWritableWithResponse: false,
11
+ isWritableWithoutResponse: true,
12
+ };
13
+
14
+ expect(hasWritableCapability(characteristic)).toBe(true);
15
+ expect(resolveBleWriteMode(characteristic)).toBe('withoutResponse');
16
+ });
17
+
18
+ test('falls back to Android default ATT payload when MTU is unavailable', () => {
19
+ expect(
20
+ resolveProtocolV2PacketCapacity({
21
+ platform: 'android',
22
+ androidPacketLength: 192,
23
+ mtu: null,
24
+ })
25
+ ).toBe(20);
26
+ });
27
+
28
+ test('caps Android packet length by negotiated MTU payload', () => {
29
+ expect(
30
+ resolveProtocolV2PacketCapacity({
31
+ platform: 'android',
32
+ androidPacketLength: 192,
33
+ mtu: 100,
34
+ })
35
+ ).toBe(97);
36
+ });
37
+
38
+ test('keeps iOS packet length controlled by tuning profile', () => {
39
+ expect(
40
+ resolveProtocolV2PacketCapacity({
41
+ platform: 'ios',
42
+ iosPacketLength: 244,
43
+ mtu: 256,
44
+ })
45
+ ).toBe(244);
46
+ });
47
+ });
@@ -0,0 +1,62 @@
1
+ import { ANDROID_DEFAULT_MTU, ANDROID_PACKET_LENGTH, IOS_PACKET_LENGTH } from './constants';
2
+
3
+ export type BlePlatform = 'ios' | 'android' | string;
4
+
5
+ export type BleWriteCapability = {
6
+ isWritableWithResponse?: boolean | null;
7
+ isWritableWithoutResponse?: boolean | null;
8
+ };
9
+
10
+ export type BleWriteMode = 'withResponse' | 'withoutResponse';
11
+
12
+ export function hasWritableCapability(characteristic: BleWriteCapability) {
13
+ return !!(
14
+ characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse
15
+ );
16
+ }
17
+
18
+ export function resolveBleWriteMode(
19
+ characteristic: BleWriteCapability,
20
+ preferredMode: BleWriteMode = 'withoutResponse'
21
+ ): BleWriteMode {
22
+ if (preferredMode === 'withoutResponse' && characteristic.isWritableWithoutResponse) {
23
+ return 'withoutResponse';
24
+ }
25
+
26
+ if (preferredMode === 'withResponse' && characteristic.isWritableWithResponse) {
27
+ return 'withResponse';
28
+ }
29
+
30
+ if (characteristic.isWritableWithoutResponse) {
31
+ return 'withoutResponse';
32
+ }
33
+
34
+ if (characteristic.isWritableWithResponse) {
35
+ return 'withResponse';
36
+ }
37
+
38
+ return preferredMode;
39
+ }
40
+
41
+ export function resolveProtocolV2PacketCapacity({
42
+ platform,
43
+ iosPacketLength = IOS_PACKET_LENGTH,
44
+ androidPacketLength = ANDROID_PACKET_LENGTH,
45
+ mtu,
46
+ }: {
47
+ platform: BlePlatform;
48
+ iosPacketLength?: number;
49
+ androidPacketLength?: number;
50
+ mtu?: number | null;
51
+ }) {
52
+ if (platform === 'ios') {
53
+ return iosPacketLength;
54
+ }
55
+
56
+ if (platform === 'android') {
57
+ const payloadLength = Math.max((mtu ?? ANDROID_DEFAULT_MTU) - 3, 1);
58
+ return Math.min(androidPacketLength, payloadLength);
59
+ }
60
+
61
+ return androidPacketLength;
62
+ }
package/src/constants.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export const IOS_PACKET_LENGTH = 128;
2
2
  export const ANDROID_PACKET_LENGTH = 192;
3
+ export const ANDROID_DEFAULT_MTU = 23;
3
4
 
4
5
  type BluetoothServices = Record<
5
6
  string,
package/src/index.ts CHANGED
@@ -22,6 +22,11 @@ import transport, {
22
22
  import { ERRORS, HardwareErrorCode, createDeferred, isOnekeyDevice } from '@onekeyfe/hd-shared';
23
23
 
24
24
  import { getConnectedDeviceIds, onDeviceBondState, pairDevice } from './BleManager';
25
+ import {
26
+ hasWritableCapability,
27
+ resolveBleWriteMode,
28
+ resolveProtocolV2PacketCapacity,
29
+ } from './bleStrategy';
25
30
  import { subscribeBleOn } from './subscribeBleOn';
26
31
  import {
27
32
  ANDROID_PACKET_LENGTH,
@@ -48,9 +53,10 @@ const Log = bleLogger;
48
53
  const transportCache: Record<string, BleTransport> = {};
49
54
  const BLE_RESPONSE_TIMEOUT_MS = 30_000;
50
55
  const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
51
- const PROTOCOL_V2_PROBE_TIMEOUT_MS = 5000;
56
+ const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10_000;
52
57
  const DEVICE_SCAN_TIMEOUT_MS = 8000;
53
58
  const IOS_NOTIFY_READY_DELAY_MS = 150;
59
+ const ANDROID_NOTIFY_READY_DELAY_MS = 300;
54
60
  const HIGH_VOLUME_WRITE_BURST_SIZE = Platform.OS === 'ios' ? 4 : 6;
55
61
  const HIGH_VOLUME_WRITE_PAUSE_MS = Platform.OS === 'ios' ? 6 : 2;
56
62
  const HIGH_VOLUME_WRITE_FLUSH_DELAY_MS = Platform.OS === 'ios' ? 20 : 8;
@@ -143,7 +149,7 @@ function hasKnownOneKeyService(device?: Device | null) {
143
149
  );
144
150
  }
145
151
 
146
- let connectOptions: Record<string, unknown> = {
152
+ const connectOptions: Record<string, unknown> = {
147
153
  requestMTU: 256,
148
154
  timeout: 3000,
149
155
  refreshGatt: 'OnConnected',
@@ -402,17 +408,33 @@ export default class ReactNativeBleTransport {
402
408
  throw ERRORS.TypedError(HardwareErrorCode.BleRequiredUUID);
403
409
  }
404
410
 
405
- let device: Device | null = null;
411
+ const cachedTransport = transportCache[uuid];
412
+ if (cachedTransport) {
413
+ const cachedProtocol = this.deviceProtocol.get(uuid);
414
+ const isCachedDeviceConnected = await cachedTransport.device.isConnected().catch(() => false);
415
+ if (
416
+ isCachedDeviceConnected &&
417
+ cachedProtocol &&
418
+ (!expectedProtocol || cachedProtocol === expectedProtocol)
419
+ ) {
420
+ Log?.debug(
421
+ '[ReactNativeBleTransport] reuse cached BLE transport:',
422
+ uuid,
423
+ cachedProtocol
424
+ );
425
+ return { uuid, protocolType: cachedProtocol };
426
+ }
406
427
 
407
- if (transportCache[uuid]) {
408
428
  /**
409
- * If the transport is not released due to an exception operation
410
- * it will be handled again here
429
+ * If the transport is not reusable due to a protocol mismatch or stale
430
+ * connection, clean it up before creating a new transport instance.
411
431
  */
412
- Log?.debug('transport not be released, will release: ', uuid);
413
- await this.release(uuid);
432
+ Log?.debug('transport not reusable, will release: ', uuid);
433
+ await this.release(uuid, true);
414
434
  }
415
435
 
436
+ let device: Device | null = null;
437
+
416
438
  if (forceCleanRunPromise && this.runPromise) {
417
439
  const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
418
440
  this.runPromise.reject(error);
@@ -430,11 +452,12 @@ export default class ReactNativeBleTransport {
430
452
  throw error;
431
453
  }
432
454
 
433
- // check device is bonded
434
455
  if (Platform.OS === 'android') {
435
456
  const bondState = await pairDevice(uuid);
436
457
  if (bondState.bonding) {
437
458
  await onDeviceBondState(uuid);
459
+ } else if (!bondState.bonded) {
460
+ throw ERRORS.TypedError(HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
438
461
  }
439
462
  }
440
463
 
@@ -460,7 +483,6 @@ export default class ReactNativeBleTransport {
460
483
  e.errorCode === BleErrorCode.DeviceMTUChangeFailed ||
461
484
  e.errorCode === BleErrorCode.OperationCancelled
462
485
  ) {
463
- connectOptions = {};
464
486
  Log?.debug('first try to reconnect without params');
465
487
  device = await blePlxManager.connectToDevice(uuid);
466
488
  } else if (e.errorCode === BleErrorCode.DeviceAlreadyConnected) {
@@ -487,7 +509,6 @@ export default class ReactNativeBleTransport {
487
509
  e.errorCode === BleErrorCode.DeviceMTUChangeFailed ||
488
510
  e.errorCode === BleErrorCode.OperationCancelled
489
511
  ) {
490
- connectOptions = {};
491
512
  Log?.debug('second try to reconnect without params');
492
513
  try {
493
514
  device = await device.connect();
@@ -590,7 +611,7 @@ export default class ReactNativeBleTransport {
590
611
  throw ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
591
612
  }
592
613
 
593
- if (!writeCharacteristic.isWritableWithResponse) {
614
+ if (!hasWritableCapability(writeCharacteristic)) {
594
615
  throw ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
595
616
  }
596
617
 
@@ -606,12 +627,15 @@ export default class ReactNativeBleTransport {
606
627
  inferProtocolHintFromDeviceName(getDeviceDisplayName(device));
607
628
 
608
629
  // release transport before new transport instance
609
- await this.release(uuid);
630
+ await this.release(uuid, true);
610
631
  if (protocolHint) {
611
632
  this.deviceProtocolHints.set(uuid, protocolHint);
612
633
  }
613
634
 
614
635
  const transport = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
636
+ if (Platform.OS === 'android') {
637
+ transport.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport.mtuSize;
638
+ }
615
639
  const monitorToken = this.nextMonitorToken;
616
640
  this.nextMonitorToken += 1;
617
641
  const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
@@ -632,6 +656,8 @@ export default class ReactNativeBleTransport {
632
656
  await new Promise<void>(resolve => {
633
657
  setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
634
658
  });
659
+ } else if (Platform.OS === 'android') {
660
+ await delay(ANDROID_NOTIFY_READY_DELAY_MS);
635
661
  }
636
662
 
637
663
  const protocolType = await this.detectProtocol(uuid, expectedProtocol, protocolHint);
@@ -663,7 +689,7 @@ export default class ReactNativeBleTransport {
663
689
  } catch (e) {
664
690
  Log?.debug('device disconnect error: ', e);
665
691
  } finally {
666
- this.release(uuid);
692
+ this.release(uuid, true);
667
693
  }
668
694
  });
669
695
 
@@ -779,7 +805,7 @@ export default class ReactNativeBleTransport {
779
805
  return subscription;
780
806
  }
781
807
 
782
- async release(uuid: string) {
808
+ async release(uuid: string, onclose = false) {
783
809
  const transport = transportCache[uuid];
784
810
  if (this.runPromise) {
785
811
  const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
@@ -791,6 +817,15 @@ export default class ReactNativeBleTransport {
791
817
  this.resetProtocolV2Frames(uuid);
792
818
  }
793
819
 
820
+ if (Platform.OS === 'android' && !onclose && transport) {
821
+ this.protocolV2Assemblers.get(uuid)?.reset();
822
+ this.resetProtocolV2Frames(uuid);
823
+ if (this.activeProtocolV2Call?.uuid === uuid) {
824
+ this.activeProtocolV2Call = null;
825
+ }
826
+ return Promise.resolve(true);
827
+ }
828
+
794
829
  if (transport) {
795
830
  if (this.monitorTokens.get(uuid) === transport.monitorToken) {
796
831
  this.monitorTokens.delete(uuid);
@@ -1164,10 +1199,13 @@ export default class ReactNativeBleTransport {
1164
1199
  throw this.createProtocolMismatchError(expectedProtocol);
1165
1200
  }
1166
1201
 
1167
- if (protocolHint === 'V2' && (await this.probeProtocolV2(uuid))) {
1168
- this.deviceProtocol.set(uuid, 'V2');
1169
- Log?.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (hint)`);
1170
- return 'V2';
1202
+ if (protocolHint === 'V2') {
1203
+ if (await this.probeProtocolV2(uuid)) {
1204
+ this.deviceProtocol.set(uuid, 'V2');
1205
+ Log?.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (hint)`);
1206
+ return 'V2';
1207
+ }
1208
+ throw this.createProtocolMismatchError('V2');
1171
1209
  }
1172
1210
 
1173
1211
  if (this.deviceProtocol.get(uuid) === 'V2' && (await this.probeProtocolV2(uuid))) {
@@ -1370,18 +1408,26 @@ export default class ReactNativeBleTransport {
1370
1408
  options?: { highVolume?: boolean; writeWithResponse?: boolean }
1371
1409
  ) {
1372
1410
  const tuning = getProtocolV2BleTuning();
1373
- const packetCapacity =
1374
- Platform.OS === 'ios' ? tuning.iosPacketLength : tuning.androidPacketLength;
1411
+ const packetCapacity = resolveProtocolV2PacketCapacity({
1412
+ platform: Platform.OS,
1413
+ iosPacketLength: tuning.iosPacketLength,
1414
+ androidPacketLength: tuning.androidPacketLength,
1415
+ mtu: Platform.OS === 'android' ? transport.mtuSize : undefined,
1416
+ });
1375
1417
  const writeWithResponse =
1376
1418
  !!options?.writeWithResponse || (!!options?.highVolume && tuning.highVolumeWriteWithResponse);
1377
- const shouldThrottle = !!options?.highVolume && !writeWithResponse;
1419
+ const writeMode = resolveBleWriteMode(
1420
+ transport.writeCharacteristic,
1421
+ writeWithResponse ? 'withResponse' : 'withoutResponse'
1422
+ );
1423
+ const shouldThrottle = !!options?.highVolume && writeMode === 'withoutResponse';
1378
1424
  let packetsWritten = 0;
1379
1425
 
1380
1426
  try {
1381
1427
  for (let offset = 0; offset < frame.length; offset += packetCapacity) {
1382
1428
  const chunk = frame.slice(offset, offset + packetCapacity);
1383
1429
  const base64 = Buffer.from(chunk).toString('base64');
1384
- if (writeWithResponse) {
1430
+ if (writeMode === 'withResponse') {
1385
1431
  await transport.writeCharacteristic.writeWithResponse(base64);
1386
1432
  } else {
1387
1433
  await transport.writeCharacteristic.writeWithoutResponse(base64);
@@ -1476,8 +1522,11 @@ export default class ReactNativeBleTransport {
1476
1522
  protocolV2: this._messagesV2,
1477
1523
  },
1478
1524
  router: PROTOCOL_V2_CHANNEL_BLE_UART,
1479
- writeFrame: (frame: Uint8Array) =>
1480
- this.writeProtocolV2Frame(transport, frame, { highVolume: highVolumeWrite }),
1525
+ writeFrame: async (frame: Uint8Array) => {
1526
+ await this.writeProtocolV2Frame(transport, frame, {
1527
+ highVolume: highVolumeWrite,
1528
+ });
1529
+ },
1481
1530
  readFrame: async () => {
1482
1531
  const rxFrame = await this.readProtocolV2Frame(uuid);
1483
1532
  if (!(rxFrame instanceof Uint8Array)) {