react-native-acoustic-connect-beta 18.0.22 → 18.0.24

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 (35) hide show
  1. package/AcousticConnectRN.podspec +24 -4
  2. package/README.md +237 -67
  3. package/android/build.gradle +47 -2
  4. package/android/gradle.properties +3 -3
  5. package/android/src/main/assets/ConnectAdvancedConfig.json +1 -1
  6. package/android/src/main/assets/ConnectBasicConfig.properties +1 -1
  7. package/android/src/main/assets/TealeafAdvancedConfig.json +1 -1
  8. package/android/src/main/java/com/acousticconnectrn/AcousticConnectRNPackage.java +9 -32
  9. package/android/src/main/java/com/acousticconnectrn/HybridAcousticConnectRN.kt +258 -87
  10. package/ios/HybridAcousticConnectRN.swift +181 -73
  11. package/lib/commonjs/TLTRN.js +18 -12
  12. package/lib/commonjs/TLTRN.js.map +1 -1
  13. package/lib/commonjs/components/Connect.js +3 -0
  14. package/lib/commonjs/components/Connect.js.map +1 -1
  15. package/lib/module/TLTRN.js +18 -12
  16. package/lib/module/TLTRN.js.map +1 -1
  17. package/lib/module/components/Connect.js +3 -0
  18. package/lib/module/components/Connect.js.map +1 -1
  19. package/lib/typescript/src/TLTRN.d.ts.map +1 -1
  20. package/lib/typescript/src/components/Connect.d.ts.map +1 -1
  21. package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts +62 -0
  22. package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts.map +1 -1
  23. package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.cpp +10 -0
  24. package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.hpp +2 -0
  25. package/nitrogen/generated/android/kotlin/com/margelo/nitro/acousticconnectrn/HybridAcousticConnectRNSpec.kt +8 -0
  26. package/nitrogen/generated/ios/c++/HybridAcousticConnectRNSpecSwift.hpp +16 -0
  27. package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec.swift +2 -0
  28. package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec_cxx.swift +24 -0
  29. package/nitrogen/generated/shared/c++/HybridAcousticConnectRNSpec.cpp +2 -0
  30. package/nitrogen/generated/shared/c++/HybridAcousticConnectRNSpec.hpp +2 -0
  31. package/package.json +7 -4
  32. package/scripts/ConnectConfig.json +1 -1
  33. package/src/TLTRN.ts +23 -16
  34. package/src/components/Connect.tsx +3 -0
  35. package/src/specs/react-native-acoustic-connect.nitro.ts +63 -0
@@ -8,7 +8,28 @@ repository = package["repository"]["url"]
8
8
  useRelease = connectConfig["Connect"]["useRelease"]
9
9
  dependencyName = useRelease ? 'AcousticConnect' : 'AcousticConnectDebug'
10
10
  iOSVersion = connectConfig["Connect"]["iOSVersion"]
11
- dependencyVersion = iOSVersion.to_s.empty? ? "" : ", '#{iOSVersion}'"
11
+
12
+ # Floor required by the RN bridge:
13
+ # - `ConnectSDK.shared.enable(with:)` and `ConnectConfig` landed in 2.0.0
14
+ # (CA-135041) — anything older lacks the Swift symbols this file imports.
15
+ # - Bundle-less init via `_connectApplyBundleDefaults` landed in 2.0.5
16
+ # (CA-136977, Release_Connect_Module_2_0_5, 2026-04-13). Without it,
17
+ # consumers who don't bundle `EOCoreSettings.bundle` + `TLFResources.bundle`
18
+ # fail to enable the SDK at all — the bridge ships no bundles and relies
19
+ # on programmatic config, so this fix is load-bearing here.
20
+ # Consumers can still pin a specific version via
21
+ # `ConnectConfig.json -> Connect.iOSVersion`; CocoaPods composes both
22
+ # constraints, so an attempted downgrade fails loudly at `pod install`.
23
+ #
24
+ # Push: the iOS Connect SDK ships push as part of the same pod (`ConnectPushConfig`
25
+ # is in `ConnectSDK.shared.enable(with:)`), so this single floor covers both the
26
+ # analytics and push code paths. If a future SDK major splits push into a
27
+ # separate pod or moves push features to a higher floor, this is the natural
28
+ # place to introduce a conditional floor keyed off
29
+ # `ConnectConfig.json -> Connect.PushEnabled` (mirrors the Android conditional
30
+ # on `connect-push-fcm` in `android/build.gradle`).
31
+ sdkFloor = '>= 2.0.5'
32
+ dependencyRequirements = iOSVersion.to_s.empty? ? [sdkFloor] : [sdkFloor, iOSVersion]
12
33
 
13
34
  # Write the merged consumer config to the resource-bundle source path AT POD INSTALL TIME.
14
35
  # This MUST happen before CocoaPods builds the AcousticConnectRNConfig bundle target,
@@ -29,8 +50,7 @@ puts JSON.pretty_generate(connectConfig)
29
50
  puts "repository:#{repository}"
30
51
  puts "useRelease:#{useRelease}"
31
52
  puts "dependencyName:#{dependencyName}"
32
- puts "dependencyVersion:#{dependencyVersion}"
33
- puts "connectDependency:#{dependencyName}#{dependencyVersion}"
53
+ puts "dependencyRequirements:#{dependencyRequirements.inspect}"
34
54
  puts "***************************************************************"
35
55
 
36
56
  Pod::Spec.new do |s|
@@ -69,6 +89,6 @@ Pod::Spec.new do |s|
69
89
 
70
90
  s.dependency 'React-jsi'
71
91
  s.dependency 'React-callinvoker'
72
- s.dependency "#{dependencyName}#{dependencyVersion}"
92
+ s.dependency dependencyName, *dependencyRequirements
73
93
  install_modules_dependencies(s)
74
94
  end
package/README.md CHANGED
@@ -1,93 +1,263 @@
1
1
  # react-native-acoustic-connect-beta
2
2
 
3
+ React Native plugin for the Acoustic Connect SDK. Captures user interactions,
4
+ screen replays, and analytics events on iOS and Android. Supports optional push
5
+ notifications via the Connect backend.
6
+
7
+ For the full product overview see the
8
+ [Connect SDK overview on the developer portal](https://developer.goacoustic.com/acoustic-connect/docs/connect-sdk-overview).
9
+
3
10
  ## Requirements
4
11
 
5
- - React Native v0.78.0 or higher using new architecture
6
- - Node 20.0.0 or higher
7
- - Does not support expo
12
+ - React Native 0.82.x – 0.85.x with the new architecture
13
+ - React 19.1.1 or newer (or whatever your RN version pins)
14
+ - Node 20 or newer
15
+ - iOS deployment target ≥ 15.1, AcousticConnect / AcousticConnectDebug pod ≥ 2.0.5
16
+ - Android `minSdk` ≥ 26, `compileSdk` ≥ 35, `io.github.go-acoustic:connect` in `[11.0.11, 12.0.0)`
17
+ - **Expo is not supported by this package.** Expo apps should use the sibling
18
+ Config Plugin (tracked separately under PES-4002 / CA-137701).
8
19
 
9
20
  ## Installation
10
21
 
11
22
  ```bash
12
- // To add to your package
13
- npm add react-native-acoustic-connect-beta react-native-nitro-modules
14
- // To install on your application and view debug information during install
15
- npm install --foreground-scripts --force
16
-
23
+ npm install react-native-acoustic-connect-beta react-native-nitro-modules
24
+ cd ios && pod install
17
25
  ```
18
- ## Overview
19
26
 
20
- [Go to overview](https://developer.goacoustic.com/acoustic-connect/docs/connect-sdk-overview)
27
+ The plugin reads a `ConnectConfig.json` from your project root at install time
28
+ (iOS via the podspec, Android via `config.gradle`) and bakes the values into the
29
+ native bundles. **`ConnectConfig.json` is the single source of truth** — there
30
+ is no runtime override path. A minimal config looks like:
21
31
 
22
- ---
32
+ ```json
33
+ {
34
+ "Connect": {
35
+ "AppKey": "your-app-key",
36
+ "PostMessageUrl": "https://collector.example.com/collectorPost",
37
+ "KillSwitchUrl": "https://collector.example.com/collector/switch/your-app-key",
38
+ "useRelease": false,
23
39
 
24
- ## Getting started
40
+ "PushEnabled": false,
41
+ "iOSPushMode": "automatic",
42
+ "iOSAppGroupIdentifier": null,
43
+ "AndroidNotificationIconResName": null
44
+ }
45
+ }
46
+ ```
25
47
 
26
- **This module uses only enhanced replay.
48
+ Field summary (see [API reference](#api-reference) for full semantics):
27
49
 
28
- [Connect Install Documentation](https://developer.goacoustic.com/acoustic-connect/docs/react-native-integration)
50
+ | Field | Default | Purpose |
51
+ | --- | --- | --- |
52
+ | `AppKey` | _(required)_ | Your Connect application key. |
53
+ | `PostMessageUrl` | _(required)_ | Collector endpoint URL. |
54
+ | `KillSwitchUrl` | _(optional)_ | Kill-switch endpoint URL. |
55
+ | `useRelease` | `false` | `true` selects the release AcousticConnect iOS pod over the debug variant. |
56
+ | `iOSVersion` | `""` | Pin a specific iOS pod version; empty = newest in the supported range. |
57
+ | `AndroidVersion` | `""` | Pin a specific Android Connect SDK version; empty = newest in the supported range. |
58
+ | `PushEnabled` | `false` | Master switch. On Android, also gates the `connect-push-fcm` artifact inclusion. |
59
+ | `iOSPushMode` | `"automatic"` | iOS-only: `"automatic"` (SDK owns APNs delegate) or `"manual"` (app owns it). Ignored when `PushEnabled` is `false`. |
60
+ | `iOSAppGroupIdentifier` | `null` | iOS App Group shared with the Notification Service / Notification Content extension. |
61
+ | `AndroidNotificationIconResName` | `null` | Drawable resource name (no extension) for the Android notification small icon. |
29
62
 
30
- ---
31
- # Demo
32
- ## Sample Code with integrated
33
- ### Using NativeBase v3 KitchenSink
34
- ![demo](https://github.com/go-acoustic/react-native-acoustic-connect/blob/main/Example/nativebase-v3-kitchensink/assets/demo.png)
63
+ ## Quick start
35
64
 
36
- * NativeBase-KitchenSink taken from https://github.com/GeekyAnts/nativebase-v3-kitchensink which is at Example/nativebase-v3-kitchensink.
65
+ ### 1. Initialise the SDK
37
66
 
38
- [Installation instructions](https://developer.goacoustic.com/acoustic-connect/docs/build-a-sample-react-native-app)
39
- ---
67
+ The SDK **auto-initialises** at module load time using the values from
68
+ `ConnectConfig.json`. For most apps there is no JS-side init code to write —
69
+ just import the package and you're done:
40
70
 
41
- # Notes
42
- There are several know issues between npm install versus yarn install. Since yarn is a Facebook tool. It normally has fixes patched for installing dependancies.
71
+ ```ts
72
+ // index.js
73
+ import AcousticConnectRN from 'react-native-acoustic-connect-beta'
74
+ // SDK is already initialising on the main actor / main looper. No further
75
+ // setup required.
76
+ ```
43
77
 
44
- ## Troubleshooting
78
+ For consent-gated apps (GDPR, CCPA, COPPA), use the lifecycle pair:
79
+
80
+ ```ts
81
+ import AcousticConnectRN from 'react-native-acoustic-connect-beta'
45
82
 
46
- ### Issues installing
83
+ // At app start, if you don't yet have user consent:
84
+ AcousticConnectRN.disable()
85
+
86
+ // Later, after the user opts in:
87
+ AcousticConnectRN.enable()
47
88
  ```
48
- npm add react-native-nitro-modules
49
- npm ERR! code ERESOLVE
50
- npm ERR! ERESOLVE could not resolve
51
- npm ERR!
52
- npm ERR! While resolving: @expo/webpack-config@19.0.1
53
- npm ERR! Found: expo@52.0.46
54
- npm ERR! node_modules/expo
55
- npm ERR! peer expo@"*" from expo-font@13.0.4
56
- npm ERR! node_modules/expo-font
57
- npm ERR! expo-font@"~13.0.4" from expo@52.0.46
58
- npm ERR! peer expo-font@"*" from @expo/vector-icons@14.1.0
59
- npm ERR! node_modules/@expo/vector-icons
60
- npm ERR! @expo/vector-icons@"^14.0.0" from expo@52.0.46
61
- npm ERR! 1 more (the root project)
62
- npm ERR! 1 more (the root project)
63
- npm ERR! peer expo@"*" from expo-file-system@18.0.12
64
- npm ERR! node_modules/expo-file-system
65
- npm ERR! expo-file-system@"~18.0.12" from expo@52.0.46
66
- npm ERR! 6 more (expo-asset, expo-pwa, expo-keep-awake, expo-constants, ...)
67
- npm ERR!
68
- npm ERR! Could not resolve dependency:
69
- npm ERR! peer expo@"^49.0.7 || ^50.0.0-0" from @expo/webpack-config@19.0.1
70
- npm ERR! node_modules/@expo/webpack-config
71
- npm ERR! @expo/webpack-config@"^19.0.1" from the root project
72
- npm ERR!
73
- npm ERR! Conflicting peer dependency: expo@50.0.21
74
- npm ERR! node_modules/expo
75
- npm ERR! peer expo@"^49.0.7 || ^50.0.0-0" from @expo/webpack-config@19.0.1
76
- npm ERR! node_modules/@expo/webpack-config
77
- npm ERR! @expo/webpack-config@"^19.0.1" from the root project
78
- npm ERR!
79
- npm ERR! Fix the upstream dependency conflict, or retry
80
- npm ERR! this command with --force or --legacy-peer-deps
81
- npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
82
- npm ERR!
83
- npm ERR!
84
- npm ERR! For a full report see:
85
- npm ERR! .npm/_logs/2025-05-24T00_43_01_748Z-eresolve-report.txt
86
-
87
- npm ERR! A complete log of this run can be found in: .npm/_logs/2025-05-24T00_43_01_748Z-debug-0.log
89
+
90
+ `enable()` and `disable()` are both parameterless — all configuration comes
91
+ from `ConnectConfig.json`. They're idempotent at the native layer; calling
92
+ `enable()` on an already-running SDK is a no-op.
93
+
94
+ ### 2. Add the `<Connect>` wrapper (declarative, in your tree)
95
+
96
+ Wrap your `NavigationContainer` in `<Connect>` to enable navigation tracking,
97
+ touch capture, and optional keyboard / dialog interception. The wrapper does
98
+ not own SDK lifecycle — that's been done in step 1 — so it can mount, unmount,
99
+ or remount freely without disrupting the session.
100
+
101
+ ```tsx
102
+ import { useNavigationContainerRef, NavigationContainer } from '@react-navigation/native'
103
+ import { Connect } from 'react-native-acoustic-connect-beta'
104
+
105
+ export default function App() {
106
+ const navigationRef = useNavigationContainerRef()
107
+ return (
108
+ <Connect
109
+ navigationRef={navigationRef}
110
+ captureKeyboardEvents
111
+ captureDialogEvents
112
+ >
113
+ <NavigationContainer ref={navigationRef}>
114
+ {/* your screens */}
115
+ </NavigationContainer>
116
+ </Connect>
117
+ )
118
+ }
88
119
  ```
89
120
 
90
- fix issue or you use the following to solve depencencies issues
121
+ `<Connect>` is optional. Apps that only need custom event logging (no automatic
122
+ screen / touch / keyboard tracking) can skip it entirely.
123
+
124
+ ### 3. Log events (imperative, anywhere)
125
+
126
+ ```ts
127
+ import AcousticConnectRN from 'react-native-acoustic-connect-beta'
128
+
129
+ // Custom application event
130
+ AcousticConnectRN.logCustomEvent('checkout_started', { cartId: 'abc' }, 1)
131
+
132
+ // Force a logical screen name (e.g. for non-NavigationContainer screens)
133
+ AcousticConnectRN.setCurrentScreenName('CheckoutScreen')
134
+
135
+ // Manual exception capture
136
+ AcousticConnectRN.logExceptionEvent(
137
+ 'Payment failed',
138
+ err.stack ?? '',
139
+ /* unhandled */ false
140
+ )
91
141
  ```
142
+
143
+ Dialog tracking helpers (`useDialogTracking`, `DialogListener`,
144
+ `withAcousticAutoDialog`) instrument React Native `Alert.alert(...)` and custom
145
+ dialogs automatically. See the
146
+ [developer portal](https://developer.goacoustic.com/acoustic-connect/docs/react-native-integration)
147
+ for details.
148
+
149
+ ## API reference
150
+
151
+ ### `AcousticConnectRN.enable(): boolean`
152
+
153
+ Re-enables the SDK after a prior `disable()`. Reads all configuration from
154
+ `ConnectConfig.json`. Returns `true` on accepted dispatch; `false` only when
155
+ the platform can't satisfy a precondition (e.g. Android without an
156
+ `Application` context yet). Idempotent — the native SDK short-circuits if it's
157
+ already running.
158
+
159
+ > The SDK also auto-initialises at module load using the same configuration,
160
+ > so you typically don't need to call `enable()` at all. The method exists to
161
+ > pair with `disable()` for opt-out / consent flows.
162
+
163
+ ### `AcousticConnectRN.disable(): boolean`
164
+
165
+ Stops data capture, flushes pending messages, releases push state. Idempotent.
166
+
167
+ ### Push configuration (`ConnectConfig.json`)
168
+
169
+ | Field | Type | Default | Semantics |
170
+ | --- | --- | --- | --- |
171
+ | `PushEnabled` | boolean | `false` | Cross-platform master switch. On Android, drives `connect-push-fcm` artifact inclusion at build time. |
172
+ | `iOSPushMode` | `"automatic"` / `"manual"` | `"automatic"` | iOS-only. Ignored when `PushEnabled` is `false`. |
173
+ | `iOSAppGroupIdentifier` | string \| null | `null` | iOS App Group shared with NSE / NCE for rich push payloads. |
174
+ | `AndroidNotificationIconResName` | string \| null | `null` | Drawable resource name for the Android notification small icon. |
175
+
176
+ #### iOS push modes
177
+
178
+ - `"automatic"` — the iOS Connect SDK manages APNs token registration internally. The host app only requests user permission via `UNUserNotificationCenter`; token delivery and forwarding to the Connect backend are handled by the SDK.
179
+ - `"manual"` — the host app owns APNs delegate callbacks (`application(_:didRegisterForRemoteNotificationsWithDeviceToken:)`) and forwards tokens explicitly via `ConnectSDK.shared.push.didRegisterWithToken(token)`.
180
+
181
+ #### Android push
182
+
183
+ The `iOSPushMode` field is iOS-only; Android push is gated solely by
184
+ `PushEnabled`. On Android, FCM requires a `FirebaseMessagingService` subclass
185
+ that the host app declares in its `AndroidManifest.xml`, so push is always
186
+ app-driven. The host app is responsible for:
187
+
188
+ - shipping `google-services.json` in `android/app/`,
189
+ - implementing `FirebaseMessagingService.onNewToken(...)`,
190
+ - forwarding the FCM token to the Connect SDK.
191
+
192
+ The Android push-forwarding API itself is wired under follow-up work — until
193
+ that lands, `PushEnabled: true` on Android only changes which artifact is on
194
+ the classpath; the host-side token forwarding API is not yet exposed.
195
+
196
+ ### `<Connect>` props
197
+
198
+ | Prop | Type | Required | Description |
199
+ | --- | --- | --- | --- |
200
+ | `children` | `ReactNode` | yes | Your `NavigationContainer` (or any subtree). |
201
+ | `navigationRef` | `RefObject` | recommended | Ref from `useNavigationContainerRef()`. Enables screen-name tracking. |
202
+ | `captureKeyboardEvents` | `boolean` | yes | Capture iOS/Android keyboard show/hide events. |
203
+ | `captureDialogEvents` | `boolean` | no (default `false`) | Auto-track `Alert.alert(...)` calls. |
204
+
205
+ ### Other methods
206
+
207
+ The plugin exposes the full Connect SDK surface — custom events, signals,
208
+ exceptions, location, screen layout, click / text-change events, dialog events,
209
+ and config-item getters/setters. Signatures are stable across platforms; see
210
+ `src/specs/react-native-acoustic-connect.nitro.ts` for the typed Nitro spec and
211
+ the
212
+ [developer portal](https://developer.goacoustic.com/acoustic-connect/docs/react-native-integration)
213
+ for end-to-end recipes.
214
+
215
+ ## Migration from earlier versions
216
+
217
+ See [Migration-Guide.md](./Migration-Guide.md) for the steps to move from the
218
+ legacy `NativeModules.AcousticConnectRN` interface to the current ESM exports
219
+ and the `<Connect>` component.
220
+
221
+ ## Troubleshooting
222
+
223
+ ### `npm install` peer-dependency conflicts
224
+
225
+ If `npm install` errors out on a peer-dependency resolution involving Expo or
226
+ older `react-native-nitro-modules` versions, retry with:
227
+
228
+ ```bash
92
229
  npm install react-native-nitro-modules --legacy-peer-deps
93
230
  ```
231
+
232
+ This usually only happens when an existing project pulls in stale Expo
233
+ transitives. Permanent fix: align RN, React, and Nitro versions with the
234
+ [Requirements](#requirements) section above.
235
+
236
+ ### iOS — `pod install` fails with `[Connect] requires AcousticConnect >= 2.0.5`
237
+
238
+ You've pinned an older `iOSVersion` in `ConnectConfig.json`. Bump it to a
239
+ 2.0.5+ release (or leave it empty for the newest available) and re-run
240
+ `pod install`.
241
+
242
+ ### Android — Gradle resolution fails on `io.github.go-acoustic:connect`
243
+
244
+ The strict constraint at `[11.0.11, 12.0.0)` is rejecting your pin. Bump
245
+ `AndroidVersion` in `ConnectConfig.json` to a release within that range (or
246
+ leave it empty for the newest 11.x available). 12.x is intentionally outside
247
+ the supported range pending compatibility validation — track that work
248
+ separately if you need it.
249
+
250
+ ### Gradle can't find `node`
251
+
252
+ Common when Gradle is launched outside an NVM-loaded shell. Either:
253
+
254
+ - Stop the daemon (`./gradlew --stop`) and re-run `npm run android` from a
255
+ shell where `which node` resolves, or
256
+ - Symlink node onto a stable PATH: `ln -sf "$(which node)" /opt/homebrew/bin/node`.
257
+
258
+ ---
259
+
260
+ For more, see the
261
+ [Connect React Native integration guide](https://developer.goacoustic.com/acoustic-connect/docs/react-native-integration)
262
+ and the
263
+ [sample app walk-through](https://developer.goacoustic.com/acoustic-connect/docs/build-a-sample-react-native-app).
@@ -152,6 +152,23 @@ allprojects {
152
152
  }
153
153
  }
154
154
 
155
+ // Read consumer config at script-evaluation time so the right Connect Android
156
+ // artifact is selected without depending on config.gradle's text-rewriting
157
+ // pass (which only matches the analytics artifact name). Both `PushEnabled`
158
+ // and `AndroidVersion` are read directly here:
159
+ // - `PushEnabled` picks between the analytics-only and push-fcm artifacts.
160
+ // - `AndroidVersion` (when set) pins the version against the active artifact.
161
+ import groovy.json.JsonSlurper
162
+ def acousticConfigFile = new File("$rootDir/../ConnectConfig.json")
163
+ def acousticConfig = acousticConfigFile.exists()
164
+ ? new JsonSlurper().parse(acousticConfigFile)
165
+ : [Connect: [:]]
166
+ def acousticPushEnabled = (acousticConfig.Connect?.PushEnabled ?: false).toString().toBoolean()
167
+ def acousticVersionPin = (acousticConfig.Connect?.AndroidVersion ?: '').trim()
168
+ def acousticVersion = acousticVersionPin.isEmpty() ? '+' : acousticVersionPin
169
+ def acousticArtifact = acousticPushEnabled ? 'connect-push-fcm' : 'connect'
170
+ println "AcousticConnectRN: PushEnabled=$acousticPushEnabled, artifact=io.github.go-acoustic:$acousticArtifact:$acousticVersion"
171
+
155
172
  dependencies {
156
173
  // Provided by the host app at runtime — compileOnly avoids version conflicts
157
174
  //noinspection GradleDynamicVersion
@@ -160,8 +177,36 @@ dependencies {
160
177
  // Provided by the host app via react-native-nitro-modules peer dependency
161
178
  compileOnly project(":react-native-nitro-modules")
162
179
 
163
- // Connect SDK — version overridden by config.gradle based on ConnectConfig.json
164
- implementation 'io.github.go-acoustic:connect:10.4.29'
180
+ // Connect Android SDK — analytics-only artifact OR push variant, never both.
181
+ // The push-fcm artifact transitively brings in the core analytics module;
182
+ // declaring both as direct dependencies would risk duplicate-class errors
183
+ // and ambiguous version resolution. The selection is structural and gated
184
+ // at build time by `ConnectConfig.json -> Connect.PushEnabled` — a customer
185
+ // who didn't opt in for push can't accidentally pull in FCM transitives,
186
+ // and a customer who did opt in gets the right module without a second
187
+ // toggle.
188
+ //noinspection GradleDynamicVersion
189
+ implementation "io.github.go-acoustic:$acousticArtifact:$acousticVersion"
190
+
191
+ // Version range enforced by the RN bridge. Lower bound prevents downgrades
192
+ // to releases that lack APIs this bridge calls; upper bound prevents a
193
+ // future 12.x major (with potentially breaking changes) from being picked
194
+ // up automatically by Gradle's `+` resolver. Both halves are `strictly` so
195
+ // an attempted override via `Connect.AndroidVersion` fails loudly at
196
+ // resolution time rather than surfacing as a runtime `ClassNotFoundException`
197
+ // or method-missing error. Constraints are declared for both artifact
198
+ // names — Gradle only enforces the one that resolves into the graph, so
199
+ // the unused entry is inert.
200
+ constraints {
201
+ implementation('io.github.go-acoustic:connect') {
202
+ version { strictly '[11.0.11, 12.0.0)' }
203
+ because 'AcousticConnectRN requires Connect Android SDK in [11.0.11, 12.0.0). Bump the upper bound after validating compatibility with a new major.'
204
+ }
205
+ implementation('io.github.go-acoustic:connect-push-fcm') {
206
+ version { strictly '[11.0.11, 12.0.0)' }
207
+ because 'connect-push-fcm tracks the same release line as the core connect artifact.'
208
+ }
209
+ }
165
210
  }
166
211
 
167
212
  if (isNewArchitectureEnabled()) {
@@ -1,5 +1,5 @@
1
1
  AcousticConnectRN_kotlinVersion=2.0.21
2
- AcousticConnectRN_minSdkVersion=23
3
- AcousticConnectRN_targetSdkVersion=34
4
- AcousticConnectRN_compileSdkVersion=34
2
+ AcousticConnectRN_minSdkVersion=26
3
+ AcousticConnectRN_targetSdkVersion=36
4
+ AcousticConnectRN_compileSdkVersion=36
5
5
  AcousticConnectRN_ndkVersion=27.1.12297006
@@ -24,7 +24,7 @@
24
24
  "IpPlaceholder": "N/A",
25
25
  "KillSwitchAsync": true,
26
26
  "KillSwitchDelay": 300,
27
- "LibraryVersion": "11.0.9-beta",
27
+ "LibraryVersion": "11.0.12-beta",
28
28
  "LogFullRequestResponsePayloads": true,
29
29
  "MessageTypeHeader": "WorklightHit",
30
30
  "MessageTypes": "4,5",
@@ -1,4 +1,4 @@
1
- #Tue Apr 28 02:21:07 PDT 2026
1
+ #Tue May 26 07:16:53 PDT 2026
2
2
  UseWhiteList=true
3
3
  PrintScreen=3
4
4
  UseRandomSample=false
@@ -24,7 +24,7 @@
24
24
  "IpPlaceholder": "N/A",
25
25
  "KillSwitchAsync": true,
26
26
  "KillSwitchDelay": 300,
27
- "LibraryVersion": "10.4.28-beta",
27
+ "LibraryVersion": "10.4.29-beta",
28
28
  "LogFullRequestResponsePayloads": true,
29
29
  "MessageTypeHeader": "WorklightHit",
30
30
  "MessageTypes": "4,5",
@@ -12,9 +12,6 @@
12
12
 
13
13
  package com.acousticconnectrn;
14
14
 
15
- import android.os.Handler;
16
- import android.os.Looper;
17
- import android.util.Log;
18
15
  import androidx.annotation.Nullable;
19
16
  import androidx.annotation.NonNull;
20
17
 
@@ -22,7 +19,6 @@ import com.facebook.react.bridge.NativeModule;
22
19
  import com.facebook.react.bridge.ReactApplicationContext;
23
20
  import com.facebook.react.module.model.ReactModuleInfoProvider;
24
21
  import com.facebook.react.TurboReactPackage;
25
- import com.margelo.nitro.NitroModules;
26
22
  import com.margelo.nitro.acousticconnectrn.AcousticConnectRNOnLoad;
27
23
 
28
24
  import java.util.HashMap;
@@ -41,34 +37,15 @@ public class AcousticConnectRNPackage extends TurboReactPackage {
41
37
  }
42
38
 
43
39
  static {
40
+ // Nitro's C++ factory (AcousticConnectRNOnLoad.cpp) constructs instances
41
+ // of HybridAcousticConnectRN itself via a zero-arg constructor, lazily on
42
+ // first JS call. Earlier versions of this file spun up a background
43
+ // thread to poll NitroModules.getApplicationContext() and eagerly
44
+ // construct one instance — that workaround was masking the symptom of
45
+ // the bridge holding a stored ReactApplicationContext field that Nitro's
46
+ // factory then passed as null. The bridge now resolves the React context
47
+ // on-demand from NitroModules.applicationContext (nullable, guarded), so
48
+ // no eager construction is needed.
44
49
  AcousticConnectRNOnLoad.initializeNative();
45
- try {
46
- // Start a background thread to wait for the context
47
- new Thread(() -> {
48
- ReactApplicationContext reactContext = null;
49
-
50
- // Poll until NitroModules.getApplicationContext() is not null
51
- while (reactContext == null) {
52
- reactContext = NitroModules.getApplicationContext();
53
- if (reactContext == null) {
54
- try {
55
- Thread.sleep(100); // Sleep for 100ms before checking again
56
- } catch (InterruptedException e) {
57
- Log.e("AcousticConnectRNPackage", "Thread interrupted while waiting for ReactApplicationContext.", e);
58
- return;
59
- }
60
- }
61
- }
62
-
63
- // Post initialization logic to the main (UI) thread
64
- ReactApplicationContext finalReactContext = reactContext;
65
- new Handler(Looper.getMainLooper()).post(() -> {
66
- HybridAcousticConnectRN hybridInstance = new HybridAcousticConnectRN(finalReactContext);
67
- Log.i("AcousticConnectRNPackage", "HybridAcousticConnectRN initialized successfully.");
68
- });
69
- }).start();
70
- } catch (Exception e) {
71
- Log.e("AcousticConnectRNPackage", "Failed to initialize HybridAcousticConnectRN.", e);
72
- }
73
50
  }
74
51
  }