@matiks/rn-app-state 1.0.0

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 (55) hide show
  1. package/FLOW.md +239 -0
  2. package/NitroAppState.podspec +31 -0
  3. package/README.md +72 -0
  4. package/android/CMakeLists.txt +29 -0
  5. package/android/build.gradle +140 -0
  6. package/android/fix-prefab.gradle +51 -0
  7. package/android/gradle.properties +5 -0
  8. package/android/src/main/AndroidManifest.xml +2 -0
  9. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  10. package/android/src/main/java/com/margelo/nitro/appstate/HybridAppState.kt +188 -0
  11. package/android/src/main/java/com/margelo/nitro/appstate/NitroAppStatePackage.kt +18 -0
  12. package/ios/HybridAppState.swift +224 -0
  13. package/nitro.json +24 -0
  14. package/nitrogen/generated/.gitattributes +1 -0
  15. package/nitrogen/generated/android/NitroAppState+autolinking.cmake +81 -0
  16. package/nitrogen/generated/android/NitroAppState+autolinking.gradle +27 -0
  17. package/nitrogen/generated/android/NitroAppStateOnLoad.cpp +48 -0
  18. package/nitrogen/generated/android/NitroAppStateOnLoad.hpp +25 -0
  19. package/nitrogen/generated/android/c++/JAppStateChangeEvent.hpp +57 -0
  20. package/nitrogen/generated/android/c++/JAppStateListener.hpp +67 -0
  21. package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
  22. package/nitrogen/generated/android/c++/JFunc_void_AppStateChangeEvent.hpp +78 -0
  23. package/nitrogen/generated/android/c++/JHybridAppStateModuleSpec.cpp +84 -0
  24. package/nitrogen/generated/android/c++/JHybridAppStateModuleSpec.hpp +68 -0
  25. package/nitrogen/generated/android/kotlin/com/margelo/nitro/appstate/AppStateChangeEvent.kt +38 -0
  26. package/nitrogen/generated/android/kotlin/com/margelo/nitro/appstate/AppStateListener.kt +42 -0
  27. package/nitrogen/generated/android/kotlin/com/margelo/nitro/appstate/Func_void.kt +80 -0
  28. package/nitrogen/generated/android/kotlin/com/margelo/nitro/appstate/Func_void_AppStateChangeEvent.kt +80 -0
  29. package/nitrogen/generated/android/kotlin/com/margelo/nitro/appstate/HybridAppStateModuleSpec.kt +72 -0
  30. package/nitrogen/generated/android/kotlin/com/margelo/nitro/appstate/NitroAppStateOnLoad.kt +35 -0
  31. package/nitrogen/generated/ios/NitroAppState+autolinking.rb +60 -0
  32. package/nitrogen/generated/ios/NitroAppState-Swift-Cxx-Bridge.cpp +49 -0
  33. package/nitrogen/generated/ios/NitroAppState-Swift-Cxx-Bridge.hpp +112 -0
  34. package/nitrogen/generated/ios/NitroAppState-Swift-Cxx-Umbrella.hpp +51 -0
  35. package/nitrogen/generated/ios/NitroAppStateAutolinking.mm +33 -0
  36. package/nitrogen/generated/ios/NitroAppStateAutolinking.swift +26 -0
  37. package/nitrogen/generated/ios/c++/HybridAppStateModuleSpecSwift.cpp +11 -0
  38. package/nitrogen/generated/ios/c++/HybridAppStateModuleSpecSwift.hpp +106 -0
  39. package/nitrogen/generated/ios/swift/AppStateChangeEvent.swift +29 -0
  40. package/nitrogen/generated/ios/swift/AppStateListener.swift +37 -0
  41. package/nitrogen/generated/ios/swift/Func_void.swift +46 -0
  42. package/nitrogen/generated/ios/swift/Func_void_AppStateChangeEvent.swift +46 -0
  43. package/nitrogen/generated/ios/swift/HybridAppStateModuleSpec.swift +57 -0
  44. package/nitrogen/generated/ios/swift/HybridAppStateModuleSpec_cxx.swift +172 -0
  45. package/nitrogen/generated/shared/c++/AppStateChangeEvent.hpp +83 -0
  46. package/nitrogen/generated/shared/c++/AppStateListener.hpp +83 -0
  47. package/nitrogen/generated/shared/c++/HybridAppStateModuleSpec.cpp +24 -0
  48. package/nitrogen/generated/shared/c++/HybridAppStateModuleSpec.hpp +70 -0
  49. package/package.json +54 -0
  50. package/src/index.ts +2 -0
  51. package/src/specs/AppState.nitro.ts +57 -0
  52. package/src/useNitroAppState/index.ts +2 -0
  53. package/src/useNitroAppState/types.ts +21 -0
  54. package/src/useNitroAppState/useNitroAppState.native.ts +142 -0
  55. package/src/useNitroAppState/useNitroAppState.web.ts +56 -0
@@ -0,0 +1,188 @@
1
+ package com.margelo.nitro.appstate
2
+
3
+ import android.content.Context
4
+ import android.content.SharedPreferences
5
+ import android.os.Handler
6
+ import android.os.Looper
7
+ import android.util.Log
8
+ import androidx.lifecycle.DefaultLifecycleObserver
9
+ import androidx.lifecycle.LifecycleOwner
10
+ import androidx.lifecycle.ProcessLifecycleOwner
11
+ import com.facebook.proguard.annotations.DoNotStrip
12
+ import androidx.annotation.Keep
13
+ import com.margelo.nitro.NitroModules
14
+ import java.util.UUID
15
+ import java.util.concurrent.ConcurrentHashMap
16
+
17
+ /**
18
+ * Thread-safe native app state module for Android.
19
+ * Uses ProcessLifecycleOwner to observe app lifecycle and notifies JS listeners.
20
+ *
21
+ * States:
22
+ * - "active": App is in the foreground (resumed)
23
+ * - "background": App is in the background (stopped)
24
+ * - "killed": Only reported via `wasKilledLastSession` (not a live state)
25
+ *
26
+ * Thread safety:
27
+ * - Listeners stored in ConcurrentHashMap for thread-safe access.
28
+ * - State updates happen on the main thread (lifecycle callbacks are main-thread).
29
+ * - getCurrentState() is safe to call from any thread (reads a volatile field).
30
+ */
31
+ @DoNotStrip
32
+ @Keep
33
+ class HybridAppState : HybridAppStateModuleSpec() {
34
+
35
+ companion object {
36
+ private const val TAG = "HybridAppState"
37
+ private const val PREFS_NAME = "com.matiks.appstate"
38
+ private const val KEY_DID_EXIT_CLEANLY = "didExitCleanly"
39
+ private const val KEY_HAS_LAUNCHED_BEFORE = "hasLaunchedBefore"
40
+
41
+ /**
42
+ * Get SharedPreferences using NitroModules.applicationContext.
43
+ * Falls back gracefully if context is not yet available.
44
+ */
45
+ private fun getPrefs(): SharedPreferences? {
46
+ val ctx = NitroModules.applicationContext
47
+ if (ctx == null) {
48
+ Log.w(TAG, "NitroModules.applicationContext is null — SharedPreferences unavailable")
49
+ return null
50
+ }
51
+ return ctx.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
52
+ }
53
+ }
54
+
55
+ // MARK: - State
56
+
57
+ /** Current app state. Volatile for cross-thread visibility. */
58
+ @Volatile
59
+ private var currentState: String = "active"
60
+
61
+ /** Whether the previous session was killed. */
62
+ override val wasKilledLastSession: Boolean
63
+
64
+ /** Registered JS listeners. ConcurrentHashMap for thread safety. */
65
+ private val listeners = ConcurrentHashMap<String, (event: AppStateChangeEvent) -> Unit>()
66
+
67
+ /** Main thread handler for dispatching lifecycle observer registration. */
68
+ private val mainHandler = Handler(Looper.getMainLooper())
69
+
70
+ /** Lifecycle observer instance (stored to allow removal on dispose). */
71
+ private val lifecycleObserver: DefaultLifecycleObserver
72
+
73
+ // MARK: - Init
74
+
75
+ init {
76
+ val prefs = getPrefs()
77
+
78
+ // Determine if the app was killed last session.
79
+ val hasLaunchedBefore = prefs?.getBoolean(KEY_HAS_LAUNCHED_BEFORE, false) ?: false
80
+ val didExitCleanly = prefs?.getBoolean(KEY_DID_EXIT_CLEANLY, false) ?: false
81
+
82
+ // First launch ever: no previous session, so not "killed".
83
+ // Subsequent launches: if the flag is false, the app was killed.
84
+ wasKilledLastSession = hasLaunchedBefore && !didExitCleanly
85
+
86
+ // Reset the flag. It will be set to true when we exit cleanly.
87
+ prefs?.edit()
88
+ ?.putBoolean(KEY_HAS_LAUNCHED_BEFORE, true)
89
+ ?.putBoolean(KEY_DID_EXIT_CLEANLY, false)
90
+ ?.apply()
91
+
92
+ Log.d(TAG, "Initialized. wasKilledLastSession=$wasKilledLastSession")
93
+
94
+ // Create lifecycle observer
95
+ lifecycleObserver = object : DefaultLifecycleObserver {
96
+ override fun onStart(owner: LifecycleOwner) {
97
+ // App came to foreground
98
+ updateState("active")
99
+ }
100
+
101
+ override fun onStop(owner: LifecycleOwner) {
102
+ // App went to background - mark clean exit
103
+ markCleanExit()
104
+ updateState("background")
105
+ }
106
+ }
107
+
108
+ // Register lifecycle observer on the main thread.
109
+ // ProcessLifecycleOwner.get().lifecycle must be accessed on main thread.
110
+ val registerBlock = Runnable {
111
+ try {
112
+ ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleObserver)
113
+ Log.d(TAG, "Lifecycle observer registered")
114
+ } catch (e: Exception) {
115
+ Log.e(TAG, "Failed to register lifecycle observer", e)
116
+ }
117
+ }
118
+
119
+ if (Looper.myLooper() == Looper.getMainLooper()) {
120
+ registerBlock.run()
121
+ } else {
122
+ mainHandler.post(registerBlock)
123
+ }
124
+ }
125
+
126
+ // MARK: - HybridAppStateModuleSpec Methods
127
+
128
+ override fun getCurrentState(): String {
129
+ return currentState
130
+ }
131
+
132
+ override fun addListener(onStateChange: (event: AppStateChangeEvent) -> Unit): AppStateListener {
133
+ val id = UUID.randomUUID().toString()
134
+ listeners[id] = onStateChange
135
+
136
+ val removeCallback: () -> Unit = {
137
+ listeners.remove(id)
138
+ }
139
+
140
+ return AppStateListener(removeCallback)
141
+ }
142
+
143
+ override fun getStateOnNotification(): String {
144
+ // Return the current state at the moment a notification is received.
145
+ // ProcessLifecycleOwner accurately tracks foreground/background,
146
+ // so currentState reflects the real state even during notification handling.
147
+ return currentState
148
+ }
149
+
150
+ // MARK: - Private Helpers
151
+
152
+ /**
153
+ * Update the current state and notify all listeners.
154
+ * Called from lifecycle callbacks (always on main thread).
155
+ */
156
+ private fun updateState(newState: String) {
157
+ if (newState == currentState) return
158
+ currentState = newState
159
+
160
+ Log.d(TAG, "State changed to: $newState")
161
+
162
+ val event = AppStateChangeEvent(state = newState)
163
+
164
+ // Snapshot and iterate. ConcurrentHashMap's values are safe to iterate
165
+ // even if a listener calls remove() during callback.
166
+ for ((_, listener) in listeners) {
167
+ try {
168
+ listener(event)
169
+ } catch (e: Exception) {
170
+ Log.e(TAG, "Error in app state listener callback", e)
171
+ }
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Persist a flag indicating the app exited cleanly (not killed).
177
+ * Uses commit() (synchronous) to ensure it's written before process death.
178
+ */
179
+ private fun markCleanExit() {
180
+ try {
181
+ getPrefs()?.edit()
182
+ ?.putBoolean(KEY_DID_EXIT_CLEANLY, true)
183
+ ?.commit()
184
+ } catch (e: Exception) {
185
+ Log.e(TAG, "Failed to mark clean exit", e)
186
+ }
187
+ }
188
+ }
@@ -0,0 +1,18 @@
1
+ package com.margelo.nitro.appstate
2
+
3
+ import com.facebook.react.bridge.NativeModule
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.module.model.ReactModuleInfoProvider
6
+ import com.facebook.react.BaseReactPackage
7
+
8
+ class NitroAppStatePackage : BaseReactPackage() {
9
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = null
10
+
11
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = ReactModuleInfoProvider { HashMap() }
12
+
13
+ companion object {
14
+ init {
15
+ NitroAppStateOnLoad.initializeNative()
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,224 @@
1
+ import UIKit
2
+ import NitroModules
3
+
4
+ /// Thread-safe native app state module for iOS.
5
+ /// Observes UIApplication lifecycle notifications and notifies JS listeners.
6
+ ///
7
+ /// States:
8
+ /// - "active": App is in the foreground and interactive
9
+ /// - "background": App is in the background or inactive (iOS inactive is merged into background)
10
+ /// - "killed": Only reported via `wasKilledLastSession` (not a live state)
11
+ ///
12
+ /// Thread safety:
13
+ /// - Nitro calls methods on arbitrary threads.
14
+ /// - UIApplication.shared.applicationState must be read on the main thread.
15
+ /// - Listener storage uses a serial queue for thread-safe access.
16
+ /// - Listener callbacks are dispatched on the main thread.
17
+ class HybridAppState: HybridAppStateModuleSpec {
18
+
19
+ // MARK: - Constants
20
+
21
+ private static let killedFlagKey = "com.matiks.appstate.didExitCleanly"
22
+
23
+ // MARK: - State
24
+
25
+ /// Serial queue protecting listener dictionary access.
26
+ private let listenerQueue = DispatchQueue(label: "com.matiks.appstate.listeners")
27
+
28
+ /// All registered JS listeners, keyed by UUID.
29
+ private var listeners: [UUID: (AppStateChangeEvent) -> Void] = [:]
30
+
31
+ /// The current state as tracked by this module. Only mutated on the main thread.
32
+ private var currentState: String = "active"
33
+
34
+ /// Whether the previous session was killed (force-quit / OOM / crash).
35
+ private(set) var wasKilledLastSession: Bool = false
36
+
37
+ // MARK: - Init
38
+
39
+ override init() {
40
+ // Compute the killed flag before super.init(), then assign after.
41
+ // The C++ wrapper is created lazily (not during init), so the
42
+ // property will have the correct value by the time JS accesses it.
43
+ let defaults = UserDefaults.standard
44
+ let hasLaunchedBefore = defaults.object(forKey: HybridAppState.killedFlagKey) != nil
45
+ let didExitCleanly = defaults.bool(forKey: HybridAppState.killedFlagKey)
46
+
47
+ // First launch ever: no previous session, so not "killed".
48
+ // Subsequent launches: if the flag is false, the app was killed.
49
+ let killed = hasLaunchedBefore && !didExitCleanly
50
+
51
+ super.init()
52
+
53
+ self.wasKilledLastSession = killed
54
+
55
+ // Reset the flag to false. It will be set to true when we exit cleanly
56
+ // (entering background or willTerminate).
57
+ defaults.set(false, forKey: HybridAppState.killedFlagKey)
58
+ defaults.synchronize()
59
+
60
+ // Determine initial state from UIApplication (must be on main thread).
61
+ if Thread.isMainThread {
62
+ self.currentState = self.readApplicationState()
63
+ } else {
64
+ DispatchQueue.main.sync {
65
+ self.currentState = self.readApplicationState()
66
+ }
67
+ }
68
+
69
+ // Register for lifecycle notifications on the main thread.
70
+ let registerBlock = { [weak self] in
71
+ guard let self = self else { return }
72
+ let center = NotificationCenter.default
73
+ center.addObserver(
74
+ self,
75
+ selector: #selector(self.handleDidBecomeActive),
76
+ name: UIApplication.didBecomeActiveNotification,
77
+ object: nil
78
+ )
79
+ center.addObserver(
80
+ self,
81
+ selector: #selector(self.handleDidEnterBackground),
82
+ name: UIApplication.didEnterBackgroundNotification,
83
+ object: nil
84
+ )
85
+ center.addObserver(
86
+ self,
87
+ selector: #selector(self.handleWillResignActive),
88
+ name: UIApplication.willResignActiveNotification,
89
+ object: nil
90
+ )
91
+ center.addObserver(
92
+ self,
93
+ selector: #selector(self.handleWillTerminate),
94
+ name: UIApplication.willTerminateNotification,
95
+ object: nil
96
+ )
97
+ }
98
+
99
+ if Thread.isMainThread {
100
+ registerBlock()
101
+ } else {
102
+ DispatchQueue.main.async(execute: registerBlock)
103
+ }
104
+ }
105
+
106
+ deinit {
107
+ NotificationCenter.default.removeObserver(self)
108
+ }
109
+
110
+ // MARK: - HybridAppStateModuleSpec Methods
111
+
112
+ func getCurrentState() throws -> String {
113
+ if Thread.isMainThread {
114
+ return currentState
115
+ }
116
+ var state = ""
117
+ DispatchQueue.main.sync {
118
+ state = self.currentState
119
+ }
120
+ return state
121
+ }
122
+
123
+ func addListener(onStateChange: @escaping (AppStateChangeEvent) -> Void) throws -> AppStateListener {
124
+ let id = UUID()
125
+
126
+ listenerQueue.sync {
127
+ listeners[id] = onStateChange
128
+ }
129
+
130
+ let removeCallback: () -> Void = { [weak self] in
131
+ guard let self = self else { return }
132
+ self.listenerQueue.sync {
133
+ _ = self.listeners.removeValue(forKey: id)
134
+ }
135
+ }
136
+
137
+ return AppStateListener(remove: removeCallback)
138
+ }
139
+
140
+ func getStateOnNotification() throws -> String {
141
+ // Return the real UIApplication state at the moment of the call.
142
+ // This is useful when a push/silent notification wakes the app.
143
+ if Thread.isMainThread {
144
+ return readApplicationState()
145
+ }
146
+ var state = ""
147
+ DispatchQueue.main.sync {
148
+ state = self.readApplicationState()
149
+ }
150
+ return state
151
+ }
152
+
153
+ // MARK: - Lifecycle Handlers (always called on main thread by NotificationCenter)
154
+
155
+ @objc private func handleDidBecomeActive() {
156
+ updateState("active")
157
+ }
158
+
159
+ @objc private func handleDidEnterBackground() {
160
+ // Mark clean exit so next launch knows we weren't killed.
161
+ markCleanExit()
162
+ updateState("background")
163
+ }
164
+
165
+ @objc private func handleWillResignActive() {
166
+ // iOS fires willResignActive before didEnterBackground,
167
+ // and also when opening notification center, control center, etc.
168
+ // We treat this as "background" since the user only wants active/background/killed.
169
+ updateState("background")
170
+ }
171
+
172
+ @objc private func handleWillTerminate() {
173
+ // App is about to be terminated by the system or user.
174
+ // This is a clean termination, so mark it.
175
+ markCleanExit()
176
+ }
177
+
178
+ // MARK: - Private Helpers
179
+
180
+ /// Update the current state and notify all listeners.
181
+ /// Must be called on the main thread.
182
+ private func updateState(_ newState: String) {
183
+ guard newState != currentState else { return }
184
+ currentState = newState
185
+
186
+ let event = AppStateChangeEvent(state: newState)
187
+
188
+ // Snapshot listeners under the lock, then call outside the lock
189
+ // to avoid deadlocks if a listener calls remove() during callback.
190
+ var currentListeners: [(AppStateChangeEvent) -> Void] = []
191
+ listenerQueue.sync {
192
+ currentListeners = Array(self.listeners.values)
193
+ }
194
+
195
+ for listener in currentListeners {
196
+ listener(event)
197
+ }
198
+ }
199
+
200
+ /// Read UIApplication.shared.applicationState and map to our state strings.
201
+ /// MUST be called on the main thread.
202
+ private func readApplicationState() -> String {
203
+ let appState = UIApplication.shared.applicationState
204
+ switch appState {
205
+ case .active:
206
+ return "active"
207
+ case .background:
208
+ return "background"
209
+ case .inactive:
210
+ // iOS "inactive" is transitional (e.g., notification center open).
211
+ // Map to "background" since user only wants active/background/killed.
212
+ return "background"
213
+ @unknown default:
214
+ return "active"
215
+ }
216
+ }
217
+
218
+ /// Persist a flag indicating the app exited cleanly (not killed).
219
+ private func markCleanExit() {
220
+ let defaults = UserDefaults.standard
221
+ defaults.set(true, forKey: HybridAppState.killedFlagKey)
222
+ defaults.synchronize()
223
+ }
224
+ }
package/nitro.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "https://nitro.margelo.com/nitro.schema.json",
3
+ "cxxNamespace": [
4
+ "appstate"
5
+ ],
6
+ "ios": {
7
+ "iosModuleName": "NitroAppState"
8
+ },
9
+ "android": {
10
+ "androidNamespace": [
11
+ "appstate"
12
+ ],
13
+ "androidCxxLibName": "NitroAppState"
14
+ },
15
+ "autolinking": {
16
+ "AppStateModule": {
17
+ "swift": "HybridAppState",
18
+ "kotlin": "HybridAppState"
19
+ }
20
+ },
21
+ "ignorePaths": [
22
+ "**/node_modules"
23
+ ]
24
+ }
@@ -0,0 +1 @@
1
+ ** linguist-generated=true
@@ -0,0 +1,81 @@
1
+ #
2
+ # NitroAppState+autolinking.cmake
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
+ # This is a CMake file that adds all files generated by Nitrogen
9
+ # to the current CMake project.
10
+ #
11
+ # To use it, add this to your CMakeLists.txt:
12
+ # ```cmake
13
+ # include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroAppState+autolinking.cmake)
14
+ # ```
15
+
16
+ # Define a flag to check if we are building properly
17
+ add_definitions(-DBUILDING_NITROAPPSTATE_WITH_GENERATED_CMAKE_PROJECT)
18
+
19
+ # Enable Raw Props parsing in react-native (for Nitro Views)
20
+ add_definitions(-DRN_SERIALIZABLE_STATE)
21
+
22
+ # Add all headers that were generated by Nitrogen
23
+ include_directories(
24
+ "../nitrogen/generated/shared/c++"
25
+ "../nitrogen/generated/android/c++"
26
+ "../nitrogen/generated/android/"
27
+ )
28
+
29
+ # Add all .cpp sources that were generated by Nitrogen
30
+ target_sources(
31
+ # CMake project name (Android C++ library name)
32
+ NitroAppState PRIVATE
33
+ # Autolinking Setup
34
+ ../nitrogen/generated/android/NitroAppStateOnLoad.cpp
35
+ # Shared Nitrogen C++ sources
36
+ ../nitrogen/generated/shared/c++/HybridAppStateModuleSpec.cpp
37
+ # Android-specific Nitrogen C++ sources
38
+ ../nitrogen/generated/android/c++/JHybridAppStateModuleSpec.cpp
39
+ )
40
+
41
+ # From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake
42
+ # Used in node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake
43
+ target_compile_definitions(
44
+ NitroAppState PRIVATE
45
+ -DFOLLY_NO_CONFIG=1
46
+ -DFOLLY_HAVE_CLOCK_GETTIME=1
47
+ -DFOLLY_USE_LIBCPP=1
48
+ -DFOLLY_CFG_NO_COROUTINES=1
49
+ -DFOLLY_MOBILE=1
50
+ -DFOLLY_HAVE_RECVMMSG=1
51
+ -DFOLLY_HAVE_PTHREAD=1
52
+ # Once we target android-23 above, we can comment
53
+ # the following line. NDK uses GNU style stderror_r() after API 23.
54
+ -DFOLLY_HAVE_XSI_STRERROR_R=1
55
+ )
56
+
57
+ # Add all libraries required by the generated specs
58
+ find_package(fbjni REQUIRED) # <-- Used for communication between Java <-> C++
59
+ find_package(ReactAndroid REQUIRED) # <-- Used to set up React Native bindings (e.g. CallInvoker/TurboModule)
60
+ find_package(react-native-nitro-modules REQUIRED) # <-- Used to create all HybridObjects and use the Nitro core library
61
+
62
+ # Link all libraries together
63
+ target_link_libraries(
64
+ NitroAppState
65
+ fbjni::fbjni # <-- Facebook C++ JNI helpers
66
+ ReactAndroid::jsi # <-- RN: JSI
67
+ react-native-nitro-modules::NitroModules # <-- NitroModules Core :)
68
+ )
69
+
70
+ # Link react-native (different prefab between RN 0.75 and RN 0.76)
71
+ if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)
72
+ target_link_libraries(
73
+ NitroAppState
74
+ ReactAndroid::reactnative # <-- RN: Native Modules umbrella prefab
75
+ )
76
+ else()
77
+ target_link_libraries(
78
+ NitroAppState
79
+ ReactAndroid::react_nativemodule_core # <-- RN: TurboModules Core
80
+ )
81
+ endif()
@@ -0,0 +1,27 @@
1
+ ///
2
+ /// NitroAppState+autolinking.gradle
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
+ /// This is a Gradle file that adds all files generated by Nitrogen
9
+ /// to the current Gradle project.
10
+ ///
11
+ /// To use it, add this to your build.gradle:
12
+ /// ```gradle
13
+ /// apply from: '../nitrogen/generated/android/NitroAppState+autolinking.gradle'
14
+ /// ```
15
+
16
+ logger.warn("[NitroModules] 🔥 NitroAppState is boosted by nitro!")
17
+
18
+ android {
19
+ sourceSets {
20
+ main {
21
+ java.srcDirs += [
22
+ // Nitrogen files
23
+ "${project.projectDir}/../nitrogen/generated/android/kotlin"
24
+ ]
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,48 @@
1
+ ///
2
+ /// NitroAppStateOnLoad.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
+ #ifndef BUILDING_NITROAPPSTATE_WITH_GENERATED_CMAKE_PROJECT
9
+ #error NitroAppStateOnLoad.cpp is not being built with the autogenerated CMakeLists.txt project. Is a different CMakeLists.txt building this?
10
+ #endif
11
+
12
+ #include "NitroAppStateOnLoad.hpp"
13
+
14
+ #include <jni.h>
15
+ #include <fbjni/fbjni.h>
16
+ #include <NitroModules/HybridObjectRegistry.hpp>
17
+
18
+ #include "JHybridAppStateModuleSpec.hpp"
19
+ #include "JFunc_void.hpp"
20
+ #include "JFunc_void_AppStateChangeEvent.hpp"
21
+ #include <NitroModules/DefaultConstructableObject.hpp>
22
+
23
+ namespace margelo::nitro::appstate {
24
+
25
+ int initialize(JavaVM* vm) {
26
+ using namespace margelo::nitro;
27
+ using namespace margelo::nitro::appstate;
28
+ using namespace facebook;
29
+
30
+ return facebook::jni::initialize(vm, [] {
31
+ // Register native JNI methods
32
+ margelo::nitro::appstate::JHybridAppStateModuleSpec::registerNatives();
33
+ margelo::nitro::appstate::JFunc_void_cxx::registerNatives();
34
+ margelo::nitro::appstate::JFunc_void_AppStateChangeEvent_cxx::registerNatives();
35
+
36
+ // Register Nitro Hybrid Objects
37
+ HybridObjectRegistry::registerHybridObjectConstructor(
38
+ "AppStateModule",
39
+ []() -> std::shared_ptr<HybridObject> {
40
+ static DefaultConstructableObject<JHybridAppStateModuleSpec::javaobject> object("com/margelo/nitro/appstate/HybridAppState");
41
+ auto instance = object.create();
42
+ return instance->cthis()->shared();
43
+ }
44
+ );
45
+ });
46
+ }
47
+
48
+ } // namespace margelo::nitro::appstate
@@ -0,0 +1,25 @@
1
+ ///
2
+ /// NitroAppStateOnLoad.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
+ #include <jni.h>
9
+ #include <NitroModules/NitroDefines.hpp>
10
+
11
+ namespace margelo::nitro::appstate {
12
+
13
+ /**
14
+ * Initializes the native (C++) part of NitroAppState, and autolinks all Hybrid Objects.
15
+ * Call this in your `JNI_OnLoad` function (probably inside `cpp-adapter.cpp`).
16
+ * Example:
17
+ * ```cpp (cpp-adapter.cpp)
18
+ * JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
19
+ * return margelo::nitro::appstate::initialize(vm);
20
+ * }
21
+ * ```
22
+ */
23
+ int initialize(JavaVM* vm);
24
+
25
+ } // namespace margelo::nitro::appstate