unified-ble-manager 4.0.26 → 4.0.28
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/CHANGELOG.md +25 -0
- package/MIGRATION_4.0.md +1 -1
- package/README.md +1 -1
- package/RELEASE.md +19 -3
- package/SBOM.cdx.json +4 -4
- package/THIRD_PARTY_LICENSES.json +1 -1
- package/docs/ELECTRON.md +1 -1
- package/docs/EXPO_PLUGIN.md +1 -1
- package/docs/GAPS.4.0.md +1 -1
- package/docs/GETTING_STARTED.md +3 -3
- package/docs/NODE.md +1 -1
- package/docs/WEB.md +1 -1
- package/docs/generated/PLATFORM_SUPPORT.md +1 -1
- package/ios/NativeProtocol/UnifiedBleProtocolAppleExecution.hpp +2 -1
- package/ios/NativeProtocol/UnifiedBleProtocolAppleExecution.mm +23 -7
- package/ios/NativeProtocol/UnifiedBleProtocolAppleExecutionState.hpp +5 -1
- package/ios/Owned/OwnedCoreBluetoothProtocolRadio.swift +2 -0
- package/ios/Owned/OwnedCoreBluetoothProtocolRadioCancellation.swift +4 -0
- package/ios/Owned/OwnedCoreBluetoothProtocolRadioOwner.swift +149 -0
- package/ios/UnifiedBleProtocolControl.mm +23 -11
- package/lib/commonjs/implementation-version.js +1 -1
- package/lib/module/implementation-version.js +1 -1
- package/lib/typescript/commonjs/src/backends/bluez/bluez-backend-provider.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/corebluetooth/corebluetooth-identity.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/reactnative/react-native-android-provider.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/reactnative/react-native-apple-provider.d.ts +1 -1
- package/lib/typescript/commonjs/src/backends/winrt/winrt-provider.d.ts +1 -1
- package/lib/typescript/commonjs/src/implementation-version.d.ts +1 -1
- package/lib/typescript/module/src/backends/bluez/bluez-backend-provider.d.ts +1 -1
- package/lib/typescript/module/src/backends/corebluetooth/corebluetooth-identity.d.ts +1 -1
- package/lib/typescript/module/src/backends/reactnative/react-native-android-provider.d.ts +1 -1
- package/lib/typescript/module/src/backends/reactnative/react-native-apple-provider.d.ts +1 -1
- package/lib/typescript/module/src/backends/winrt/winrt-provider.d.ts +1 -1
- package/lib/typescript/module/src/implementation-version.d.ts +1 -1
- package/native/PREBUILDS.json +5 -5
- package/native/electron/corebluetooth/prebuilds/darwin-arm64/unified_ble_corebluetooth.node +0 -0
- package/native/electron/corebluetooth/prebuilds/darwin-x64/unified_ble_corebluetooth.node +0 -0
- package/native/electron/winrt/prebuilds/win32-arm64/unified_ble_winrt.node +0 -0
- package/native/electron/winrt/prebuilds/win32-x64/unified_ble_winrt.node +0 -0
- package/native/tauri/src/btleplug_dispatcher.rs +18 -3
- package/package.json +1 -1
- package/src/implementation-version.ts +1 -1
- package/unified-ble-manager.podspec +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,31 @@ All notable changes to `unified-ble-manager` are documented here.
|
|
|
6
6
|
|
|
7
7
|
No changes yet.
|
|
8
8
|
|
|
9
|
+
## [4.0.28] - 2026-09-09
|
|
10
|
+
|
|
11
|
+
### Fixes
|
|
12
|
+
|
|
13
|
+
- React Native Apple hosts now keep one process-owned CoreBluetooth restoration
|
|
14
|
+
radio for each immutable native configuration. Reconstructing the TurboModule
|
|
15
|
+
borrows that radio instead of registering another `CBCentralManager` with the
|
|
16
|
+
same restoration identifier, avoiding duplicate-restoration ownership and
|
|
17
|
+
preserving the OS restoration provider across JavaScript runtime replacement.
|
|
18
|
+
- Apple protocol attachments claim callback delivery exclusively and fail closed
|
|
19
|
+
if another attachment is active. Closing or invalidating an attachment releases
|
|
20
|
+
only that borrower's scans, subscriptions, pending operations, and non-restored
|
|
21
|
+
connections; it no longer destroys the process-owned restoration provider.
|
|
22
|
+
|
|
23
|
+
## [4.0.27] - 2026-09-06
|
|
24
|
+
|
|
25
|
+
### Fixes
|
|
26
|
+
|
|
27
|
+
- Tauri continuous scans now pace synthetic peripheral-inventory snapshots at
|
|
28
|
+
two-second intervals instead of replaying the full inventory four times per
|
|
29
|
+
second. Real btleplug advertisement events remain event-driven. This keeps
|
|
30
|
+
discovery live when platform events are silent or closed while sharply reducing
|
|
31
|
+
bounded IPC pressure without suppressing real `duplicates: "all"` reports.
|
|
32
|
+
Slow inventory work delays the next poll instead of triggering catch-up bursts.
|
|
33
|
+
|
|
9
34
|
## [4.0.26] - 2026-09-06
|
|
10
35
|
|
|
11
36
|
### Fixes
|
package/MIGRATION_4.0.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Migrating from react-native-ble-plx
|
|
4
4
|
|
|
5
|
-
This source targets `4.0.
|
|
5
|
+
This source targets `4.0.28`. The `4.0.0` release is a new package and a new contract. It is **not a source-compatible rename**. There is no `new BleManager()` facade, no Base64 characteristic values, and no public transaction IDs.
|
|
6
6
|
|
|
7
7
|
This page is for a React Native app that already uses `react-native-ble-plx`. Web, Electron, Node, and Tauri are new hosts — use those pages after you understand the RN rewrite.
|
|
8
8
|
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ root import does not pick a radio. Package SemVer and backend support labels are
|
|
|
18
18
|
independent: each radio backend keeps its evidence-derived label. See
|
|
19
19
|
[`docs/PLATFORMS.md`](docs/PLATFORMS.md).
|
|
20
20
|
|
|
21
|
-
This source tree is versioned `4.0.
|
|
21
|
+
This source tree is versioned `4.0.28`. Install the exact version shown in the npm
|
|
22
22
|
registry. During release preparation, the version in `package.json` can be ahead
|
|
23
23
|
of npm until the matching tag-driven workflow publishes it; the registry and
|
|
24
24
|
GitHub release remain authoritative.
|
package/RELEASE.md
CHANGED
|
@@ -83,8 +83,8 @@ On release day, set `release_candidate` to the exact candidate required by the
|
|
|
83
83
|
release plan. RC2, RC3, RC4, `4.0.0-rc.4.1`, and RC5 are already immutable
|
|
84
84
|
once tagged. Stable `4.0.0` through `4.0.20` are immutable. The unpublished
|
|
85
85
|
`v4.0.21` tag is also immutable after its cancelled workflow. `4.0.22`,
|
|
86
|
-
`4.0.23`, `4.0.24`, and `4.0.
|
|
87
|
-
prepares `4.0.
|
|
86
|
+
`4.0.23`, `4.0.24`, `4.0.25`, `4.0.26`, and `4.0.27` are immutable tagged
|
|
87
|
+
history. This branch prepares `4.0.28`.
|
|
88
88
|
|
|
89
89
|
```sh
|
|
90
90
|
release_candidate=4.0.0-rc.N
|
|
@@ -112,6 +112,22 @@ The first stable tag `v4.0.0` is immutable published history. Do not recreate or
|
|
|
112
112
|
git tag -a v4.0.0 -m "v4.0.0"
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
## Releasing 4.0.28
|
|
116
|
+
|
|
117
|
+
Release `v4.0.28` only from the exact current `main` commit after its canonical
|
|
118
|
+
CI succeeds. Verify `package.json` is `4.0.28`, the worktree is clean, and
|
|
119
|
+
release-note extraction finds `## [4.0.28]`. Push a new annotated `v4.0.28`
|
|
120
|
+
tag; never move the immutable `v4.0.27` tag. Follow the required local validation,
|
|
121
|
+
publish workflow, and registry verification below.
|
|
122
|
+
|
|
123
|
+
## Releasing 4.0.27
|
|
124
|
+
|
|
125
|
+
Release `v4.0.27` only from the exact current `main` commit after its canonical
|
|
126
|
+
CI succeeds. Verify `package.json` is `4.0.27`, the worktree is clean, and
|
|
127
|
+
release-note extraction finds `## [4.0.27]`. Push a new annotated `v4.0.27`
|
|
128
|
+
tag; never move the immutable `v4.0.26` tag. Follow the required local validation,
|
|
129
|
+
publish workflow, and registry verification below.
|
|
130
|
+
|
|
115
131
|
## Releasing 4.0.26
|
|
116
132
|
|
|
117
133
|
Release `v4.0.26` only from the exact current `main` commit after its canonical
|
|
@@ -508,7 +524,7 @@ a green publish job and a package a consumer can actually install are not the
|
|
|
508
524
|
same claim.
|
|
509
525
|
|
|
510
526
|
```sh
|
|
511
|
-
version=4.0.
|
|
527
|
+
version=4.0.28
|
|
512
528
|
|
|
513
529
|
npm view "unified-ble-manager@$version" version
|
|
514
530
|
npm view unified-ble-manager dist-tags --json
|
package/SBOM.cdx.json
CHANGED
|
@@ -6,15 +6,15 @@
|
|
|
6
6
|
"metadata": {
|
|
7
7
|
"component": {
|
|
8
8
|
"type": "library",
|
|
9
|
-
"bom-ref": "pkg:npm/unified-ble-manager@4.0.
|
|
9
|
+
"bom-ref": "pkg:npm/unified-ble-manager@4.0.28",
|
|
10
10
|
"name": "unified-ble-manager",
|
|
11
|
-
"version": "4.0.
|
|
11
|
+
"version": "4.0.28",
|
|
12
12
|
"licenses": [
|
|
13
13
|
{
|
|
14
14
|
"expression": "Apache-2.0"
|
|
15
15
|
}
|
|
16
16
|
],
|
|
17
|
-
"purl": "pkg:npm/unified-ble-manager@4.0.
|
|
17
|
+
"purl": "pkg:npm/unified-ble-manager@4.0.28"
|
|
18
18
|
},
|
|
19
19
|
"properties": [
|
|
20
20
|
{
|
|
@@ -537,7 +537,7 @@
|
|
|
537
537
|
"dependsOn": []
|
|
538
538
|
},
|
|
539
539
|
{
|
|
540
|
-
"ref": "pkg:npm/unified-ble-manager@4.0.
|
|
540
|
+
"ref": "pkg:npm/unified-ble-manager@4.0.28",
|
|
541
541
|
"dependsOn": [
|
|
542
542
|
"pkg:npm/%40babel/runtime@7.29.7",
|
|
543
543
|
"pkg:npm/node-addon-api@8.9.0",
|
package/docs/ELECTRON.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Main owns the radio. The renderer uses a versioned IPC client and never loads a native addon.
|
|
6
6
|
|
|
7
|
-
This source targets `4.0.
|
|
7
|
+
This source targets `4.0.28`. Tagged releases ship Node-API v8 prebuilds covering macOS and Windows `arm64`/`x64` for both Node and modern Electron.
|
|
8
8
|
|
|
9
9
|
`unified-ble-manager/electron/main` and
|
|
10
10
|
`unified-ble-manager/electron/renderer` are the only Electron entrypoints.
|
package/docs/EXPO_PLUGIN.md
CHANGED
|
@@ -7,7 +7,7 @@ start a radio, request runtime permissions during prebuild, or prove physical
|
|
|
7
7
|
radio/restoration reliability. Expo Go is not a supported BLE execution
|
|
8
8
|
environment because it cannot contain this native module.
|
|
9
9
|
|
|
10
|
-
Use the v2 plugin options in this `4.0.
|
|
10
|
+
Use the v2 plugin options in this `4.0.28` source. Those options match
|
|
11
11
|
the schema introduced at `4.0.0-rc.4`. Expo Go cannot load this native module.
|
|
12
12
|
|
|
13
13
|
## Installation and development build
|
package/docs/GAPS.4.0.md
CHANGED
|
@@ -14,7 +14,7 @@ This file tracks platform code, CI, package, lab, and live-radio evidence. It do
|
|
|
14
14
|
|
|
15
15
|
The clean-baseline contract, unified core, public manager, deterministic backend, TCK, native protocol, first-party backend implementations, host-isolated package exports, SDK/CLI, and legacy-absence gates exist in the 4.0 source. Passing deterministic, compile, ABI, or package tests are implementation proof; they do not become physical-radio support evidence unless a retained record proves the corresponding live scenario.
|
|
16
16
|
|
|
17
|
-
This source targets `unified-ble-manager@4.0.
|
|
17
|
+
This source targets `unified-ble-manager@4.0.28`; the npm registry and release
|
|
18
18
|
provenance, not a source version string, determine whether it is published.
|
|
19
19
|
Earlier stable releases remain immutable published history. Backend support labels remain
|
|
20
20
|
evidence-derived. This package does not rewrite the evidence inventory: a backend remains at the support level
|
package/docs/GETTING_STARTED.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
This page gets you to a first scan, connect, read, notify, and teardown on React Native. Other hosts are linked at the bottom. The root import does not turn Bluetooth on.
|
|
6
6
|
|
|
7
|
-
This source targets `4.0.
|
|
7
|
+
This source targets `4.0.28`; verify the published version in the npm registry.
|
|
8
8
|
|
|
9
9
|
## Pick a host
|
|
10
10
|
|
|
@@ -38,11 +38,11 @@ request runtime permissions on Android 12+, add
|
|
|
38
38
|
#### Expo / CNG v2
|
|
39
39
|
|
|
40
40
|
The Expo v2 schema and `unified-ble-manager/expo` factory are in this source.
|
|
41
|
-
After the npm registry lists `4.0.
|
|
41
|
+
After the npm registry lists `4.0.28`, install that exact version and keep it in
|
|
42
42
|
your lockfile while validating the native build:
|
|
43
43
|
|
|
44
44
|
```sh
|
|
45
|
-
pnpm add unified-ble-manager@4.0.
|
|
45
|
+
pnpm add unified-ble-manager@4.0.28
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
The package does not run in Expo Go.
|
package/docs/NODE.md
CHANGED
|
@@ -10,7 +10,7 @@ The root import does not open an adapter. Pick one backend:
|
|
|
10
10
|
| `unified-ble-manager/node/winrt` | Windows |
|
|
11
11
|
| `unified-ble-manager/node/bluez` | Linux (needs `dbus-next@^0.10.2` in the app) |
|
|
12
12
|
|
|
13
|
-
This source targets `4.0.
|
|
13
|
+
This source targets `4.0.28`. Tagged releases ship Node-API v8 prebuilds for macOS and Windows on `arm64` and `x64`. A normal install should not compile native code. BlueZ talks D-Bus and has no addon.
|
|
14
14
|
|
|
15
15
|
## One-call factories
|
|
16
16
|
|
package/docs/WEB.md
CHANGED
|
@@ -6,7 +6,7 @@ Use `unified-ble-manager/web` to run the public UBM manager directly in a browse
|
|
|
6
6
|
|
|
7
7
|
The complete runnable TypeScript/Vite application is in [`example-web/`](../example-web/).
|
|
8
8
|
|
|
9
|
-
This guide targets `4.0.
|
|
9
|
+
This guide targets `4.0.28`. Web Bluetooth support still depends on the browser, operating system, adapter, and peripheral. UBM reports those runtime boundaries; it does not fabricate a fallback backend.
|
|
10
10
|
|
|
11
11
|
## Requirements
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@ This page is generated by `scripts/docs/generate-platform-support.js` from valid
|
|
|
6
6
|
|
|
7
7
|
## Current package
|
|
8
8
|
|
|
9
|
-
`unified-ble-manager@4.0.
|
|
9
|
+
`unified-ble-manager@4.0.28`
|
|
10
10
|
|
|
11
11
|
No evidence record is bound to this exact package version and artifact. Consequently, this generated page makes no Preview, Live Preview, Supported, or Reliability-qualified platform claim for the current package.
|
|
12
12
|
|
|
@@ -22,7 +22,8 @@ class AppleNativeProtocolExecution final {
|
|
|
22
22
|
|
|
23
23
|
AppleNativeProtocolExecution(
|
|
24
24
|
std::shared_ptr<native_protocol::v2::NativeProtocolControlRuntime> runtime,
|
|
25
|
-
void* radio
|
|
25
|
+
void* radio,
|
|
26
|
+
void* radioBorrower = nullptr);
|
|
26
27
|
~AppleNativeProtocolExecution();
|
|
27
28
|
|
|
28
29
|
AppleNativeProtocolExecution(const AppleNativeProtocolExecution&) = delete;
|
|
@@ -191,10 +191,15 @@ namespace unified_ble::apple_protocol {
|
|
|
191
191
|
|
|
192
192
|
AppleNativeProtocolExecution::State::State(
|
|
193
193
|
std::shared_ptr<protocol::NativeProtocolControlRuntime> runtimeValue,
|
|
194
|
-
void* radioValue
|
|
195
|
-
|
|
194
|
+
void* radioValue,
|
|
195
|
+
void* radioBorrowerValue)
|
|
196
|
+
: runtime(std::move(runtimeValue)), radio(radioValue), radioBorrower(radioBorrowerValue) {
|
|
197
|
+
if (radioBorrower != nullptr) CFRetain(radioBorrower);
|
|
198
|
+
}
|
|
196
199
|
|
|
197
|
-
AppleNativeProtocolExecution::State::~State()
|
|
200
|
+
AppleNativeProtocolExecution::State::~State() {
|
|
201
|
+
if (radioBorrower != nullptr) CFRelease(radioBorrower);
|
|
202
|
+
}
|
|
198
203
|
|
|
199
204
|
namespace {
|
|
200
205
|
|
|
@@ -202,6 +207,10 @@ OwnedCoreBluetoothProtocolRadio* radioFor(const std::shared_ptr<AppleNativeProto
|
|
|
202
207
|
return (__bridge OwnedCoreBluetoothProtocolRadio*)state->radio;
|
|
203
208
|
}
|
|
204
209
|
|
|
210
|
+
id radioBorrowerFor(const std::shared_ptr<AppleNativeProtocolExecution::State>& state) {
|
|
211
|
+
return (__bridge id)state->radioBorrower;
|
|
212
|
+
}
|
|
213
|
+
|
|
205
214
|
bool boundedBufferCanAdmit(
|
|
206
215
|
const protocol::BoundedNativeEventBuffer& buffer,
|
|
207
216
|
std::size_t recordBytes,
|
|
@@ -466,7 +475,10 @@ void failAttachmentAfterTerminalAdmissionFailure(
|
|
|
466
475
|
notifyJavaScriptFatalSink(state, context, fatalAttachmentGeneration);
|
|
467
476
|
if (releaseRadio) {
|
|
468
477
|
@try {
|
|
469
|
-
[
|
|
478
|
+
[OwnedCoreBluetoothProtocolRadioOwner
|
|
479
|
+
releaseBorrowerWithRadio:radioFor(state)
|
|
480
|
+
delegate:radioBorrowerFor(state)
|
|
481
|
+
completion:^(NSError* error) {
|
|
470
482
|
if (error != nil) {
|
|
471
483
|
NSLog(@"[UnifiedBleProtocolAppleExecution] %s radio release failed: %@", context, error.localizedDescription);
|
|
472
484
|
}
|
|
@@ -1348,7 +1360,10 @@ void dispatchCommand(
|
|
|
1348
1360
|
return;
|
|
1349
1361
|
}
|
|
1350
1362
|
if (kind == "destroy") {
|
|
1351
|
-
[
|
|
1363
|
+
[OwnedCoreBluetoothProtocolRadioOwner
|
|
1364
|
+
releaseBorrowerWithRadio:radio
|
|
1365
|
+
delegate:radioBorrowerFor(state)
|
|
1366
|
+
completion:^(NSError* error) {
|
|
1352
1367
|
if (error == nil) static_cast<void>(success(state, command));
|
|
1353
1368
|
else fail(state, command, "destroyFailed", error);
|
|
1354
1369
|
}];
|
|
@@ -1745,8 +1760,9 @@ void logAppleNativeFailure(const char* context, const std::exception& error) {
|
|
|
1745
1760
|
|
|
1746
1761
|
AppleNativeProtocolExecution::AppleNativeProtocolExecution(
|
|
1747
1762
|
std::shared_ptr<protocol::NativeProtocolControlRuntime> runtime,
|
|
1748
|
-
void* radio
|
|
1749
|
-
|
|
1763
|
+
void* radio,
|
|
1764
|
+
void* radioBorrower)
|
|
1765
|
+
: state_(std::make_shared<State>(std::move(runtime), radio, radioBorrower)) {}
|
|
1750
1766
|
|
|
1751
1767
|
AppleNativeProtocolExecution::~AppleNativeProtocolExecution() {
|
|
1752
1768
|
close();
|
|
@@ -39,11 +39,15 @@ class AppleNativeProtocolExecution::State final : public std::enable_shared_from
|
|
|
39
39
|
std::optional<native_protocol::v2::ProtocolRecord> error;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
State(
|
|
42
|
+
State(
|
|
43
|
+
std::shared_ptr<native_protocol::v2::NativeProtocolControlRuntime> runtimeValue,
|
|
44
|
+
void* radioValue,
|
|
45
|
+
void* radioBorrowerValue = nullptr);
|
|
43
46
|
~State();
|
|
44
47
|
|
|
45
48
|
std::shared_ptr<native_protocol::v2::NativeProtocolControlRuntime> runtime;
|
|
46
49
|
void* radio;
|
|
50
|
+
void* radioBorrower;
|
|
47
51
|
std::shared_ptr<facebook::react::CallInvoker> callInvoker;
|
|
48
52
|
std::shared_ptr<facebook::jsi::Function> eventSink;
|
|
49
53
|
std::shared_ptr<facebook::jsi::Function> fatalSink;
|
|
@@ -25,6 +25,8 @@ public final class OwnedCoreBluetoothProtocolRadio: NSObject, CBPeripheralDelega
|
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
@objc public weak var delegate: OwnedCoreBluetoothProtocolRadioDelegate?
|
|
28
|
+
let borrowerRelease = OwnedCoreBluetoothBorrowerReleaseCoordinator()
|
|
29
|
+
var borrowerReleaseRetryScheduled = false
|
|
28
30
|
|
|
29
31
|
let queue: DispatchQueue
|
|
30
32
|
var central: CBCentralManager!
|
|
@@ -256,6 +256,10 @@ extension OwnedCoreBluetoothProtocolRadio {
|
|
|
256
256
|
completion(error)
|
|
257
257
|
return
|
|
258
258
|
}
|
|
259
|
+
if error != nil && !destroyRadio {
|
|
260
|
+
completion(error)
|
|
261
|
+
return
|
|
262
|
+
}
|
|
259
263
|
for (identifier, peripheral) in self.peripheralByIdentifier where !restoredIdentifiers.contains(identifier) {
|
|
260
264
|
peripheral.delegate = nil
|
|
261
265
|
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// ios/Owned/OwnedCoreBluetoothProtocolRadioOwner.swift
|
|
2
|
+
|
|
3
|
+
import Foundation
|
|
4
|
+
|
|
5
|
+
/** Queue-confined attachment/release state, split from CoreBluetooth for executable race tests. */
|
|
6
|
+
final class OwnedCoreBluetoothBorrowerReleaseCoordinator {
|
|
7
|
+
typealias Completion = (NSError?) -> Void
|
|
8
|
+
|
|
9
|
+
enum ReleaseAdmission {
|
|
10
|
+
case noBorrower
|
|
11
|
+
case joined
|
|
12
|
+
case start
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private var activeBorrower: ObjectIdentifier?
|
|
16
|
+
private var releasing = false
|
|
17
|
+
private var completions = [Completion]()
|
|
18
|
+
|
|
19
|
+
var releaseInProgress: Bool { releasing }
|
|
20
|
+
|
|
21
|
+
func attach(_ candidate: AnyObject) -> Bool {
|
|
22
|
+
guard activeBorrower == nil, !releasing else { return false }
|
|
23
|
+
activeBorrower = ObjectIdentifier(candidate)
|
|
24
|
+
return true
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
func beginRelease(_ candidate: AnyObject, completion: @escaping Completion) -> ReleaseAdmission {
|
|
28
|
+
guard activeBorrower == ObjectIdentifier(candidate) else { return .noBorrower }
|
|
29
|
+
completions.append(completion)
|
|
30
|
+
guard !releasing else { return .joined }
|
|
31
|
+
releasing = true
|
|
32
|
+
return .start
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func finish(_ error: NSError?) -> [Completion] {
|
|
36
|
+
if error == nil { activeBorrower = nil }
|
|
37
|
+
releasing = false
|
|
38
|
+
let pending = completions
|
|
39
|
+
completions.removeAll()
|
|
40
|
+
return pending
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
extension OwnedCoreBluetoothProtocolRadio {
|
|
45
|
+
/**
|
|
46
|
+
* Claims the sole JavaScript event route for this process-owned radio.
|
|
47
|
+
* A second TurboModule must not steal callbacks from an attached borrower.
|
|
48
|
+
*/
|
|
49
|
+
@objc public func attachDelegateIfAvailable(_ candidate: OwnedCoreBluetoothProtocolRadioDelegate) -> Bool {
|
|
50
|
+
queue.sync {
|
|
51
|
+
guard borrowerRelease.attach(candidate) else { return false }
|
|
52
|
+
delegate = candidate
|
|
53
|
+
return true
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Releases one borrower without opening an attachment gap during physical
|
|
59
|
+
* cleanup. Concurrent releases join the same terminal cleanup result.
|
|
60
|
+
*/
|
|
61
|
+
@objc public func releaseBorrowerIfCurrent(
|
|
62
|
+
_ candidate: OwnedCoreBluetoothProtocolRadioDelegate,
|
|
63
|
+
completion: @escaping (NSError?) -> Void
|
|
64
|
+
) {
|
|
65
|
+
queue.async {
|
|
66
|
+
switch self.borrowerRelease.beginRelease(candidate, completion: completion) {
|
|
67
|
+
case .noBorrower:
|
|
68
|
+
completion(nil)
|
|
69
|
+
return
|
|
70
|
+
case .joined:
|
|
71
|
+
return
|
|
72
|
+
case .start:
|
|
73
|
+
break
|
|
74
|
+
}
|
|
75
|
+
self.releaseProtocolClient { error in
|
|
76
|
+
if error == nil, let current = self.delegate, current === candidate {
|
|
77
|
+
self.delegate = nil
|
|
78
|
+
}
|
|
79
|
+
let completions = self.borrowerRelease.finish(error)
|
|
80
|
+
if error != nil {
|
|
81
|
+
self.scheduleBorrowerReleaseRetry(candidate)
|
|
82
|
+
}
|
|
83
|
+
for pendingCompletion in completions {
|
|
84
|
+
pendingCompletion(error)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private func scheduleBorrowerReleaseRetry(_ candidate: OwnedCoreBluetoothProtocolRadioDelegate) {
|
|
91
|
+
guard !borrowerReleaseRetryScheduled else { return }
|
|
92
|
+
borrowerReleaseRetryScheduled = true
|
|
93
|
+
queue.asyncAfter(deadline: .now() + .seconds(1)) {
|
|
94
|
+
self.borrowerReleaseRetryScheduled = false
|
|
95
|
+
self.releaseBorrowerIfCurrent(candidate) { _ in }
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Process lifetime registry for CoreBluetooth centrals selected by immutable
|
|
102
|
+
* native configuration. React Native may construct its TurboModule more than
|
|
103
|
+
* once; those modules borrow the same radio rather than registering duplicate
|
|
104
|
+
* CoreBluetooth restoration identifiers.
|
|
105
|
+
*/
|
|
106
|
+
@objc(OwnedCoreBluetoothProtocolRadioOwner)
|
|
107
|
+
public final class OwnedCoreBluetoothProtocolRadioOwner: NSObject {
|
|
108
|
+
private struct Configuration: Hashable {
|
|
109
|
+
let restoreIdentifierKey: String?
|
|
110
|
+
let showPowerAlert: Bool?
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private static let lock = NSLock()
|
|
114
|
+
private static var radios = [Configuration: OwnedCoreBluetoothProtocolRadio]()
|
|
115
|
+
|
|
116
|
+
@objc(acquireWithRestoreIdentifierKey:showPowerAlert:)
|
|
117
|
+
public static func acquire(
|
|
118
|
+
restoreIdentifierKey: String?,
|
|
119
|
+
showPowerAlert: NSNumber?
|
|
120
|
+
) -> OwnedCoreBluetoothProtocolRadio {
|
|
121
|
+
let configuration = Configuration(
|
|
122
|
+
restoreIdentifierKey: restoreIdentifierKey,
|
|
123
|
+
showPowerAlert: showPowerAlert?.boolValue
|
|
124
|
+
)
|
|
125
|
+
lock.lock()
|
|
126
|
+
defer { lock.unlock() }
|
|
127
|
+
if let existing = radios[configuration] { return existing }
|
|
128
|
+
let created = OwnedCoreBluetoothProtocolRadio(
|
|
129
|
+
restoreIdentifierKey: restoreIdentifierKey,
|
|
130
|
+
showPowerAlert: showPowerAlert
|
|
131
|
+
)
|
|
132
|
+
radios[configuration] = created
|
|
133
|
+
return created
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* A borrower releases its own radio work only when it still owns callback
|
|
138
|
+
* delivery. The process-owned central remains available for restoration and
|
|
139
|
+
* a replacement TurboModule.
|
|
140
|
+
*/
|
|
141
|
+
@objc(releaseBorrowerWithRadio:delegate:completion:)
|
|
142
|
+
public static func releaseBorrower(
|
|
143
|
+
radio: OwnedCoreBluetoothProtocolRadio,
|
|
144
|
+
delegate: OwnedCoreBluetoothProtocolRadioDelegate,
|
|
145
|
+
completion: @escaping (NSError?) -> Void
|
|
146
|
+
) {
|
|
147
|
+
radio.releaseBorrowerIfCurrent(delegate, completion: completion)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -351,8 +351,8 @@ RCT_EXPORT_MODULE(UnifiedBleProtocolControl)
|
|
|
351
351
|
_restorationClientId = derived[@"clientId"];
|
|
352
352
|
_restorationHostSessionScope = derived[@"hostSessionScope"];
|
|
353
353
|
NSNumber *showPowerAlert = configuredInfoBool(@"UnifiedBleProtocolShowPowerAlert");
|
|
354
|
-
_radio = [
|
|
355
|
-
|
|
354
|
+
_radio = [OwnedCoreBluetoothProtocolRadioOwner
|
|
355
|
+
acquireWithRestoreIdentifierKey:(
|
|
356
356
|
hasCompleteRestorationConfiguration(
|
|
357
357
|
_restorationRestoreIdentifier,
|
|
358
358
|
_restorationNamespace,
|
|
@@ -362,10 +362,11 @@ RCT_EXPORT_MODULE(UnifiedBleProtocolControl)
|
|
|
362
362
|
? _restorationRestoreIdentifier
|
|
363
363
|
: nil)
|
|
364
364
|
showPowerAlert:showPowerAlert];
|
|
365
|
+
_radioDelegate = [UnifiedBleProtocolAppleRadioDelegate new];
|
|
365
366
|
_execution = std::make_shared<unified_ble::apple_protocol::AppleNativeProtocolExecution>(
|
|
366
367
|
_runtime,
|
|
367
|
-
(__bridge void *)_radio
|
|
368
|
-
|
|
368
|
+
(__bridge void *)_radio,
|
|
369
|
+
(__bridge void *)_radioDelegate);
|
|
369
370
|
_radioDelegate.execution = _execution.get();
|
|
370
371
|
}
|
|
371
372
|
return self;
|
|
@@ -508,8 +509,13 @@ RCT_EXPORT_MODULE(UnifiedBleProtocolControl)
|
|
|
508
509
|
return;
|
|
509
510
|
}
|
|
510
511
|
}
|
|
512
|
+
if (![_radio attachDelegateIfAvailable:_radioDelegate]) {
|
|
513
|
+
_execution->detachAttachment();
|
|
514
|
+
_runtime->close(attachment);
|
|
515
|
+
rejectControl(reject, @"nativeProtocolHandshake", @"The process-owned Apple radio already has an attached protocol client");
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
511
518
|
_attachment = [requestedAttachment copy];
|
|
512
|
-
_radio.delegate = _radioDelegate;
|
|
513
519
|
_execution->receiveAdapterState((__bridge void *)[_radio adapterSnapshot]);
|
|
514
520
|
resolve(@{
|
|
515
521
|
@"nativeProtocol": @2,
|
|
@@ -713,14 +719,21 @@ RCT_EXPORT_MODULE(UnifiedBleProtocolControl)
|
|
|
713
719
|
attachment.backendGeneration(),
|
|
714
720
|
attachment.adapterId(),
|
|
715
721
|
attachment.adapterGeneration());
|
|
716
|
-
_radio.delegate = nil;
|
|
717
722
|
_radioDelegate.execution = nullptr;
|
|
718
723
|
_execution->detachAttachment();
|
|
719
724
|
if (_runtime->open()) {
|
|
720
725
|
_runtime->close(nativeAttachmentValue);
|
|
721
726
|
}
|
|
722
|
-
|
|
723
|
-
|
|
727
|
+
[OwnedCoreBluetoothProtocolRadioOwner releaseBorrowerWithRadio:_radio delegate:_radioDelegate completion:^(NSError *error) {
|
|
728
|
+
if (error != nil) {
|
|
729
|
+
rejectControl(reject, @"nativeProtocolClose", error.localizedDescription);
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if ([_attachment isEqualToDictionary:requestedAttachment]) {
|
|
733
|
+
_attachment = nil;
|
|
734
|
+
}
|
|
735
|
+
resolve(nil);
|
|
736
|
+
}];
|
|
724
737
|
} catch (const std::exception& error) {
|
|
725
738
|
rejectControl(reject, @"nativeProtocolClose", [NSString stringWithUTF8String:error.what()]);
|
|
726
739
|
}
|
|
@@ -728,7 +741,6 @@ RCT_EXPORT_MODULE(UnifiedBleProtocolControl)
|
|
|
728
741
|
|
|
729
742
|
- (void)invalidate {
|
|
730
743
|
NSDictionary *attachment = [_attachment copy];
|
|
731
|
-
_radio.delegate = nil;
|
|
732
744
|
_radioDelegate.execution = nullptr;
|
|
733
745
|
_execution->close();
|
|
734
746
|
BOOL runtimeClosed = !_runtime->open();
|
|
@@ -747,9 +759,9 @@ RCT_EXPORT_MODULE(UnifiedBleProtocolControl)
|
|
|
747
759
|
NSLog(@"[UnifiedBleProtocolControl] native runtime close during invalidation failed with an unknown exception");
|
|
748
760
|
}
|
|
749
761
|
}
|
|
750
|
-
[_radio
|
|
762
|
+
[OwnedCoreBluetoothProtocolRadioOwner releaseBorrowerWithRadio:_radio delegate:_radioDelegate completion:^(NSError *error) {
|
|
751
763
|
if (error != nil) {
|
|
752
|
-
NSLog(@"[UnifiedBleProtocolControl] radio
|
|
764
|
+
NSLog(@"[UnifiedBleProtocolControl] radio borrower release during invalidation failed: %@", error.localizedDescription);
|
|
753
765
|
}
|
|
754
766
|
}];
|
|
755
767
|
if (runtimeClosed) _attachment = nil;
|
|
@@ -7,5 +7,5 @@ exports.UNIFIED_BLE_IMPLEMENTATION_VERSION = void 0;
|
|
|
7
7
|
// src/implementation-version.ts
|
|
8
8
|
|
|
9
9
|
/** The one production version stamped into every first-party backend identity. */
|
|
10
|
-
const UNIFIED_BLE_IMPLEMENTATION_VERSION = exports.UNIFIED_BLE_IMPLEMENTATION_VERSION = '4.0.
|
|
10
|
+
const UNIFIED_BLE_IMPLEMENTATION_VERSION = exports.UNIFIED_BLE_IMPLEMENTATION_VERSION = '4.0.28';
|
|
11
11
|
//# sourceMappingURL=implementation-version.js.map
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
// src/implementation-version.ts
|
|
4
4
|
|
|
5
5
|
/** The one production version stamped into every first-party backend identity. */
|
|
6
|
-
export const UNIFIED_BLE_IMPLEMENTATION_VERSION = '4.0.
|
|
6
|
+
export const UNIFIED_BLE_IMPLEMENTATION_VERSION = '4.0.28';
|
|
7
7
|
//# sourceMappingURL=implementation-version.js.map
|
|
@@ -4,7 +4,7 @@ import { type BackendCompatibilityOffer } from '../../backend-contract/primitive
|
|
|
4
4
|
import { type BluezBusKind, type BluezDbusBoundaryFactory } from './bluez-dbus-contract';
|
|
5
5
|
export declare const BLUEZ_BACKEND_ID = "unified-ble:bluez-dbus";
|
|
6
6
|
export declare const BLUEZ_PLATFORM_ID = "unified-ble:linux-bluez";
|
|
7
|
-
export declare const BLUEZ_IMPLEMENTATION_VERSION = "4.0.
|
|
7
|
+
export declare const BLUEZ_IMPLEMENTATION_VERSION = "4.0.28";
|
|
8
8
|
export declare const bluezCompatibility: BackendCompatibilityOffer;
|
|
9
9
|
export interface BluezBackendProviderOptions {
|
|
10
10
|
readonly busKind: BluezBusKind;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type FeatureRegistry } from '../../backend-contract/capabilities';
|
|
2
2
|
export declare const COREBLUETOOTH_BACKEND_ID = "unified-ble:corebluetooth";
|
|
3
3
|
export declare const COREBLUETOOTH_PLATFORM_ID = "unified-ble:macos-corebluetooth";
|
|
4
|
-
export declare const COREBLUETOOTH_IMPLEMENTATION_VERSION = "4.0.
|
|
4
|
+
export declare const COREBLUETOOTH_IMPLEMENTATION_VERSION = "4.0.28";
|
|
5
5
|
/** Identity metadata for a direct-GATT boundary that shares this backend core. */
|
|
6
6
|
export interface DirectGattBackendIdentityOptions {
|
|
7
7
|
readonly registeredBackendId: string;
|
|
@@ -9,7 +9,7 @@ import { ReactNativeAndroidProtocolBoundary } from '../../native-protocol/rn-and
|
|
|
9
9
|
import { ReactNativeRestorationCoordinator, type ReactNativeRestorationActivation, type ReactNativeRestorationBackendProvider } from './react-native-restoration';
|
|
10
10
|
export declare const REACT_NATIVE_ANDROID_BACKEND_ID = "unified-ble:react-native-android";
|
|
11
11
|
export declare const REACT_NATIVE_ANDROID_PLATFORM_ID = "unified-ble:android-gatt";
|
|
12
|
-
export declare const REACT_NATIVE_ANDROID_IMPLEMENTATION_VERSION = "4.0.
|
|
12
|
+
export declare const REACT_NATIVE_ANDROID_IMPLEMENTATION_VERSION = "4.0.28";
|
|
13
13
|
export declare const REACT_NATIVE_ANDROID_DEFAULT_ADAPTER_NATIVE_ID = "android-default-adapter";
|
|
14
14
|
export declare const reactNativeAndroidCompatibility: NativeCompatibilityOffer;
|
|
15
15
|
export interface ReactNativeAndroidBackendProviderOptions {
|
|
@@ -3,7 +3,7 @@ import type { Spec as NativeProtocolControl } from '../../NativeUnifiedBleProtoc
|
|
|
3
3
|
import { type ReactNativeRestorationBackendProvider } from './react-native-restoration';
|
|
4
4
|
export declare const REACT_NATIVE_APPLE_BACKEND_ID = "unified-ble:react-native-apple";
|
|
5
5
|
export declare const REACT_NATIVE_APPLE_PLATFORM_ID = "unified-ble:apple-corebluetooth";
|
|
6
|
-
export declare const REACT_NATIVE_APPLE_IMPLEMENTATION_VERSION = "4.0.
|
|
6
|
+
export declare const REACT_NATIVE_APPLE_IMPLEMENTATION_VERSION = "4.0.28";
|
|
7
7
|
export declare const REACT_NATIVE_APPLE_DEFAULT_ADAPTER_NATIVE_ID = "apple-corebluetooth-default-adapter";
|
|
8
8
|
export declare const reactNativeAppleCompatibility: NativeCompatibilityOffer;
|
|
9
9
|
export interface ReactNativeAppleBackendProviderOptions {
|
|
@@ -3,7 +3,7 @@ import { type BackendCompatibilityOffer } from '../../backend-contract/primitive
|
|
|
3
3
|
import { type WinRtAdapterRecord, type WinRtBoundary } from './winrt-boundary';
|
|
4
4
|
export declare const WINRT_BACKEND_ID = "unified-ble:winrt";
|
|
5
5
|
export declare const WINRT_PLATFORM_ID = "unified-ble:windows-winrt";
|
|
6
|
-
export declare const WINRT_IMPLEMENTATION_VERSION = "4.0.
|
|
6
|
+
export declare const WINRT_IMPLEMENTATION_VERSION = "4.0.28";
|
|
7
7
|
export declare const winRtCompatibility: BackendCompatibilityOffer;
|
|
8
8
|
export interface WinRtBackendProviderOptions {
|
|
9
9
|
readonly boundaryFactory: () => WinRtBoundary;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** The one production version stamped into every first-party backend identity. */
|
|
2
|
-
export declare const UNIFIED_BLE_IMPLEMENTATION_VERSION = "4.0.
|
|
2
|
+
export declare const UNIFIED_BLE_IMPLEMENTATION_VERSION = "4.0.28";
|
|
3
3
|
//# sourceMappingURL=implementation-version.d.ts.map
|
|
@@ -4,7 +4,7 @@ import { type BackendCompatibilityOffer } from '../../backend-contract/primitive
|
|
|
4
4
|
import { type BluezBusKind, type BluezDbusBoundaryFactory } from './bluez-dbus-contract.js';
|
|
5
5
|
export declare const BLUEZ_BACKEND_ID = "unified-ble:bluez-dbus";
|
|
6
6
|
export declare const BLUEZ_PLATFORM_ID = "unified-ble:linux-bluez";
|
|
7
|
-
export declare const BLUEZ_IMPLEMENTATION_VERSION = "4.0.
|
|
7
|
+
export declare const BLUEZ_IMPLEMENTATION_VERSION = "4.0.28";
|
|
8
8
|
export declare const bluezCompatibility: BackendCompatibilityOffer;
|
|
9
9
|
export interface BluezBackendProviderOptions {
|
|
10
10
|
readonly busKind: BluezBusKind;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type FeatureRegistry } from '../../backend-contract/capabilities.js';
|
|
2
2
|
export declare const COREBLUETOOTH_BACKEND_ID = "unified-ble:corebluetooth";
|
|
3
3
|
export declare const COREBLUETOOTH_PLATFORM_ID = "unified-ble:macos-corebluetooth";
|
|
4
|
-
export declare const COREBLUETOOTH_IMPLEMENTATION_VERSION = "4.0.
|
|
4
|
+
export declare const COREBLUETOOTH_IMPLEMENTATION_VERSION = "4.0.28";
|
|
5
5
|
/** Identity metadata for a direct-GATT boundary that shares this backend core. */
|
|
6
6
|
export interface DirectGattBackendIdentityOptions {
|
|
7
7
|
readonly registeredBackendId: string;
|
|
@@ -9,7 +9,7 @@ import { ReactNativeAndroidProtocolBoundary } from '../../native-protocol/rn-and
|
|
|
9
9
|
import { ReactNativeRestorationCoordinator, type ReactNativeRestorationActivation, type ReactNativeRestorationBackendProvider } from './react-native-restoration.js';
|
|
10
10
|
export declare const REACT_NATIVE_ANDROID_BACKEND_ID = "unified-ble:react-native-android";
|
|
11
11
|
export declare const REACT_NATIVE_ANDROID_PLATFORM_ID = "unified-ble:android-gatt";
|
|
12
|
-
export declare const REACT_NATIVE_ANDROID_IMPLEMENTATION_VERSION = "4.0.
|
|
12
|
+
export declare const REACT_NATIVE_ANDROID_IMPLEMENTATION_VERSION = "4.0.28";
|
|
13
13
|
export declare const REACT_NATIVE_ANDROID_DEFAULT_ADAPTER_NATIVE_ID = "android-default-adapter";
|
|
14
14
|
export declare const reactNativeAndroidCompatibility: NativeCompatibilityOffer;
|
|
15
15
|
export interface ReactNativeAndroidBackendProviderOptions {
|
|
@@ -3,7 +3,7 @@ import type { Spec as NativeProtocolControl } from '../../NativeUnifiedBleProtoc
|
|
|
3
3
|
import { type ReactNativeRestorationBackendProvider } from './react-native-restoration.js';
|
|
4
4
|
export declare const REACT_NATIVE_APPLE_BACKEND_ID = "unified-ble:react-native-apple";
|
|
5
5
|
export declare const REACT_NATIVE_APPLE_PLATFORM_ID = "unified-ble:apple-corebluetooth";
|
|
6
|
-
export declare const REACT_NATIVE_APPLE_IMPLEMENTATION_VERSION = "4.0.
|
|
6
|
+
export declare const REACT_NATIVE_APPLE_IMPLEMENTATION_VERSION = "4.0.28";
|
|
7
7
|
export declare const REACT_NATIVE_APPLE_DEFAULT_ADAPTER_NATIVE_ID = "apple-corebluetooth-default-adapter";
|
|
8
8
|
export declare const reactNativeAppleCompatibility: NativeCompatibilityOffer;
|
|
9
9
|
export interface ReactNativeAppleBackendProviderOptions {
|
|
@@ -3,7 +3,7 @@ import { type BackendCompatibilityOffer } from '../../backend-contract/primitive
|
|
|
3
3
|
import { type WinRtAdapterRecord, type WinRtBoundary } from './winrt-boundary.js';
|
|
4
4
|
export declare const WINRT_BACKEND_ID = "unified-ble:winrt";
|
|
5
5
|
export declare const WINRT_PLATFORM_ID = "unified-ble:windows-winrt";
|
|
6
|
-
export declare const WINRT_IMPLEMENTATION_VERSION = "4.0.
|
|
6
|
+
export declare const WINRT_IMPLEMENTATION_VERSION = "4.0.28";
|
|
7
7
|
export declare const winRtCompatibility: BackendCompatibilityOffer;
|
|
8
8
|
export interface WinRtBackendProviderOptions {
|
|
9
9
|
readonly boundaryFactory: () => WinRtBoundary;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** The one production version stamped into every first-party backend identity. */
|
|
2
|
-
export declare const UNIFIED_BLE_IMPLEMENTATION_VERSION = "4.0.
|
|
2
|
+
export declare const UNIFIED_BLE_IMPLEMENTATION_VERSION = "4.0.28";
|
|
3
3
|
//# sourceMappingURL=implementation-version.d.ts.map
|
package/native/PREBUILDS.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"package": "unified-ble-manager@4.0.
|
|
3
|
+
"package": "unified-ble-manager@4.0.28",
|
|
4
4
|
"nodeApiVersion": 8,
|
|
5
5
|
"entries": [
|
|
6
6
|
{
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"nodeApiVersion": 8,
|
|
11
11
|
"path": "native/electron/corebluetooth/prebuilds/darwin-arm64/unified_ble_corebluetooth.node",
|
|
12
12
|
"bytes": 334128,
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "02d7a3fa8512799456f97a548803f0342a5974db94e5ff386b90dd3d0f52f4f6"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"backend": "corebluetooth",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"nodeApiVersion": 8,
|
|
20
20
|
"path": "native/electron/corebluetooth/prebuilds/darwin-x64/unified_ble_corebluetooth.node",
|
|
21
21
|
"bytes": 324296,
|
|
22
|
-
"sha256": "
|
|
22
|
+
"sha256": "5d58f6b13a8f528daf2a2aed8050199e7d81f7dfc377762f1136601068961ff7"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"backend": "winrt",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"nodeApiVersion": 8,
|
|
29
29
|
"path": "native/electron/winrt/prebuilds/win32-arm64/unified_ble_winrt.node",
|
|
30
30
|
"bytes": 646144,
|
|
31
|
-
"sha256": "
|
|
31
|
+
"sha256": "b7fb722bb9bb0cfc8aacbe27f9d5cc319f83563572173bae6a6a825c6cb58cf3"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"backend": "winrt",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"nodeApiVersion": 8,
|
|
38
38
|
"path": "native/electron/winrt/prebuilds/win32-x64/unified_ble_winrt.node",
|
|
39
39
|
"bytes": 616448,
|
|
40
|
-
"sha256": "
|
|
40
|
+
"sha256": "fb2775834392cbbb55c666dc5e90d2b2e8dc9242782a3153c797dca5fb05ea8f"
|
|
41
41
|
}
|
|
42
42
|
]
|
|
43
43
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -32,7 +32,7 @@ const MAX_CORRELATIONS: usize = 256;
|
|
|
32
32
|
const COMPLETED_CORRELATION_TTL: Duration = Duration::from_secs(30);
|
|
33
33
|
const MAX_QUARANTINE_WORKERS: usize = 4;
|
|
34
34
|
const MAX_QUARANTINE_ATTEMPTS: u32 = 8;
|
|
35
|
-
const SCAN_POLL_INTERVAL: Duration = Duration::
|
|
35
|
+
const SCAN_POLL_INTERVAL: Duration = Duration::from_secs(2);
|
|
36
36
|
/// Safety bound, not host policy.
|
|
37
37
|
///
|
|
38
38
|
/// btleplug's CoreBluetooth `disconnect()` never resolves when the peripheral
|
|
@@ -1189,7 +1189,7 @@ impl BtleplugDispatcher {
|
|
|
1189
1189
|
if started_tx.send(Ok(())).is_err() {
|
|
1190
1190
|
return;
|
|
1191
1191
|
}
|
|
1192
|
-
let mut interval =
|
|
1192
|
+
let mut interval = scan_poll_interval();
|
|
1193
1193
|
let mut events_open = true;
|
|
1194
1194
|
let mut polls: u32 = 0;
|
|
1195
1195
|
loop {
|
|
@@ -4227,6 +4227,12 @@ fn scan_event_peripheral_id(event: CentralEvent) -> Option<btleplug::platform::P
|
|
|
4227
4227
|
}
|
|
4228
4228
|
}
|
|
4229
4229
|
|
|
4230
|
+
fn scan_poll_interval() -> tokio::time::Interval {
|
|
4231
|
+
let mut interval = tokio::time::interval(SCAN_POLL_INTERVAL);
|
|
4232
|
+
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
|
|
4233
|
+
interval
|
|
4234
|
+
}
|
|
4235
|
+
|
|
4230
4236
|
fn scan_properties_match(
|
|
4231
4237
|
properties: &btleplug::api::PeripheralProperties,
|
|
4232
4238
|
requested_services: &[Uuid],
|
|
@@ -5010,7 +5016,7 @@ mod tests {
|
|
|
5010
5016
|
use super::error_confirms_device_released;
|
|
5011
5017
|
use super::{
|
|
5012
5018
|
characteristic_properties, disconnect_with_state_check, negotiate_ipc_versions, object,
|
|
5013
|
-
released, resolve_disconnect_failure, scan_properties_match_optional,
|
|
5019
|
+
released, resolve_disconnect_failure, scan_poll_interval, scan_properties_match_optional,
|
|
5014
5020
|
should_clear_peer_owner, string, BtleplugDispatcher, BtleplugDispatcherOptions,
|
|
5015
5021
|
CallerState, DispatchError, IpcEventSink, QuarantineScheduler,
|
|
5016
5022
|
DISCONNECT_COMPLETION_TIMEOUT,
|
|
@@ -5027,6 +5033,15 @@ mod tests {
|
|
|
5027
5033
|
);
|
|
5028
5034
|
}
|
|
5029
5035
|
|
|
5036
|
+
#[tokio::test]
|
|
5037
|
+
async fn scan_inventory_polling_is_paced_without_catch_up_bursts() {
|
|
5038
|
+
assert_eq!(super::SCAN_POLL_INTERVAL, std::time::Duration::from_secs(2));
|
|
5039
|
+
assert_eq!(
|
|
5040
|
+
scan_poll_interval().missed_tick_behavior(),
|
|
5041
|
+
tokio::time::MissedTickBehavior::Delay
|
|
5042
|
+
);
|
|
5043
|
+
}
|
|
5044
|
+
|
|
5030
5045
|
#[test]
|
|
5031
5046
|
fn native_dispatch_error_keeps_structured_platform_diagnostics_for_terminals() {
|
|
5032
5047
|
let error = DispatchError::new("platform.transport", "stream", "tauri.event-send")
|
package/package.json
CHANGED
|
@@ -29,6 +29,7 @@ Pod::Spec.new do |s|
|
|
|
29
29
|
"ios/Owned/OwnedCoreBluetoothProtocolRadioDescriptors.swift",
|
|
30
30
|
"ios/Owned/OwnedCoreBluetoothProtocolRadio.swift",
|
|
31
31
|
"ios/Owned/OwnedCoreBluetoothProtocolRadioCancellation.swift",
|
|
32
|
+
"ios/Owned/OwnedCoreBluetoothProtocolRadioOwner.swift",
|
|
32
33
|
"ios/Owned/OwnedCoreBluetoothProtocolRadioSupport.swift",
|
|
33
34
|
"native/protocol/src/**/*.cpp"
|
|
34
35
|
]
|