@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.
- package/dist/BleManager.d.ts.map +1 -1
- package/dist/BleTransport.d.ts.map +1 -1
- package/dist/bleStrategy.d.ts +15 -0
- package/dist/bleStrategy.d.ts.map +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -82
- package/package.json +5 -5
- package/src/BleManager.ts +11 -12
- package/src/BleTransport.ts +1 -2
- package/src/__tests__/bleStrategy.test.ts +47 -0
- package/src/bleStrategy.ts +62 -0
- package/src/constants.ts +1 -0
- package/src/index.ts +74 -25
package/dist/BleManager.d.ts.map
CHANGED
|
@@ -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,
|
|
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;
|
|
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"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -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;
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -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;
|
|
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;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAIL,UAAU,IAAI,aAAa,EAE5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAEhB,KAAK,oBAAoB,EAGzB,KAAK,YAAY,EAGjB,KAAK,oBAAoB,EAE1B,MAAM,wBAAwB,CAAC;
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
86
|
+
cleanup();
|
|
88
87
|
resolve(peripheral);
|
|
89
88
|
}
|
|
90
89
|
else if (hasCanceled) {
|
|
91
|
-
cleanup(
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
486
|
-
if (
|
|
487
|
-
|
|
488
|
-
yield
|
|
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
|
|
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
|
-
(
|
|
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: ', (
|
|
806
|
-
(
|
|
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 ((
|
|
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
|
-
(
|
|
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 ((
|
|
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'
|
|
1095
|
-
this.
|
|
1096
|
-
|
|
1097
|
-
|
|
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 =
|
|
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
|
|
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 (
|
|
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
|
|
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.
|
|
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.
|
|
23
|
-
"@onekeyfe/hd-shared": "1.1.27-alpha.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.1.27-alpha.
|
|
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": "
|
|
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:
|
|
24
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
25
|
+
let cleanupListener: (() => void) | undefined;
|
|
25
26
|
|
|
26
|
-
const cleanup = (
|
|
27
|
+
const cleanup = () => {
|
|
27
28
|
if (timeout) {
|
|
28
29
|
clearTimeout(timeout);
|
|
29
30
|
}
|
|
30
31
|
if (cleanupListener) cleanupListener();
|
|
31
32
|
};
|
|
32
33
|
|
|
33
|
-
|
|
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(
|
|
49
|
+
cleanup();
|
|
51
50
|
resolve(peripheral);
|
|
52
51
|
} else if (hasCanceled) {
|
|
53
|
-
cleanup(
|
|
52
|
+
cleanup();
|
|
54
53
|
reject(ERRORS.TypedError(HardwareErrorCode.BleDeviceBondedCanceled, 'bonding canceled'));
|
|
55
54
|
}
|
|
56
55
|
});
|
package/src/BleTransport.ts
CHANGED
|
@@ -14,7 +14,7 @@ export default class BleTransport {
|
|
|
14
14
|
|
|
15
15
|
device: Device;
|
|
16
16
|
|
|
17
|
-
mtuSize =
|
|
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
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
410
|
-
* it
|
|
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
|
|
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
|
|
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'
|
|
1168
|
-
this.
|
|
1169
|
-
|
|
1170
|
-
|
|
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
|
|
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
|
|
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 (
|
|
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, {
|
|
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)) {
|