react-native-acoustic-connect-beta 19.0.14 → 19.0.16

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 (37) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/ConnectConfig.example.json +1 -1
  3. package/Examples/SampleUI/ConnectConfig.json +2 -2
  4. package/README.md +164 -1
  5. package/android/build.gradle +64 -0
  6. package/android/config.gradle +123 -12
  7. package/android/src/main/assets/ConnectAdvancedConfig.json +1 -1
  8. package/android/src/main/assets/ConnectBasicConfig.properties +1 -1
  9. package/android/src/main/java/com/acousticconnectrn/HybridAcousticConnectRN.kt +210 -20
  10. package/ios/ConnectRNParsing.swift +229 -0
  11. package/ios/HybridAcousticConnectRN.swift +125 -27
  12. package/lib/commonjs/TLTRN.js +26 -3
  13. package/lib/commonjs/TLTRN.js.map +1 -1
  14. package/lib/commonjs/index.js +3 -0
  15. package/lib/commonjs/index.js.map +1 -1
  16. package/lib/module/TLTRN.js +26 -3
  17. package/lib/module/TLTRN.js.map +1 -1
  18. package/lib/module/index.js +5 -0
  19. package/lib/module/index.js.map +1 -1
  20. package/lib/typescript/src/TLTRN.d.ts +22 -1
  21. package/lib/typescript/src/TLTRN.d.ts.map +1 -1
  22. package/lib/typescript/src/index.d.ts +1 -0
  23. package/lib/typescript/src/index.d.ts.map +1 -1
  24. package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts +150 -10
  25. package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts.map +1 -1
  26. package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.cpp +5 -9
  27. package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.hpp +1 -1
  28. package/nitrogen/generated/android/kotlin/com/margelo/nitro/acousticconnectrn/HybridAcousticConnectRNSpec.kt +2 -1
  29. package/nitrogen/generated/ios/AcousticConnectRN-Swift-Cxx-Umbrella.hpp +1 -0
  30. package/nitrogen/generated/ios/c++/HybridAcousticConnectRNSpecSwift.hpp +2 -1
  31. package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec.swift +1 -1
  32. package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec_cxx.swift +2 -25
  33. package/nitrogen/generated/shared/c++/HybridAcousticConnectRNSpec.hpp +2 -1
  34. package/package.json +2 -1
  35. package/src/TLTRN.ts +31 -3
  36. package/src/index.ts +5 -0
  37. package/src/specs/react-native-acoustic-connect.nitro.ts +152 -10
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 19.0.16 (2026-08-31)
2
+
3
+ ### Reverts
4
+
5
+ * Revert "Beta ReactNativeConnect build: 18.0.36" ([609ad7d](https://github.com/aipoweredmarketer/react-native-acoustic-connect-beta/commit/609ad7d3244ec06f27dced5864d40585c5b3c9cf))
6
+ ## [19.0.15](https://github.com/aipoweredmarketer/react-native-acoustic-connect-beta/compare/19.0.14...19.0.15) (2026-08-24)
1
7
  ## 19.0.14 (2026-07-31)
2
8
 
3
9
  ### Reverts
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "Connect": {
3
3
  "AndroidNotificationIconResName": "ic_notification",
4
- "AndroidVersion": "11.0.16-beta",
4
+ "AndroidVersion": "11.0.21-beta",
5
5
  "AppKey": "YOUR_CONNECT_APP_KEY_HERE",
6
6
  "KillSwitchUrl": "YOUR_KILL_SWITCH_URL_HERE",
7
7
  "PostMessageUrl": "YOUR_POST_MESSAGE_URL_HERE",
@@ -56,7 +56,7 @@
56
56
  "ScreenShot": false
57
57
  },
58
58
  "GlobalScreenSettings": {
59
- "CaptureLayoutDelay": 1,
59
+ "CaptureLayoutDelay": 500,
60
60
  "CaptureLayoutOn": 2,
61
61
  "CaptureScreenVisits": false,
62
62
  "CaptureScreenshotOn": 2,
@@ -141,7 +141,7 @@
141
141
  "ScreenShot": false
142
142
  },
143
143
  "GlobalScreenSettings": {
144
- "CaptureLayoutDelay": 1,
144
+ "CaptureLayoutDelay": 500,
145
145
  "CaptureLayoutOn": 2,
146
146
  "CaptureScreenVisits": false,
147
147
  "CaptureScreenshotOn": 2,
package/README.md CHANGED
@@ -365,9 +365,18 @@ screen / touch / keyboard tracking) can skip it entirely.
365
365
  ```ts
366
366
  import AcousticConnectRN from 'react-native-acoustic-connect-beta'
367
367
 
368
- // Custom application event
368
+ // Custom application event (flat key/value pairs)
369
369
  AcousticConnectRN.logCustomEvent('checkout_started', { cartId: 'abc' }, 1)
370
370
 
371
+ // Signal — accepts arbitrary JSON, including nested objects and arrays
372
+ AcousticConnectRN.logSignal(
373
+ {
374
+ signalContent: { signalType: 'pageview', pageCategory: 'checkout' },
375
+ audience: [{ name: 'Account ID', value: '4815162342' }],
376
+ },
377
+ 1
378
+ )
379
+
371
380
  // Force a logical screen name (e.g. for non-NavigationContainer screens)
372
381
  AcousticConnectRN.setCurrentScreenName('CheckoutScreen')
373
382
 
@@ -403,6 +412,66 @@ already running.
403
412
 
404
413
  Stops data capture, flushes pending messages, releases push state. Idempotent.
405
414
 
415
+ ### `AcousticConnectRN.logSignal(values, level): boolean`
416
+
417
+ Logs a signal. `values` accepts **arbitrary JSON** — nested objects and arrays,
418
+ not just scalars — and the payload is carried through without flattening or
419
+ reshaping:
420
+
421
+ ```ts
422
+ AcousticConnectRN.logSignal(
423
+ {
424
+ signalContent: {
425
+ signalType: 'pageview',
426
+ url: 'https://app.example.com/dashboard',
427
+ pageCategory: 'dashboard',
428
+ },
429
+ audience: [
430
+ { name: 'Account Name', value: 'Acme Corp' },
431
+ { name: 'Account ID', value: '4815162342' },
432
+ ],
433
+ },
434
+ 1
435
+ )
436
+ ```
437
+
438
+ Flat scalar payloads keep working unchanged — the type is a superset of
439
+ `Record<string, string | number | boolean>`.
440
+
441
+ An object literal needs no type import. If you want to *name* a payload — a
442
+ shared constant, a helper parameter — the package exports `SignalValues` for it:
443
+
444
+ ```ts
445
+ import AcousticConnectRN, {
446
+ type SignalValues,
447
+ } from 'react-native-acoustic-connect-beta'
448
+
449
+ const pageView: SignalValues = {
450
+ signalContent: { signalType: 'pageview', pageCategory: 'checkout' },
451
+ }
452
+
453
+ AcousticConnectRN.logSignal(pageView, 1)
454
+ ```
455
+
456
+ > **Android: send numbers nested, not at the top level.** The Android SDK's
457
+ > signal serializer carries strings, booleans, objects and arrays at the top
458
+ > level of the payload but drops a top-level numeric value. Numbers nested
459
+ > inside an object or array are unaffected. iOS carries top-level numbers
460
+ > normally, so put numbers one level down when you need both platforms to agree:
461
+ >
462
+ > ```ts
463
+ > AcousticConnectRN.logSignal({ cart: { items: 3 } }, 1) // both platforms
464
+ > AcousticConnectRN.logSignal({ items: 3 }, 1) // iOS only
465
+ > ```
466
+
467
+ ### `AcousticConnectRN.logCustomEvent(eventName, values, level): boolean`
468
+
469
+ Logs a named custom event. Unlike `logSignal`, `values` is **flat** — strings,
470
+ numbers and booleans only. The Android SDK's custom-event path is typed for
471
+ string values end to end, so there is no native route for nested JSON; widening
472
+ it would preserve the nesting on iOS and silently drop it on Android. Use
473
+ `logSignal` when the payload needs structure.
474
+
406
475
  ### Push configuration (`ConnectConfig.json`)
407
476
 
408
477
  | Field | Type | Default | Semantics |
@@ -438,6 +507,100 @@ The Android push-forwarding API itself is wired under follow-up work — until
438
507
  that lands, `PushEnabled: true` on Android only changes which artifact is on
439
508
  the classpath; the host-side token forwarding API is not yet exposed.
440
509
 
510
+ ### Screen-capture configuration (`ConnectConfig.json`)
511
+
512
+ Screen layout and screenshot capture are configured per platform, because the
513
+ two native SDKs read their defaults from different places.
514
+
515
+ | Field | Type | Default | Semantics |
516
+ | --- | --- | --- | --- |
517
+ | `layoutConfig` | object \| absent | absent | Shared baseline for both platforms. Supports `AutoLayout` (screen capture rules) and `AppendMapIds`. |
518
+ | `layoutConfigIos` | object \| absent | absent | iOS-specific overrides, deep-merged over `layoutConfig`. |
519
+ | `layoutConfigAndroid` | object \| absent | absent | Android-specific overrides, deep-merged over `layoutConfig`. |
520
+ | `GetImageDataOnScreenLayout` | boolean | SDK default | Cross-platform. When `false`, layout messages carry no screenshot image data. |
521
+
522
+ `AutoLayout` holds a `GlobalScreenSettings` object plus optional per-screen
523
+ overrides keyed by screen name, where a per-screen value wins over the global
524
+ one. To turn screenshot capture off on both platforms:
525
+
526
+ ```json
527
+ {
528
+ "Connect": {
529
+ "layoutConfig": {
530
+ "AutoLayout": {
531
+ "GlobalScreenSettings": { "ScreenShot": false, "CaptureScreenshotOn": 0 }
532
+ }
533
+ }
534
+ }
535
+ }
536
+ ```
537
+
538
+ Put anything common in `layoutConfig` and use `layoutConfigIos` /
539
+ `layoutConfigAndroid` only for what differs. The platform block is **deep-merged**
540
+ over the shared one, so it refines the baseline rather than replacing it: an
541
+ iOS block setting just `ScreenShot` keeps the shared `Masking`, per-screen
542
+ rules, and every other shared value. Arrays are replaced outright rather than
543
+ concatenated, so a platform block can shorten or clear a shared list such as
544
+ `MaskIdList`.
545
+
546
+ When no block applies, each native SDK keeps the defaults from its own bundled
547
+ layout config:
548
+
549
+ - **iOS** — the defaults ship inside the Connect pod's `ConnectResources.bundle`
550
+ and are copied into your `.app`, so `pod install` replaces them on every run.
551
+ There is no app-level override file, which is why `ConnectConfig.json` is the
552
+ only supported route — do not edit anything under `Pods/`.
553
+ - **Android** — the plugin writes your merged block to its own
554
+ `ConnectLayoutConfig.json` asset. If your app ships
555
+ `android/app/src/main/assets/ConnectLayoutConfig.json`, Android asset merging
556
+ gives **your** copy priority and the `ConnectConfig.json` block is ignored;
557
+ the build prints a warning when both exist. Keep one or the other.
558
+
559
+ > Turning screenshots off does not disable behavioural capture: screen views,
560
+ > clicks, and custom events still flow. It only drops the image data, which is
561
+ > what a subscription without session replay has no consumer for.
562
+
563
+ #### Capture timing (`CaptureLayoutDelay`)
564
+
565
+ `AutoLayout.GlobalScreenSettings.CaptureLayoutDelay` is how long, in
566
+ milliseconds, the SDK waits before capturing the layout. It matters more in
567
+ React Native than in a native app: the wrapper triggers capture from React
568
+ Navigation's state change, which fires at the *start* of a screen transition,
569
+ whereas a native app captures from the view-controller lifecycle, after it. Too
570
+ short a delay and the capture catches a half-drawn screen.
571
+
572
+ The templates ship `500`, which clears a typical transition animation on both
573
+ platforms. Tune it globally, or per screen for one that is slower than the
574
+ rest:
575
+
576
+ ```json
577
+ {
578
+ "Connect": {
579
+ "layoutConfig": {
580
+ "AutoLayout": {
581
+ "GlobalScreenSettings": { "CaptureLayoutDelay": 500 },
582
+ "Checkout": { "CaptureLayoutDelay": 900 }
583
+ }
584
+ }
585
+ }
586
+ }
587
+ ```
588
+
589
+ `TLTRN.logScreenLayout(name)` uses the configured value. Pass a second argument
590
+ to override it for one call — `TLTRN.logScreenLayout(name, 0)` captures
591
+ immediately, `TLTRN.logScreenLayout(name, 900)` waits 900 ms.
592
+
593
+ A fixed delay cannot cover a screen whose content arrives asynchronously: if
594
+ data lands after the delay elapses, the capture shows the screen without it.
595
+ Raising the global delay to cover the slowest fetch delays every other screen
596
+ too. Call `TLTRN.logScreenLayout(name)` again when the content is on screen
597
+ instead — each call captures the layout as it stands at that moment.
598
+
599
+ Leaving the block out entirely gives you 500 ms as well. That is the wrapper's
600
+ default, chosen so both platforms behave the same; the native SDKs' own bundled
601
+ defaults differ from each other and are tuned for the lifecycle trigger rather
602
+ than the React Navigation one.
603
+
441
604
  ### `<Connect>` props
442
605
 
443
606
  | Prop | Type | Required | Description |
@@ -198,6 +198,34 @@ def acousticPushEnabled = (acousticConfig.Connect?.PushEnabled ?: false).toStrin
198
198
  def acousticVersionPin = (acousticConfig.Connect?.AndroidVersion ?: '').trim()
199
199
  def acousticVersion = acousticVersionPin.isEmpty() ? '+' : acousticVersionPin
200
200
  def acousticArtifact = acousticPushEnabled ? 'connect-push-fcm' : 'connect'
201
+
202
+ // Connect co-versions `eocore` + `tealeaf` with itself only from 11.0.18-beta
203
+ // onward — and from that release their POM scope is `runtime`, which drops them
204
+ // off the compile classpath (see the companion declarations below).
205
+ //
206
+ // Earlier releases in the supported range ship `tealeaf` on its own 10.4.x line
207
+ // (with eocore arriving transitively through it) at COMPILE scope, so there the
208
+ // companions are both unnecessary AND unresolvable: eocore/tealeaf 11.0.16-beta
209
+ // simply do not exist on Maven Central. Guard on the explicit pin so a consumer
210
+ // who pinned an older Connect keeps building. An empty pin means `+`, which
211
+ // always resolves to the newest (co-versioned) release.
212
+ def acousticCompanionsRequired = true
213
+ if (!acousticVersionPin.isEmpty()) {
214
+ // Compare only the numeric core, ignoring any -beta/+build qualifier: a
215
+ // 11.0.18-beta pin must count as >= the 11.0.18 floor. Encoded as one integer
216
+ // because Groovy's <=> does not compare two ArrayLists.
217
+ def core = acousticVersionPin.replaceAll(/[-+].*$/, '').tokenize('.')
218
+ def nums = (0..2).collect { i -> (i < core.size() && core[i].isInteger()) ? core[i].toInteger() : 0 }
219
+ // Upper bound as well as lower, so that a pin outside the supported range
220
+ // fails on the `strictly '[11.0.11, 12.0.0)'` constraint in the
221
+ // `constraints { }` block at the bottom of `dependencies` — which names both
222
+ // the range and the reason — rather than on an unresolvable companion
223
+ // coordinate. Verified: without this bound a 12.0.0 pin reported
224
+ // "Could not find io.github.go-acoustic:eocore:12.0.0", burying the real cause.
225
+ def pinCode = nums[0] * 1000000 + nums[1] * 1000 + nums[2]
226
+ acousticCompanionsRequired = pinCode >= 11_000_018 && pinCode < 12_000_000
227
+ }
228
+ println "AcousticConnectRN: companionCompileDeps=$acousticCompanionsRequired (pin='$acousticVersionPin')"
201
229
  println "AcousticConnectRN: PushEnabled=$acousticPushEnabled, artifact=io.github.go-acoustic:$acousticArtifact:$acousticVersion"
202
230
 
203
231
  dependencies {
@@ -219,6 +247,42 @@ dependencies {
219
247
  //noinspection GradleDynamicVersion
220
248
  implementation "io.github.go-acoustic:$acousticArtifact:$acousticVersion"
221
249
 
250
+ // Restore the compile classpath for Connect's internal modules. This bridge
251
+ // calls into both directly — `com.ibm.eo.EOCore`,
252
+ // `com.ibm.eo.model.EOMonitoringLevel`, `com.tl.uic.Tealeaf`,
253
+ // `com.tl.uic.model.ScreenviewType`,
254
+ // `com.tl.uic.util.{DialogUtil,LayoutUtil,keyboardview.KeyboardView}` — so
255
+ // with them at `runtime` scope `compileDebugKotlin` fails with ~34
256
+ // "Unresolved reference 'ibm' / 'tl' / 'EOCore'" errors.
257
+ //
258
+ // compileOnly, not implementation: the artifacts still reach the runtime graph
259
+ // through Connect's own transitive, so declaring them there too would risk a
260
+ // second, independently-resolved copy.
261
+ //
262
+ // Both scopes are required — compileOnly does NOT propagate to the unit-test
263
+ // compile classpath, and android/src/test imports com.ibm.eo.* as well, so
264
+ // compileDebugUnitTestKotlin fails without the testCompileOnly pair.
265
+ //
266
+ // Correct for BOTH artifact variants. `connect-push-fcm` does not declare
267
+ // eocore/tealeaf itself — its POM depends on `connect` at compile scope, and
268
+ // eocore/tealeaf reach the graph through that at `runtime` scope, so the
269
+ // compile classpath is short of them exactly as in the analytics-only case.
270
+ // The variants are co-versioned (connect-push-fcm 11.0.18-beta -> connect
271
+ // 11.0.18-beta -> eocore/tealeaf 11.0.18-beta), so `$acousticVersion` is the
272
+ // right coordinate either way. Confirmed on debugCompileClasspath with
273
+ // PushEnabled=true; gating these on `!acousticPushEnabled` would break the
274
+ // push variant rather than protect it.
275
+ if (acousticCompanionsRequired) {
276
+ //noinspection GradleDynamicVersion
277
+ compileOnly "io.github.go-acoustic:eocore:$acousticVersion"
278
+ //noinspection GradleDynamicVersion
279
+ compileOnly "io.github.go-acoustic:tealeaf:$acousticVersion"
280
+ //noinspection GradleDynamicVersion
281
+ testCompileOnly "io.github.go-acoustic:eocore:$acousticVersion"
282
+ //noinspection GradleDynamicVersion
283
+ testCompileOnly "io.github.go-acoustic:tealeaf:$acousticVersion"
284
+ }
285
+
222
286
  // Firebase Cloud Messaging — required by the push variant. The
223
287
  // `connect-push-fcm` AAR calls `com.google.firebase.messaging.*`
224
288
  // (its `FCMPushService` extends `FirebaseMessagingService`) but its
@@ -150,7 +150,33 @@ def updateConnectBasicConfig(mp, json) {
150
150
  println("Updating:$propertiesFile")
151
151
  }
152
152
 
153
- def updateLayoutConfig(mp, json){
153
+ /**
154
+ * Recursively merges `override` onto `base`. Nested objects merge key by key;
155
+ * every other value, arrays included, is replaced outright. Mirrors
156
+ * ConnectRNParsing.deepMerging on iOS so both platforms layer a shared config
157
+ * block and a platform-specific one the same way.
158
+ */
159
+ def deepMergeConfig(base, override) {
160
+ if (!(base instanceof Map) || !(override instanceof Map)) {
161
+ return override
162
+ }
163
+ def merged = [:]
164
+ merged.putAll(base)
165
+ override.each { key, value ->
166
+ if (merged[key] instanceof Map && value instanceof Map) {
167
+ merged[key] = deepMergeConfig(merged[key], value)
168
+ } else {
169
+ merged[key] = value
170
+ }
171
+ }
172
+ return merged
173
+ }
174
+
175
+ def updateLayoutConfig(mp, json, appAssetsDir){
176
+ // ── Legacy file, behaviour unchanged ────────────────────────────────────
177
+ // TealeafLayoutConfig.json is what this script has always written. The
178
+ // Connect SDK does not read it (see below), but it is left exactly as it
179
+ // was so nothing that does read it regresses.
154
180
  def layoutConfigPath = "$mp/src/main/assets/TealeafLayoutConfig.json"
155
181
  def layoutConfigDefaultPath = "$mp/src/main/assets/TealeafLayoutConfigDefault.json"
156
182
  def override = json.Connect.layoutConfig;
@@ -165,13 +191,71 @@ def updateLayoutConfig(mp, json){
165
191
  layoutConfigFile.text = layoutConfigDefaultFile.text
166
192
  }
167
193
  println("Updating:$layoutConfigPath")
194
+
195
+ // ── The file the Connect SDK actually reads ─────────────────────────────
196
+ // EOCore's ConfigService.getConfig composes "<moduleName>LayoutConfig.json"
197
+ // and sets moduleName to "Connect" whenever the Connect class is on the
198
+ // classpath — which it always is here. So the SDK reads
199
+ // ConnectLayoutConfig.json, never the Tealeaf-branded name above.
200
+ //
201
+ // Compose it the same way iOS does: the shared `layoutConfig` block is the
202
+ // base and `layoutConfigAndroid` is deep-merged over it, so a platform
203
+ // value wins key by key while the shared baseline survives.
204
+ def connectLayoutConfigFile = new File("$mp/src/main/assets/ConnectLayoutConfig.json")
205
+ def shared = json.Connect.layoutConfig
206
+ def androidSpecific = json.Connect.layoutConfigAndroid
207
+ def merged = shared
208
+ if (androidSpecific != null) {
209
+ merged = (merged == null) ? androidSpecific : deepMergeConfig(merged, androidSpecific)
210
+ }
211
+
212
+ if (merged != null) {
213
+ connectLayoutConfigFile.text = JsonOutput.prettyPrint(JsonOutput.toJson(merged))
214
+ println("Updating:${connectLayoutConfigFile.path}")
215
+
216
+ // Android asset merging gives the app's own sourceSet priority over a
217
+ // library's, so an app-level copy silently wins over what we just
218
+ // wrote. That is deliberate — integrations that already ship their own
219
+ // file keep working untouched — but it is worth saying out loud,
220
+ // because otherwise the ConnectConfig.json block looks ignored.
221
+ if (appAssetsDir != null) {
222
+ def appAsset = new File(appAssetsDir, "ConnectLayoutConfig.json")
223
+ if (appAsset.exists()) {
224
+ println("**Acoustic WARNING: ${appAsset.path} exists. Android asset merging gives your app's copy priority over the plugin's, so the layout block in ConnectConfig.json will NOT take effect. Keep one or the other, not both.")
225
+ }
226
+ }
227
+ } else if (connectLayoutConfigFile.exists()) {
228
+ // Nothing configured. Remove a file an earlier build wrote so the
229
+ // default inside the Connect artifact applies again. Writing a default
230
+ // copy here instead would shadow the artifact for every consumer and
231
+ // change behaviour for integrations that never asked for an override.
232
+ connectLayoutConfigFile.delete()
233
+ println("Removed:${connectLayoutConfigFile.path} (no layout config in ConnectConfig.json; using the Connect artifact default)")
234
+ }
168
235
  }
169
236
 
170
- def updateTealeafAdvConfig(mp, json) {
171
- def tealeafAdvConfigPath = "$mp/src/main/assets/TealeafAdvancedConfig.json"
172
- println("Reading file $tealeafAdvConfigPath")
173
- def jsonSlurper = new JsonSlurper()
174
- def tealeafAdvConfigData = jsonSlurper.parse(new File(tealeafAdvConfigPath))
237
+ def updateAdvConfig(mp, json) {
238
+ // The overrides are collected once and then written to both advanced-config files.
239
+ //
240
+ // TealeafAdvancedConfig.json is what this script has always written. The Connect SDK
241
+ // does not read it: EOCore's ConfigService.getConfig composes
242
+ // "<moduleName>AdvancedConfig.json" and sets moduleName to "Connect" whenever the
243
+ // Connect class is on the classpath — which it always is here. So every override
244
+ // written only to the Tealeaf-branded name was silently discarded, including
245
+ // GoogleWebViewEnabled and ExtendsGoogleWebViewClient, which are the documented way to
246
+ // opt a WebView out of auto instrumentation. The legacy file is still written so
247
+ // nothing that does read it regresses.
248
+ //
249
+ // Neither file is required. This script runs inside the consumer's build, so a missing
250
+ // asset must not fail it — advanced config is optional by nature, and if the package has
251
+ // been pruned or repackaged without ConnectAdvancedConfig.json the app still runs on the
252
+ // defaults bundled in the SDK's own AAR. Losing the overrides is worth saying out loud,
253
+ // though, which is the difference between the two branches below.
254
+ def advConfigTargets = [
255
+ [path: "$mp/src/main/assets/TealeafAdvancedConfig.json", readBySdk: false],
256
+ [path: "$mp/src/main/assets/ConnectAdvancedConfig.json", readBySdk: true],
257
+ ]
258
+ def overrides = [:]
175
259
 
176
260
  json.each { key, value ->
177
261
  if(key != "Connect"){ return }
@@ -223,14 +307,39 @@ def updateTealeafAdvConfig(mp, json) {
223
307
  config_key == "WebViewDelay" ||
224
308
  config_key == "WebViewSetTagForId" ) {
225
309
  println(config_key + "=" + config_value)
226
- tealeafAdvConfigData[config_key] = config_value
310
+ overrides[config_key] = config_value
227
311
  }
228
312
  }
229
313
  }
230
314
 
231
- def tealeafAdvConfigFile = new File(tealeafAdvConfigPath)
232
- tealeafAdvConfigFile.text = JsonOutput.toJson(tealeafAdvConfigData)
233
- println("Updating:$tealeafAdvConfigPath")
315
+ // Merge into each file rather than replacing it: both carry values this script never
316
+ // sets, most importantly LibraryVersion, which the SDK reports in its X-Tealeaf header.
317
+ def jsonSlurper = new JsonSlurper()
318
+ advConfigTargets.each { target ->
319
+ def advConfigFile = new File(target.path)
320
+
321
+ if (!advConfigFile.exists()) {
322
+ if (target.readBySdk) {
323
+ println("WARNING: Acoustic Connect: ${advConfigFile.name} is not present in " +
324
+ "the SDK package (looked in ${advConfigFile.parent}). That is the file the " +
325
+ "Connect SDK reads its advanced configuration from, so the advanced " +
326
+ "settings in ConnectConfig.json's Connect block will NOT be applied. The " +
327
+ "SDK still runs, on the defaults bundled in its own AAR.")
328
+ } else {
329
+ println("Skipping missing legacy file:${target.path}")
330
+ }
331
+
332
+ return
333
+ }
334
+
335
+ println("Reading file ${target.path}")
336
+ def advConfigData = jsonSlurper.parse(advConfigFile)
337
+ advConfigData.putAll(overrides)
338
+ // Pretty-printed to match how updateLayoutConfig writes its file, and so an SDK
339
+ // upgrade that ships a reformatted asset does not produce a whole-file diff.
340
+ advConfigFile.text = JsonOutput.prettyPrint(JsonOutput.toJson(advConfigData))
341
+ println("Updating:${target.path}")
342
+ }
234
343
  }
235
344
 
236
345
  def updateEOCoreBasicConfig(mp, json) {
@@ -390,9 +499,11 @@ try {
390
499
  println("Step 3:")
391
500
  updateConnectBasicConfig(module_path, configJSONData)
392
501
  println("Step 4:")
393
- updateLayoutConfig(module_path, configJSONData)
502
+ // The app's own assets dir, used only to warn when it shadows what we write.
503
+ def appAssetsDir = new File(project.rootDir, "app/src/main/assets")
504
+ updateLayoutConfig(module_path, configJSONData, appAssetsDir.exists() ? appAssetsDir : null)
394
505
  println("Step 5:")
395
- updateTealeafAdvConfig(module_path, configJSONData)
506
+ updateAdvConfig(module_path, configJSONData)
396
507
  println("Step 6:")
397
508
  updateEOCoreBasicConfig(module_path, configJSONData)
398
509
  println("Step 7:")
@@ -24,7 +24,7 @@
24
24
  "IpPlaceholder": "N/A",
25
25
  "KillSwitchAsync": true,
26
26
  "KillSwitchDelay": 300,
27
- "LibraryVersion": "11.0.16-beta",
27
+ "LibraryVersion": "11.0.21-beta",
28
28
  "LogFullRequestResponsePayloads": true,
29
29
  "MessageTypeHeader": "WorklightHit",
30
30
  "MessageTypes": "4,5",
@@ -1,4 +1,4 @@
1
- #Fri Jul 31 01:33:07 PDT 2026
1
+ #Mon Aug 31 14:13:24 GMT 2026
2
2
  UseWhiteList=true
3
3
  PrintScreen=3
4
4
  UseRandomSample=false