@onekeyfe/react-native-device-utils 3.0.177 → 3.0.178

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.
Files changed (23) hide show
  1. package/README.md +45 -0
  2. package/android/src/main/java/com/margelo/nitro/reactnativedeviceutils/InMemoryStore.kt +54 -0
  3. package/android/src/main/java/com/margelo/nitro/reactnativedeviceutils/ReactNativeDeviceUtils.kt +9 -0
  4. package/ios/InMemoryStore.swift +70 -0
  5. package/ios/ReactNativeDeviceUtils.swift +18 -0
  6. package/lib/typescript/src/ReactNativeDeviceUtils.nitro.d.ts +5 -0
  7. package/nitrogen/generated/android/c++/JHybridReactNativeDeviceUtilsSpec.cpp +21 -0
  8. package/nitrogen/generated/android/c++/JHybridReactNativeDeviceUtilsSpec.hpp +4 -0
  9. package/nitrogen/generated/android/c++/JInMemoryValue.cpp +30 -0
  10. package/nitrogen/generated/android/c++/JInMemoryValue.hpp +83 -0
  11. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativedeviceutils/HybridReactNativeDeviceUtilsSpec.kt +16 -0
  12. package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativedeviceutils/InMemoryValue.kt +75 -0
  13. package/nitrogen/generated/android/reactnativedeviceutils+autolinking.cmake +1 -0
  14. package/nitrogen/generated/ios/ReactNativeDeviceUtils-Swift-Cxx-Bridge.hpp +60 -0
  15. package/nitrogen/generated/ios/ReactNativeDeviceUtils-Swift-Cxx-Umbrella.hpp +1 -0
  16. package/nitrogen/generated/ios/c++/HybridReactNativeDeviceUtilsSpecSwift.hpp +31 -0
  17. package/nitrogen/generated/ios/swift/HybridReactNativeDeviceUtilsSpec.swift +4 -0
  18. package/nitrogen/generated/ios/swift/HybridReactNativeDeviceUtilsSpec_cxx.swift +92 -0
  19. package/nitrogen/generated/ios/swift/InMemoryValue.swift +32 -0
  20. package/nitrogen/generated/shared/c++/HybridReactNativeDeviceUtilsSpec.cpp +4 -0
  21. package/nitrogen/generated/shared/c++/HybridReactNativeDeviceUtilsSpec.hpp +6 -0
  22. package/package.json +1 -1
  23. package/src/ReactNativeDeviceUtils.nitro.ts +7 -0
package/README.md CHANGED
@@ -45,6 +45,51 @@ cross-platform guarantee that a service or hardware feature is available.
45
45
 
46
46
  See [src/ReactNativeDeviceUtils.nitro.ts](src/ReactNativeDeviceUtils.nitro.ts)
47
47
  for the complete signatures, enum values and platform notes.
48
+ See [docs/SPEC.md](docs/SPEC.md) for the InMemoryStore contract and acceptance status.
49
+
50
+ ## In-memory store
51
+
52
+ `ReactNativeDeviceUtils` exposes synchronous Android/iOS methods:
53
+
54
+ ```ts
55
+ type InMemoryValue = string | boolean | number;
56
+
57
+ getInMemoryValue(key: string): InMemoryValue | undefined;
58
+ setInMemoryValue(key: string, value: InMemoryValue): void;
59
+ removeInMemoryValue(key: string): boolean;
60
+ setInMemoryValueIfAbsent(key: string, value: InMemoryValue): boolean;
61
+ ```
62
+
63
+ Values are strings (including empty strings), booleans, or numbers. Reads preserve
64
+ the original type; false and 0 are stored values rather than missing keys. Numbers
65
+ use IEEE-754 doubles, including negative zero, NaN, and infinities. Objects, arrays,
66
+ null, and undefined are not supported. `setInMemoryValueIfAbsent` inserts
67
+ only when the key is missing and returns whether it inserted. All operations use
68
+ the same native lock. A module recreation, JS reload, or main/background runtime
69
+ recreation retains the same native Map. Process exit discards it. No data is
70
+ persisted, and there is no implicit reset on React lifecycle events.
71
+
72
+ Keys use exact UTF-8 identity, without Unicode normalization. The store holds at
73
+ most 128 entries; keys are limited to 256 UTF-8 bytes and string values to 4096
74
+ bytes. Boolean and number payloads are fixed size.
75
+ Overlong arguments or a new key at capacity throw synchronously without changing
76
+ the Map. Existing keys can still be replaced or removed; no entry is evicted.
77
+ Both write methods validate their arguments even when the key already exists.
78
+
79
+ Use namespaced keys. For startup reporting, only main UI may claim
80
+ `analytics:startup:jsReadyTime` or `analytics:startup:uiVisibleTime`. Claim and
81
+ enqueue synchronously; remove the key if local enqueue throws. Keep the key after
82
+ enqueue succeeds; network delivery remains the existing analytics path's job.
83
+ A pending JS logger queue can still lose entries on runtime loss or later queue
84
+ errors; acceptance into that queue does not guarantee delivery.
85
+
86
+ This API requires a rebuilt native host containing the updated module. It is not
87
+ an OTA-only change. Desktop/web/extension are not implemented by this package.
88
+
89
+ After `yarn nitrogen`, run `node tests/in-memory-store.cjs` from this package to
90
+ compile the production Swift/Kotlin stores with the generated primitive union,
91
+ exercise type preservation, concurrent claims and independent keys, and run each
92
+ executable in two fresh processes. Requires Swift, Kotlin, and Java.
48
93
 
49
94
  ## License
50
95
 
@@ -0,0 +1,54 @@
1
+ package com.margelo.nitro.reactnativedeviceutils
2
+
3
+ // Process-owned storage, independent of HybridObjects and React runtimes.
4
+ internal object InMemoryStore {
5
+ private const val MAX_ENTRIES = 128
6
+ private const val MAX_KEY_BYTES = 256
7
+ private const val MAX_VALUE_BYTES = 4096
8
+ private val values = mutableMapOf<String, InMemoryValue>()
9
+
10
+ private fun validateKey(key: String) {
11
+ require(key.length <= MAX_KEY_BYTES && key.toByteArray(Charsets.UTF_8).size <= MAX_KEY_BYTES) {
12
+ "InMemoryStore key exceeds 256 UTF-8 bytes"
13
+ }
14
+ }
15
+
16
+ private fun validateValue(value: InMemoryValue) {
17
+ val string = value.asSecondOrNull() ?: return
18
+ require(string.length <= MAX_VALUE_BYTES && string.toByteArray(Charsets.UTF_8).size <= MAX_VALUE_BYTES) {
19
+ "InMemoryStore value exceeds 4096 UTF-8 bytes"
20
+ }
21
+ }
22
+
23
+ @Synchronized
24
+ fun get(key: String): InMemoryValue? {
25
+ validateKey(key)
26
+ return values[key]
27
+ }
28
+
29
+ @Synchronized
30
+ fun set(key: String, value: InMemoryValue) {
31
+ validateKey(key)
32
+ validateValue(value)
33
+ check(values.containsKey(key) || values.size < MAX_ENTRIES) {
34
+ "InMemoryStore capacity exceeds 128 entries"
35
+ }
36
+ values[key] = value
37
+ }
38
+
39
+ @Synchronized
40
+ fun remove(key: String): Boolean {
41
+ validateKey(key)
42
+ return values.remove(key) != null
43
+ }
44
+
45
+ @Synchronized
46
+ fun setIfAbsent(key: String, value: InMemoryValue): Boolean {
47
+ validateKey(key)
48
+ validateValue(value)
49
+ if (values.containsKey(key)) return false
50
+ check(values.size < MAX_ENTRIES) { "InMemoryStore capacity exceeds 128 entries" }
51
+ values[key] = value
52
+ return true
53
+ }
54
+ }
@@ -43,6 +43,15 @@ private data class NavigationBarAppearance(
43
43
  @DoNotStrip
44
44
  class ReactNativeDeviceUtils : HybridReactNativeDeviceUtilsSpec(), LifecycleEventListener {
45
45
 
46
+ override fun getInMemoryValue(key: String): InMemoryValue? = InMemoryStore.get(key)
47
+
48
+ override fun setInMemoryValue(key: String, value: InMemoryValue) = InMemoryStore.set(key, value)
49
+
50
+ override fun removeInMemoryValue(key: String): Boolean = InMemoryStore.remove(key)
51
+
52
+ override fun setInMemoryValueIfAbsent(key: String, value: InMemoryValue): Boolean =
53
+ InMemoryStore.setIfAbsent(key, value)
54
+
46
55
  /**
47
56
  * Foldable device model constants for various manufacturers.
48
57
  * Reference: https://storage.googleapis.com/play_public/supported_devices.html
@@ -0,0 +1,70 @@
1
+ import Foundation
2
+
3
+ // The singleton outlives HybridObjects and React runtimes. Only process exit
4
+ // clears it; no value holds a JS object or writes to persistent storage.
5
+ final class InMemoryStore {
6
+ static let shared = InMemoryStore()
7
+ private static let maxEntries = 128
8
+ private static let maxKeyBytes = 256
9
+ private static let maxValueBytes = 4096
10
+ private let lock = NSLock()
11
+ // Swift String equality normalizes Unicode; Data preserves exact key bytes.
12
+ private var values: [Data: InMemoryValue] = [:]
13
+
14
+ private init() {}
15
+
16
+ private func keyData(_ key: String) throws -> Data {
17
+ guard key.utf8.prefix(Self.maxKeyBytes + 1).count <= Self.maxKeyBytes else {
18
+ throw budgetError("InMemoryStore key exceeds 256 UTF-8 bytes")
19
+ }
20
+ return Data(key.utf8)
21
+ }
22
+
23
+ private func validateValue(_ value: InMemoryValue) throws {
24
+ guard case .second(let string) = value else { return }
25
+ guard string.utf8.prefix(Self.maxValueBytes + 1).count <= Self.maxValueBytes else {
26
+ throw budgetError("InMemoryStore value exceeds 4096 UTF-8 bytes")
27
+ }
28
+ }
29
+
30
+ private func budgetError(_ message: String) -> NSError {
31
+ return NSError(domain: "InMemoryStore", code: 1,
32
+ userInfo: [NSLocalizedDescriptionKey: message])
33
+ }
34
+
35
+ func get(_ key: String) throws -> InMemoryValue? {
36
+ lock.lock()
37
+ defer { lock.unlock() }
38
+ return values[try keyData(key)]
39
+ }
40
+
41
+ func set(_ key: String, _ value: InMemoryValue) throws {
42
+ lock.lock()
43
+ defer { lock.unlock() }
44
+ let data = try keyData(key)
45
+ try validateValue(value)
46
+ guard values[data] != nil || values.count < Self.maxEntries else {
47
+ throw budgetError("InMemoryStore capacity exceeds 128 entries")
48
+ }
49
+ values[data] = value
50
+ }
51
+
52
+ func remove(_ key: String) throws -> Bool {
53
+ lock.lock()
54
+ defer { lock.unlock() }
55
+ return values.removeValue(forKey: try keyData(key)) != nil
56
+ }
57
+
58
+ func setIfAbsent(_ key: String, _ value: InMemoryValue) throws -> Bool {
59
+ lock.lock()
60
+ defer { lock.unlock() }
61
+ let data = try keyData(key)
62
+ try validateValue(value)
63
+ guard values[data] == nil else { return false }
64
+ guard values.count < Self.maxEntries else {
65
+ throw budgetError("InMemoryStore capacity exceeds 128 entries")
66
+ }
67
+ values[data] = value
68
+ return true
69
+ }
70
+ }
@@ -173,6 +173,24 @@ class ReactNativeDeviceUtils: HybridReactNativeDeviceUtilsSpec {
173
173
  // Android-only system UI.
174
174
  }
175
175
 
176
+ // MARK: - In-memory store
177
+
178
+ func getInMemoryValue(key: String) throws -> InMemoryValue? {
179
+ return try InMemoryStore.shared.get(key)
180
+ }
181
+
182
+ func setInMemoryValue(key: String, value: InMemoryValue) throws {
183
+ try InMemoryStore.shared.set(key, value)
184
+ }
185
+
186
+ func removeInMemoryValue(key: String) throws -> Bool {
187
+ return try InMemoryStore.shared.remove(key)
188
+ }
189
+
190
+ func setInMemoryValueIfAbsent(key: String, value: InMemoryValue) throws -> Bool {
191
+ return try InMemoryStore.shared.setIfAbsent(key, value)
192
+ }
193
+
176
194
  // MARK: - LaunchOptionsManager
177
195
 
178
196
  func getLaunchOptions() throws -> Promise<LaunchOptions> {
@@ -1,4 +1,5 @@
1
1
  import type { HybridObject } from 'react-native-nitro-modules';
2
+ export type InMemoryValue = string | boolean | number;
2
3
  export type UserInterfaceStyle = 'light' | 'dark' | 'unspecified';
3
4
  export type AndroidChannel = 'direct' | 'google' | 'huawei' | 'unknown';
4
5
  export type InstallerPackageName = 'appStore' | 'testFlight' | 'other' | 'playStore' | 'huaweiAppGallery' | 'unknown';
@@ -48,6 +49,10 @@ export interface ReactNativeDeviceUtils extends HybridObject<{
48
49
  saveDeviceToken(token: string): Promise<void>;
49
50
  registerDeviceToken(): Promise<boolean>;
50
51
  getStartupTime(): Promise<number>;
52
+ getInMemoryValue(key: string): InMemoryValue | undefined;
53
+ setInMemoryValue(key: string, value: InMemoryValue): void;
54
+ removeInMemoryValue(key: string): boolean;
55
+ setInMemoryValueIfAbsent(key: string, value: InMemoryValue): boolean;
51
56
  getAndClearColdStartLocalNotification(): Promise<string>;
52
57
  exitApp(): void;
53
58
  getCurrentWebViewPackageInfo(): Promise<WebViewPackageInfo>;
@@ -32,6 +32,8 @@ namespace margelo::nitro::reactnativedeviceutils { enum class UserInterfaceStyle
32
32
  #include <string>
33
33
  #include <optional>
34
34
  #include <NitroModules/JUnit.hpp>
35
+ #include <variant>
36
+ #include "JInMemoryValue.hpp"
35
37
  #include "WebViewPackageInfo.hpp"
36
38
  #include "JWebViewPackageInfo.hpp"
37
39
  #include "GooglePlayServicesStatus.hpp"
@@ -250,6 +252,25 @@ namespace margelo::nitro::reactnativedeviceutils {
250
252
  return __promise;
251
253
  }();
252
254
  }
255
+ std::optional<std::variant<bool, std::string, double>> JHybridReactNativeDeviceUtilsSpec::getInMemoryValue(const std::string& key) {
256
+ static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JInMemoryValue>(jni::alias_ref<jni::JString> /* key */)>("getInMemoryValue");
257
+ auto __result = method(_javaPart, jni::make_jstring(key));
258
+ return __result != nullptr ? std::make_optional(__result->toCpp()) : std::nullopt;
259
+ }
260
+ void JHybridReactNativeDeviceUtilsSpec::setInMemoryValue(const std::string& key, const std::variant<bool, std::string, double>& value) {
261
+ static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* key */, jni::alias_ref<JInMemoryValue> /* value */)>("setInMemoryValue");
262
+ method(_javaPart, jni::make_jstring(key), JInMemoryValue::fromCpp(value));
263
+ }
264
+ bool JHybridReactNativeDeviceUtilsSpec::removeInMemoryValue(const std::string& key) {
265
+ static const auto method = _javaPart->javaClassStatic()->getMethod<jboolean(jni::alias_ref<jni::JString> /* key */)>("removeInMemoryValue");
266
+ auto __result = method(_javaPart, jni::make_jstring(key));
267
+ return static_cast<bool>(__result);
268
+ }
269
+ bool JHybridReactNativeDeviceUtilsSpec::setInMemoryValueIfAbsent(const std::string& key, const std::variant<bool, std::string, double>& value) {
270
+ static const auto method = _javaPart->javaClassStatic()->getMethod<jboolean(jni::alias_ref<jni::JString> /* key */, jni::alias_ref<JInMemoryValue> /* value */)>("setInMemoryValueIfAbsent");
271
+ auto __result = method(_javaPart, jni::make_jstring(key), JInMemoryValue::fromCpp(value));
272
+ return static_cast<bool>(__result);
273
+ }
253
274
  std::shared_ptr<Promise<std::string>> JHybridReactNativeDeviceUtilsSpec::getAndClearColdStartLocalNotification() {
254
275
  static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("getAndClearColdStartLocalNotification");
255
276
  auto __result = method(_javaPart);
@@ -70,6 +70,10 @@ namespace margelo::nitro::reactnativedeviceutils {
70
70
  std::shared_ptr<Promise<void>> saveDeviceToken(const std::string& token) override;
71
71
  std::shared_ptr<Promise<bool>> registerDeviceToken() override;
72
72
  std::shared_ptr<Promise<double>> getStartupTime() override;
73
+ std::optional<std::variant<bool, std::string, double>> getInMemoryValue(const std::string& key) override;
74
+ void setInMemoryValue(const std::string& key, const std::variant<bool, std::string, double>& value) override;
75
+ bool removeInMemoryValue(const std::string& key) override;
76
+ bool setInMemoryValueIfAbsent(const std::string& key, const std::variant<bool, std::string, double>& value) override;
73
77
  std::shared_ptr<Promise<std::string>> getAndClearColdStartLocalNotification() override;
74
78
  void exitApp() override;
75
79
  std::shared_ptr<Promise<WebViewPackageInfo>> getCurrentWebViewPackageInfo() override;
@@ -0,0 +1,30 @@
1
+ ///
2
+ /// JInMemoryValue.cpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #include "JInMemoryValue.hpp"
9
+
10
+ namespace margelo::nitro::reactnativedeviceutils {
11
+ /**
12
+ * Converts JInMemoryValue to std::variant<bool, std::string, double>
13
+ */
14
+ std::variant<bool, std::string, double> JInMemoryValue::toCpp() const {
15
+ if (isInstanceOf(JInMemoryValue_impl::First::javaClassStatic())) {
16
+ // It's a `bool`
17
+ auto jniValue = static_cast<const JInMemoryValue_impl::First*>(this)->getValue();
18
+ return static_cast<bool>(jniValue);
19
+ } else if (isInstanceOf(JInMemoryValue_impl::Second::javaClassStatic())) {
20
+ // It's a `std::string`
21
+ auto jniValue = static_cast<const JInMemoryValue_impl::Second*>(this)->getValue();
22
+ return jniValue->toStdString();
23
+ } else if (isInstanceOf(JInMemoryValue_impl::Third::javaClassStatic())) {
24
+ // It's a `double`
25
+ auto jniValue = static_cast<const JInMemoryValue_impl::Third*>(this)->getValue();
26
+ return jniValue;
27
+ }
28
+ throw std::invalid_argument("Variant is unknown Kotlin instance!");
29
+ }
30
+ } // namespace margelo::nitro::reactnativedeviceutils
@@ -0,0 +1,83 @@
1
+ ///
2
+ /// JInMemoryValue.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #include <fbjni/fbjni.h>
11
+ #include <variant>
12
+
13
+ #include <string>
14
+ #include <variant>
15
+
16
+ namespace margelo::nitro::reactnativedeviceutils {
17
+
18
+ using namespace facebook;
19
+
20
+ /**
21
+ * The C++ JNI bridge between the C++ std::variant and the Java class "InMemoryValue".
22
+ */
23
+ class JInMemoryValue: public jni::JavaClass<JInMemoryValue> {
24
+ public:
25
+ static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/reactnativedeviceutils/InMemoryValue;";
26
+
27
+ static jni::local_ref<JInMemoryValue> create_0(jboolean value) {
28
+ static const auto method = javaClassStatic()->getStaticMethod<JInMemoryValue(jboolean)>("create");
29
+ return method(javaClassStatic(), value);
30
+ }
31
+ static jni::local_ref<JInMemoryValue> create_1(jni::alias_ref<jni::JString> value) {
32
+ static const auto method = javaClassStatic()->getStaticMethod<JInMemoryValue(jni::alias_ref<jni::JString>)>("create");
33
+ return method(javaClassStatic(), value);
34
+ }
35
+ static jni::local_ref<JInMemoryValue> create_2(double value) {
36
+ static const auto method = javaClassStatic()->getStaticMethod<JInMemoryValue(double)>("create");
37
+ return method(javaClassStatic(), value);
38
+ }
39
+
40
+ static jni::local_ref<JInMemoryValue> fromCpp(const std::variant<bool, std::string, double>& variant) {
41
+ switch (variant.index()) {
42
+ case 0: return create_0(std::get<0>(variant));
43
+ case 1: return create_1(jni::make_jstring(std::get<1>(variant)));
44
+ case 2: return create_2(std::get<2>(variant));
45
+ default: throw std::invalid_argument("Variant holds unknown index! (" + std::to_string(variant.index()) + ")");
46
+ }
47
+ }
48
+
49
+ [[nodiscard]] std::variant<bool, std::string, double> toCpp() const;
50
+ };
51
+
52
+ namespace JInMemoryValue_impl {
53
+ class First final: public jni::JavaClass<First, JInMemoryValue> {
54
+ public:
55
+ static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/reactnativedeviceutils/InMemoryValue$First;";
56
+
57
+ [[nodiscard]] jboolean getValue() const {
58
+ static const auto field = javaClassStatic()->getField<jboolean>("value");
59
+ return getFieldValue(field);
60
+ }
61
+ };
62
+
63
+ class Second final: public jni::JavaClass<Second, JInMemoryValue> {
64
+ public:
65
+ static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/reactnativedeviceutils/InMemoryValue$Second;";
66
+
67
+ [[nodiscard]] jni::local_ref<jni::JString> getValue() const {
68
+ static const auto field = javaClassStatic()->getField<jni::JString>("value");
69
+ return getFieldValue(field);
70
+ }
71
+ };
72
+
73
+ class Third final: public jni::JavaClass<Third, JInMemoryValue> {
74
+ public:
75
+ static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/reactnativedeviceutils/InMemoryValue$Third;";
76
+
77
+ [[nodiscard]] double getValue() const {
78
+ static const auto field = javaClassStatic()->getField<double>("value");
79
+ return getFieldValue(field);
80
+ }
81
+ };
82
+ } // namespace JInMemoryValue_impl
83
+ } // namespace margelo::nitro::reactnativedeviceutils
@@ -99,6 +99,22 @@ abstract class HybridReactNativeDeviceUtilsSpec: HybridObject() {
99
99
  @Keep
100
100
  abstract fun getStartupTime(): Promise<Double>
101
101
 
102
+ @DoNotStrip
103
+ @Keep
104
+ abstract fun getInMemoryValue(key: String): InMemoryValue?
105
+
106
+ @DoNotStrip
107
+ @Keep
108
+ abstract fun setInMemoryValue(key: String, value: InMemoryValue): Unit
109
+
110
+ @DoNotStrip
111
+ @Keep
112
+ abstract fun removeInMemoryValue(key: String): Boolean
113
+
114
+ @DoNotStrip
115
+ @Keep
116
+ abstract fun setInMemoryValueIfAbsent(key: String, value: InMemoryValue): Boolean
117
+
102
118
  @DoNotStrip
103
119
  @Keep
104
120
  abstract fun getAndClearColdStartLocalNotification(): Promise<String>
@@ -0,0 +1,75 @@
1
+ ///
2
+ /// InMemoryValue.kt
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ package com.margelo.nitro.reactnativedeviceutils
9
+
10
+ import com.facebook.proguard.annotations.DoNotStrip
11
+
12
+
13
+ /**
14
+ * Represents the TypeScript variant "Boolean | String | Double".
15
+ */
16
+ @Suppress("ClassName")
17
+ @DoNotStrip
18
+ sealed class InMemoryValue {
19
+ @DoNotStrip
20
+ data class First(@DoNotStrip val value: Boolean): InMemoryValue()
21
+ @DoNotStrip
22
+ data class Second(@DoNotStrip val value: String): InMemoryValue()
23
+ @DoNotStrip
24
+ data class Third(@DoNotStrip val value: Double): InMemoryValue()
25
+
26
+ inline fun <reified T> asType(): T? {
27
+ return when (this) {
28
+ is First -> (value) as? T
29
+ is Second -> (value) as? T
30
+ is Third -> (value) as? T
31
+ }
32
+ }
33
+ inline fun <reified T> isType(): Boolean {
34
+ return asType<T>() != null
35
+ }
36
+ inline fun <R> match(first: (Boolean) -> R, second: (String) -> R, third: (Double) -> R): R {
37
+ return when (this) {
38
+ is First -> first(value)
39
+ is Second -> second(value)
40
+ is Third -> third(value)
41
+ }
42
+ }
43
+
44
+ val isFirst: Boolean
45
+ get() = this is First
46
+ val isSecond: Boolean
47
+ get() = this is Second
48
+ val isThird: Boolean
49
+ get() = this is Third
50
+
51
+ fun asFirstOrNull(): Boolean? {
52
+ val value = (this as? First)?.value ?: return null
53
+ return value
54
+ }
55
+ fun asSecondOrNull(): String? {
56
+ val value = (this as? Second)?.value ?: return null
57
+ return value
58
+ }
59
+ fun asThirdOrNull(): Double? {
60
+ val value = (this as? Third)?.value ?: return null
61
+ return value
62
+ }
63
+
64
+ companion object {
65
+ @JvmStatic
66
+ @DoNotStrip
67
+ fun create(value: Boolean): InMemoryValue = First(value)
68
+ @JvmStatic
69
+ @DoNotStrip
70
+ fun create(value: String): InMemoryValue = Second(value)
71
+ @JvmStatic
72
+ @DoNotStrip
73
+ fun create(value: Double): InMemoryValue = Third(value)
74
+ }
75
+ }
@@ -36,6 +36,7 @@ target_sources(
36
36
  ../nitrogen/generated/shared/c++/HybridReactNativeDeviceUtilsSpec.cpp
37
37
  # Android-specific Nitrogen C++ sources
38
38
  ../nitrogen/generated/android/c++/JHybridReactNativeDeviceUtilsSpec.cpp
39
+ ../nitrogen/generated/android/c++/JInMemoryValue.cpp
39
40
  )
40
41
 
41
42
  # From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake
@@ -43,6 +43,7 @@ namespace ReactNativeDeviceUtils { class HybridReactNativeDeviceUtilsSpec_cxx; }
43
43
  #include <memory>
44
44
  #include <optional>
45
45
  #include <string>
46
+ #include <variant>
46
47
  #include <vector>
47
48
 
48
49
  /**
@@ -337,6 +338,56 @@ namespace margelo::nitro::reactnativedeviceutils::bridge::swift {
337
338
  return Func_void_double_Wrapper(std::move(value));
338
339
  }
339
340
 
341
+ // pragma MARK: std::variant<bool, std::string, double>
342
+ /**
343
+ * Wrapper struct for `std::variant<bool, std::string, double>`.
344
+ * std::variant cannot be used in Swift because of a Swift bug.
345
+ * Not even specializing it works. So we create a wrapper struct.
346
+ */
347
+ struct std__variant_bool__std__string__double_ final {
348
+ std::variant<bool, std::string, double> variant;
349
+ std__variant_bool__std__string__double_(std::variant<bool, std::string, double> variant): variant(variant) { }
350
+ operator std::variant<bool, std::string, double>() const noexcept {
351
+ return variant;
352
+ }
353
+ inline size_t index() const noexcept {
354
+ return variant.index();
355
+ }
356
+ inline bool get_0() const noexcept {
357
+ return std::get<0>(variant);
358
+ }
359
+ inline std::string get_1() const noexcept {
360
+ return std::get<1>(variant);
361
+ }
362
+ inline double get_2() const noexcept {
363
+ return std::get<2>(variant);
364
+ }
365
+ };
366
+ inline std__variant_bool__std__string__double_ create_std__variant_bool__std__string__double_(bool value) noexcept {
367
+ return std__variant_bool__std__string__double_(value);
368
+ }
369
+ inline std__variant_bool__std__string__double_ create_std__variant_bool__std__string__double_(const std::string& value) noexcept {
370
+ return std__variant_bool__std__string__double_(value);
371
+ }
372
+ inline std__variant_bool__std__string__double_ create_std__variant_bool__std__string__double_(double value) noexcept {
373
+ return std__variant_bool__std__string__double_(value);
374
+ }
375
+
376
+ // pragma MARK: std::optional<std::variant<bool, std::string, double>>
377
+ /**
378
+ * Specialized version of `std::optional<std::variant<bool, std::string, double>>`.
379
+ */
380
+ using std__optional_std__variant_bool__std__string__double__ = std::optional<std::variant<bool, std::string, double>>;
381
+ inline std::optional<std::variant<bool, std::string, double>> create_std__optional_std__variant_bool__std__string__double__(const std::variant<bool, std::string, double>& value) noexcept {
382
+ return std::optional<std::variant<bool, std::string, double>>(value);
383
+ }
384
+ inline bool has_value_std__optional_std__variant_bool__std__string__double__(const std::optional<std::variant<bool, std::string, double>>& optional) noexcept {
385
+ return optional.has_value();
386
+ }
387
+ inline std::variant<bool, std::string, double> get_std__optional_std__variant_bool__std__string__double__(const std::optional<std::variant<bool, std::string, double>>& optional) noexcept {
388
+ return optional.value();
389
+ }
390
+
340
391
  // pragma MARK: std::shared_ptr<Promise<WebViewPackageInfo>>
341
392
  /**
342
393
  * Specialized version of `std::shared_ptr<Promise<WebViewPackageInfo>>`.
@@ -507,6 +558,15 @@ namespace margelo::nitro::reactnativedeviceutils::bridge::swift {
507
558
  return Result<std::shared_ptr<Promise<double>>>::withError(error);
508
559
  }
509
560
 
561
+ // pragma MARK: Result<std::optional<std::variant<bool, std::string, double>>>
562
+ using Result_std__optional_std__variant_bool__std__string__double___ = Result<std::optional<std::variant<bool, std::string, double>>>;
563
+ inline Result_std__optional_std__variant_bool__std__string__double___ create_Result_std__optional_std__variant_bool__std__string__double___(const std::optional<std::variant<bool, std::string, double>>& value) noexcept {
564
+ return Result<std::optional<std::variant<bool, std::string, double>>>::withValue(value);
565
+ }
566
+ inline Result_std__optional_std__variant_bool__std__string__double___ create_Result_std__optional_std__variant_bool__std__string__double___(const std::exception_ptr& error) noexcept {
567
+ return Result<std::optional<std::variant<bool, std::string, double>>>::withError(error);
568
+ }
569
+
510
570
  // pragma MARK: Result<std::shared_ptr<Promise<WebViewPackageInfo>>>
511
571
  using Result_std__shared_ptr_Promise_WebViewPackageInfo___ = Result<std::shared_ptr<Promise<WebViewPackageInfo>>>;
512
572
  inline Result_std__shared_ptr_Promise_WebViewPackageInfo___ create_Result_std__shared_ptr_Promise_WebViewPackageInfo___(const std::shared_ptr<Promise<WebViewPackageInfo>>& value) noexcept {
@@ -41,6 +41,7 @@ namespace margelo::nitro::reactnativedeviceutils { struct WebViewPackageInfo; }
41
41
  #include <memory>
42
42
  #include <optional>
43
43
  #include <string>
44
+ #include <variant>
44
45
  #include <vector>
45
46
 
46
47
  // C++ helpers for Swift
@@ -35,6 +35,7 @@ namespace margelo::nitro::reactnativedeviceutils { enum class InstallerPackageNa
35
35
  #include "LaunchOptions.hpp"
36
36
  #include <string>
37
37
  #include <optional>
38
+ #include <variant>
38
39
  #include "WebViewPackageInfo.hpp"
39
40
  #include "GooglePlayServicesStatus.hpp"
40
41
  #include "AndroidChannel.hpp"
@@ -208,6 +209,36 @@ namespace margelo::nitro::reactnativedeviceutils {
208
209
  auto __value = std::move(__result.value());
209
210
  return __value;
210
211
  }
212
+ inline std::optional<std::variant<bool, std::string, double>> getInMemoryValue(const std::string& key) override {
213
+ auto __result = _swiftPart.getInMemoryValue(key);
214
+ if (__result.hasError()) [[unlikely]] {
215
+ std::rethrow_exception(__result.error());
216
+ }
217
+ auto __value = std::move(__result.value());
218
+ return __value;
219
+ }
220
+ inline void setInMemoryValue(const std::string& key, const std::variant<bool, std::string, double>& value) override {
221
+ auto __result = _swiftPart.setInMemoryValue(key, value);
222
+ if (__result.hasError()) [[unlikely]] {
223
+ std::rethrow_exception(__result.error());
224
+ }
225
+ }
226
+ inline bool removeInMemoryValue(const std::string& key) override {
227
+ auto __result = _swiftPart.removeInMemoryValue(key);
228
+ if (__result.hasError()) [[unlikely]] {
229
+ std::rethrow_exception(__result.error());
230
+ }
231
+ auto __value = std::move(__result.value());
232
+ return __value;
233
+ }
234
+ inline bool setInMemoryValueIfAbsent(const std::string& key, const std::variant<bool, std::string, double>& value) override {
235
+ auto __result = _swiftPart.setInMemoryValueIfAbsent(key, value);
236
+ if (__result.hasError()) [[unlikely]] {
237
+ std::rethrow_exception(__result.error());
238
+ }
239
+ auto __value = std::move(__result.value());
240
+ return __value;
241
+ }
211
242
  inline std::shared_ptr<Promise<std::string>> getAndClearColdStartLocalNotification() override {
212
243
  auto __result = _swiftPart.getAndClearColdStartLocalNotification();
213
244
  if (__result.hasError()) [[unlikely]] {
@@ -29,6 +29,10 @@ 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 getInMemoryValue(key: String) throws -> InMemoryValue?
33
+ func setInMemoryValue(key: String, value: InMemoryValue) throws -> Void
34
+ func removeInMemoryValue(key: String) throws -> Bool
35
+ func setInMemoryValueIfAbsent(key: String, value: InMemoryValue) throws -> Bool
32
36
  func getAndClearColdStartLocalNotification() throws -> Promise<String>
33
37
  func exitApp() throws -> Void
34
38
  func getCurrentWebViewPackageInfo() throws -> Promise<WebViewPackageInfo>
@@ -378,6 +378,98 @@ open class HybridReactNativeDeviceUtilsSpec_cxx {
378
378
  }
379
379
  }
380
380
 
381
+ @inline(__always)
382
+ public final func getInMemoryValue(key: std.string) -> bridge.Result_std__optional_std__variant_bool__std__string__double___ {
383
+ do {
384
+ let __result = try self.__implementation.getInMemoryValue(key: String(key))
385
+ let __resultCpp = { () -> bridge.std__optional_std__variant_bool__std__string__double__ in
386
+ if let __unwrappedValue = __result {
387
+ return bridge.create_std__optional_std__variant_bool__std__string__double__({ () -> bridge.std__variant_bool__std__string__double_ in
388
+ switch __unwrappedValue {
389
+ case .first(let __value):
390
+ return bridge.create_std__variant_bool__std__string__double_(__value)
391
+ case .second(let __value):
392
+ return bridge.create_std__variant_bool__std__string__double_(std.string(__value))
393
+ case .third(let __value):
394
+ return bridge.create_std__variant_bool__std__string__double_(__value)
395
+ }
396
+ }().variant)
397
+ } else {
398
+ return .init()
399
+ }
400
+ }()
401
+ return bridge.create_Result_std__optional_std__variant_bool__std__string__double___(__resultCpp)
402
+ } catch (let __error) {
403
+ let __exceptionPtr = __error.toCpp()
404
+ return bridge.create_Result_std__optional_std__variant_bool__std__string__double___(__exceptionPtr)
405
+ }
406
+ }
407
+
408
+ @inline(__always)
409
+ public final func setInMemoryValue(key: std.string, value: bridge.std__variant_bool__std__string__double_) -> bridge.Result_void_ {
410
+ do {
411
+ try self.__implementation.setInMemoryValue(key: String(key), value: { () -> InMemoryValue in
412
+ let __variant = value
413
+ switch __variant.index() {
414
+ case 0:
415
+ let __actual = __variant.get_0()
416
+ return .first(__actual)
417
+ case 1:
418
+ let __actual = __variant.get_1()
419
+ return .second(String(__actual))
420
+ case 2:
421
+ let __actual = __variant.get_2()
422
+ return .third(__actual)
423
+ default:
424
+ fatalError("Variant can never have index \(__variant.index())!")
425
+ }
426
+ }())
427
+ return bridge.create_Result_void_()
428
+ } catch (let __error) {
429
+ let __exceptionPtr = __error.toCpp()
430
+ return bridge.create_Result_void_(__exceptionPtr)
431
+ }
432
+ }
433
+
434
+ @inline(__always)
435
+ public final func removeInMemoryValue(key: std.string) -> bridge.Result_bool_ {
436
+ do {
437
+ let __result = try self.__implementation.removeInMemoryValue(key: String(key))
438
+ let __resultCpp = __result
439
+ return bridge.create_Result_bool_(__resultCpp)
440
+ } catch (let __error) {
441
+ let __exceptionPtr = __error.toCpp()
442
+ return bridge.create_Result_bool_(__exceptionPtr)
443
+ }
444
+ }
445
+
446
+ @inline(__always)
447
+ public final func setInMemoryValueIfAbsent(key: std.string, value: bridge.std__variant_bool__std__string__double_) -> bridge.Result_bool_ {
448
+ do {
449
+ let __result = try self.__implementation.setInMemoryValueIfAbsent(key: String(key), value: { () -> InMemoryValue in
450
+ let __variant = value
451
+ switch __variant.index() {
452
+ case 0:
453
+ let __actual = __variant.get_0()
454
+ return .first(__actual)
455
+ case 1:
456
+ let __actual = __variant.get_1()
457
+ return .second(String(__actual))
458
+ case 2:
459
+ let __actual = __variant.get_2()
460
+ return .third(__actual)
461
+ default:
462
+ fatalError("Variant can never have index \(__variant.index())!")
463
+ }
464
+ }())
465
+ let __resultCpp = __result
466
+ return bridge.create_Result_bool_(__resultCpp)
467
+ } catch (let __error) {
468
+ let __exceptionPtr = __error.toCpp()
469
+ return bridge.create_Result_bool_(__exceptionPtr)
470
+ }
471
+ }
472
+
381
473
  @inline(__always)
382
474
  public final func getAndClearColdStartLocalNotification() -> bridge.Result_std__shared_ptr_Promise_std__string___ {
383
475
  do {
@@ -0,0 +1,32 @@
1
+ ///
2
+ /// InMemoryValue.swift
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+
9
+
10
+ /**
11
+ * An Swift enum with associated values representing a Variant/Union type.
12
+ * JS type: `boolean | string | number`
13
+ */
14
+ @frozen
15
+ public enum InMemoryValue {
16
+ case first(Bool)
17
+ case second(String)
18
+ case third(Double)
19
+ }
20
+
21
+ public extension InMemoryValue {
22
+ func asType<T>(_ type: T.Type = T.self) -> T? {
23
+ switch self {
24
+ case .first(let value): return value as? T
25
+ case .second(let value): return value as? T
26
+ case .third(let value): return value as? T
27
+ }
28
+ }
29
+ func isType<T>(_ type: T.Type = T.self) -> Bool {
30
+ return self.asType(type) != nil
31
+ }
32
+ }
@@ -30,6 +30,10 @@ namespace margelo::nitro::reactnativedeviceutils {
30
30
  prototype.registerHybridMethod("saveDeviceToken", &HybridReactNativeDeviceUtilsSpec::saveDeviceToken);
31
31
  prototype.registerHybridMethod("registerDeviceToken", &HybridReactNativeDeviceUtilsSpec::registerDeviceToken);
32
32
  prototype.registerHybridMethod("getStartupTime", &HybridReactNativeDeviceUtilsSpec::getStartupTime);
33
+ prototype.registerHybridMethod("getInMemoryValue", &HybridReactNativeDeviceUtilsSpec::getInMemoryValue);
34
+ prototype.registerHybridMethod("setInMemoryValue", &HybridReactNativeDeviceUtilsSpec::setInMemoryValue);
35
+ prototype.registerHybridMethod("removeInMemoryValue", &HybridReactNativeDeviceUtilsSpec::removeInMemoryValue);
36
+ prototype.registerHybridMethod("setInMemoryValueIfAbsent", &HybridReactNativeDeviceUtilsSpec::setInMemoryValueIfAbsent);
33
37
  prototype.registerHybridMethod("getAndClearColdStartLocalNotification", &HybridReactNativeDeviceUtilsSpec::getAndClearColdStartLocalNotification);
34
38
  prototype.registerHybridMethod("exitApp", &HybridReactNativeDeviceUtilsSpec::exitApp);
35
39
  prototype.registerHybridMethod("getCurrentWebViewPackageInfo", &HybridReactNativeDeviceUtilsSpec::getCurrentWebViewPackageInfo);
@@ -35,6 +35,8 @@ namespace margelo::nitro::reactnativedeviceutils { enum class InstallerPackageNa
35
35
  #include "UserInterfaceStyle.hpp"
36
36
  #include "LaunchOptions.hpp"
37
37
  #include <string>
38
+ #include <variant>
39
+ #include <optional>
38
40
  #include "WebViewPackageInfo.hpp"
39
41
  #include "GooglePlayServicesStatus.hpp"
40
42
  #include "AndroidChannel.hpp"
@@ -87,6 +89,10 @@ namespace margelo::nitro::reactnativedeviceutils {
87
89
  virtual std::shared_ptr<Promise<void>> saveDeviceToken(const std::string& token) = 0;
88
90
  virtual std::shared_ptr<Promise<bool>> registerDeviceToken() = 0;
89
91
  virtual std::shared_ptr<Promise<double>> getStartupTime() = 0;
92
+ virtual std::optional<std::variant<bool, std::string, double>> getInMemoryValue(const std::string& key) = 0;
93
+ virtual void setInMemoryValue(const std::string& key, const std::variant<bool, std::string, double>& value) = 0;
94
+ virtual bool removeInMemoryValue(const std::string& key) = 0;
95
+ virtual bool setInMemoryValueIfAbsent(const std::string& key, const std::variant<bool, std::string, double>& value) = 0;
90
96
  virtual std::shared_ptr<Promise<std::string>> getAndClearColdStartLocalNotification() = 0;
91
97
  virtual void exitApp() = 0;
92
98
  virtual std::shared_ptr<Promise<WebViewPackageInfo>> getCurrentWebViewPackageInfo() = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-device-utils",
3
- "version": "3.0.177",
3
+ "version": "3.0.178",
4
4
  "description": "Native device, launch, system appearance and boot recovery utilities for OneKey",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -1,6 +1,8 @@
1
1
  import type { HybridObject } from 'react-native-nitro-modules';
2
2
 
3
3
 
4
+ export type InMemoryValue = string | boolean | number;
5
+
4
6
  export type UserInterfaceStyle = 'light' | 'dark' | 'unspecified';
5
7
 
6
8
  export type AndroidChannel =
@@ -73,6 +75,11 @@ export interface ReactNativeDeviceUtils
73
75
  saveDeviceToken(token: string): Promise<void>;
74
76
  registerDeviceToken(): Promise<boolean>;
75
77
  getStartupTime(): Promise<number>;
78
+ // Process-owned primitive Map, shared by all runtimes and never persisted.
79
+ getInMemoryValue(key: string): InMemoryValue | undefined;
80
+ setInMemoryValue(key: string, value: InMemoryValue): void;
81
+ removeInMemoryValue(key: string): boolean;
82
+ setInMemoryValueIfAbsent(key: string, value: InMemoryValue): boolean;
76
83
  // Returns the JSON userInfo of a LOCAL notification the user tapped to launch
77
84
  // the (killed) app, then clears it so it is delivered exactly once. Empty
78
85
  // string when there is none. iOS-only meaningful; Android returns "".