@onekeyfe/react-native-device-utils 3.0.63 → 3.0.65

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.
@@ -907,6 +907,13 @@ class ReactNativeDeviceUtils : HybridReactNativeDeviceUtilsSpec(), LifecycleEven
907
907
  }
908
908
  }
909
909
 
910
+ // iOS-only: cold-start LOCAL notification deep-link payload. Android delivers
911
+ // notification taps through the launching Intent's extras, a separate path,
912
+ // so there is nothing to hand back here.
913
+ override fun getAndClearColdStartLocalNotification(): Promise<String> {
914
+ return Promise.resolved("")
915
+ }
916
+
910
917
  // MARK: - ExitModule
911
918
 
912
919
  override fun exitApp() {
@@ -1,6 +1,7 @@
1
1
  import NitroModules
2
2
  import UIKit
3
3
  import ReactNativeNativeLogger
4
+ import os
4
5
 
5
6
  @objcMembers
6
7
  public class LaunchOptionsStore: NSObject {
@@ -21,8 +22,38 @@ public class LaunchOptionsStore: NSObject {
21
22
  public var deviceToken: Data?
22
23
  public var startupTime: TimeInterval = 0
23
24
 
25
+ // Cold-start deep-link: the JSON `userInfo` of a LOCAL notification the user
26
+ // tapped to launch the (killed) app. The legacy `NotificationCenter` broadcast
27
+ // in AppDelegate is fire-and-forget and is lost on cold start because JS has
28
+ // not registered a listener yet; this slot is a pull buffer JS drains once it
29
+ // boots. In-memory ONLY (no NSUserDefaults): a new process = fresh `nil`, so
30
+ // it is naturally launch-scoped and cannot replay a stale tap on a later
31
+ // unrelated cold start. AppDelegate writes it via KVC
32
+ // (`setValue(_:forKey:"coldStartLocalNotification")`), same bridge as the
33
+ // properties above.
34
+ public var coldStartLocalNotification: String?
35
+
24
36
  private static let deviceTokenKey = "1k_device_token"
25
37
 
38
+ // Serializes access to `coldStartLocalNotification`. The getter resolves on a
39
+ // nitro background thread (Promise.async) while AppDelegate writes the slot on
40
+ // the main thread during launch, so the read-and-clear below must be one
41
+ // critical section to avoid a double-drain race (delivering the deep-link
42
+ // twice) and memory-visibility issues. NOTE: AppDelegate writes via KVC
43
+ // (`setValue(_:forKey:)`), which bypasses this lock, so we cannot fully
44
+ // synchronize the writer from here — we protect the take side as best we can.
45
+ private var coldStartLock = os_unfair_lock()
46
+
47
+ // Read-once: hand the payload to JS exactly once per launch. The read+clear is
48
+ // performed atomically under `coldStartLock`.
49
+ public func takeColdStartLocalNotification() -> String {
50
+ os_unfair_lock_lock(&coldStartLock)
51
+ defer { os_unfair_lock_unlock(&coldStartLock) }
52
+ let value = coldStartLocalNotification ?? ""
53
+ coldStartLocalNotification = nil
54
+ return value
55
+ }
56
+
26
57
  public func getDeviceTokenString() -> String {
27
58
  // Prefer the JS-saved token (persisted across launches)
28
59
  if let saved = UserDefaults.standard.string(forKey: LaunchOptionsStore.deviceTokenKey), !saved.isEmpty {
@@ -189,6 +220,15 @@ class ReactNativeDeviceUtils: HybridReactNativeDeviceUtilsSpec {
189
220
  }
190
221
  }
191
222
 
223
+ func getAndClearColdStartLocalNotification() throws -> Promise<String> {
224
+ return Promise.async {
225
+ let value = LaunchOptionsStore.shared.takeColdStartLocalNotification()
226
+ // Presence only — never log the payload (it's a deep-link target / PII).
227
+ OneKeyLog.info("DeviceUtils", "getAndClearColdStartLocalNotification: hasPayload=\(!value.isEmpty)")
228
+ return value
229
+ }
230
+ }
231
+
192
232
  // MARK: - ExitModule
193
233
 
194
234
  func exitApp() throws {
@@ -40,6 +40,7 @@ export interface ReactNativeDeviceUtils extends HybridObject<{
40
40
  saveDeviceToken(token: string): Promise<void>;
41
41
  registerDeviceToken(): Promise<boolean>;
42
42
  getStartupTime(): Promise<number>;
43
+ getAndClearColdStartLocalNotification(): Promise<string>;
43
44
  exitApp(): void;
44
45
  getCurrentWebViewPackageInfo(): Promise<WebViewPackageInfo>;
45
46
  isGooglePlayServicesAvailable(): Promise<GooglePlayServicesStatus>;
@@ -244,6 +244,22 @@ namespace margelo::nitro::reactnativedeviceutils {
244
244
  return __promise;
245
245
  }();
246
246
  }
247
+ std::shared_ptr<Promise<std::string>> JHybridReactNativeDeviceUtilsSpec::getAndClearColdStartLocalNotification() {
248
+ static const auto method = javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("getAndClearColdStartLocalNotification");
249
+ auto __result = method(_javaPart);
250
+ return [&]() {
251
+ auto __promise = Promise<std::string>::create();
252
+ __result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
253
+ auto __result = jni::static_ref_cast<jni::JString>(__boxedResult);
254
+ __promise->resolve(__result->toStdString());
255
+ });
256
+ __result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
257
+ jni::JniException __jniError(__throwable);
258
+ __promise->reject(std::make_exception_ptr(__jniError));
259
+ });
260
+ return __promise;
261
+ }();
262
+ }
247
263
  void JHybridReactNativeDeviceUtilsSpec::exitApp() {
248
264
  static const auto method = javaClassStatic()->getMethod<void()>("exitApp");
249
265
  method(_javaPart);
@@ -69,6 +69,7 @@ namespace margelo::nitro::reactnativedeviceutils {
69
69
  std::shared_ptr<Promise<void>> saveDeviceToken(const std::string& token) override;
70
70
  std::shared_ptr<Promise<bool>> registerDeviceToken() override;
71
71
  std::shared_ptr<Promise<double>> getStartupTime() override;
72
+ std::shared_ptr<Promise<std::string>> getAndClearColdStartLocalNotification() override;
72
73
  void exitApp() override;
73
74
  std::shared_ptr<Promise<WebViewPackageInfo>> getCurrentWebViewPackageInfo() override;
74
75
  std::shared_ptr<Promise<GooglePlayServicesStatus>> isGooglePlayServicesAvailable() override;
@@ -111,6 +111,10 @@ abstract class HybridReactNativeDeviceUtilsSpec: HybridObject() {
111
111
  @Keep
112
112
  abstract fun getStartupTime(): Promise<Double>
113
113
 
114
+ @DoNotStrip
115
+ @Keep
116
+ abstract fun getAndClearColdStartLocalNotification(): Promise<String>
117
+
114
118
  @DoNotStrip
115
119
  @Keep
116
120
  abstract fun exitApp(): Unit
@@ -196,6 +196,14 @@ namespace margelo::nitro::reactnativedeviceutils {
196
196
  auto __value = std::move(__result.value());
197
197
  return __value;
198
198
  }
199
+ inline std::shared_ptr<Promise<std::string>> getAndClearColdStartLocalNotification() override {
200
+ auto __result = _swiftPart.getAndClearColdStartLocalNotification();
201
+ if (__result.hasError()) [[unlikely]] {
202
+ std::rethrow_exception(__result.error());
203
+ }
204
+ auto __value = std::move(__result.value());
205
+ return __value;
206
+ }
199
207
  inline void exitApp() override {
200
208
  auto __result = _swiftPart.exitApp();
201
209
  if (__result.hasError()) [[unlikely]] {
@@ -29,6 +29,7 @@ public protocol HybridReactNativeDeviceUtilsSpec_protocol: HybridObject {
29
29
  func saveDeviceToken(token: String) throws -> Promise<Void>
30
30
  func registerDeviceToken() throws -> Promise<Bool>
31
31
  func getStartupTime() throws -> Promise<Double>
32
+ func getAndClearColdStartLocalNotification() throws -> Promise<String>
32
33
  func exitApp() throws -> Void
33
34
  func getCurrentWebViewPackageInfo() throws -> Promise<WebViewPackageInfo>
34
35
  func isGooglePlayServicesAvailable() throws -> Promise<GooglePlayServicesStatus>
@@ -360,6 +360,25 @@ open class HybridReactNativeDeviceUtilsSpec_cxx {
360
360
  }
361
361
  }
362
362
 
363
+ @inline(__always)
364
+ public final func getAndClearColdStartLocalNotification() -> bridge.Result_std__shared_ptr_Promise_std__string___ {
365
+ do {
366
+ let __result = try self.__implementation.getAndClearColdStartLocalNotification()
367
+ let __resultCpp = { () -> bridge.std__shared_ptr_Promise_std__string__ in
368
+ let __promise = bridge.create_std__shared_ptr_Promise_std__string__()
369
+ let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__string__(__promise)
370
+ __result
371
+ .then({ __result in __promiseHolder.resolve(std.string(__result)) })
372
+ .catch({ __error in __promiseHolder.reject(__error.toCpp()) })
373
+ return __promise
374
+ }()
375
+ return bridge.create_Result_std__shared_ptr_Promise_std__string___(__resultCpp)
376
+ } catch (let __error) {
377
+ let __exceptionPtr = __error.toCpp()
378
+ return bridge.create_Result_std__shared_ptr_Promise_std__string___(__exceptionPtr)
379
+ }
380
+ }
381
+
363
382
  @inline(__always)
364
383
  public final func exitApp() -> bridge.Result_void_ {
365
384
  do {
@@ -29,6 +29,7 @@ namespace margelo::nitro::reactnativedeviceutils {
29
29
  prototype.registerHybridMethod("saveDeviceToken", &HybridReactNativeDeviceUtilsSpec::saveDeviceToken);
30
30
  prototype.registerHybridMethod("registerDeviceToken", &HybridReactNativeDeviceUtilsSpec::registerDeviceToken);
31
31
  prototype.registerHybridMethod("getStartupTime", &HybridReactNativeDeviceUtilsSpec::getStartupTime);
32
+ prototype.registerHybridMethod("getAndClearColdStartLocalNotification", &HybridReactNativeDeviceUtilsSpec::getAndClearColdStartLocalNotification);
32
33
  prototype.registerHybridMethod("exitApp", &HybridReactNativeDeviceUtilsSpec::exitApp);
33
34
  prototype.registerHybridMethod("getCurrentWebViewPackageInfo", &HybridReactNativeDeviceUtilsSpec::getCurrentWebViewPackageInfo);
34
35
  prototype.registerHybridMethod("isGooglePlayServicesAvailable", &HybridReactNativeDeviceUtilsSpec::isGooglePlayServicesAvailable);
@@ -86,6 +86,7 @@ namespace margelo::nitro::reactnativedeviceutils {
86
86
  virtual std::shared_ptr<Promise<void>> saveDeviceToken(const std::string& token) = 0;
87
87
  virtual std::shared_ptr<Promise<bool>> registerDeviceToken() = 0;
88
88
  virtual std::shared_ptr<Promise<double>> getStartupTime() = 0;
89
+ virtual std::shared_ptr<Promise<std::string>> getAndClearColdStartLocalNotification() = 0;
89
90
  virtual void exitApp() = 0;
90
91
  virtual std::shared_ptr<Promise<WebViewPackageInfo>> getCurrentWebViewPackageInfo() = 0;
91
92
  virtual std::shared_ptr<Promise<GooglePlayServicesStatus>> isGooglePlayServicesAvailable() = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-device-utils",
3
- "version": "3.0.63",
3
+ "version": "3.0.65",
4
4
  "description": "react-native-device-utils",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -59,6 +59,10 @@ export interface ReactNativeDeviceUtils
59
59
  saveDeviceToken(token: string): Promise<void>;
60
60
  registerDeviceToken(): Promise<boolean>;
61
61
  getStartupTime(): Promise<number>;
62
+ // Returns the JSON userInfo of a LOCAL notification the user tapped to launch
63
+ // the (killed) app, then clears it so it is delivered exactly once. Empty
64
+ // string when there is none. iOS-only meaningful; Android returns "".
65
+ getAndClearColdStartLocalNotification(): Promise<string>;
62
66
 
63
67
  // ExitModule
64
68
  exitApp(): void;