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.
- package/CHANGELOG.md +6 -0
- package/ConnectConfig.example.json +1 -1
- package/Examples/SampleUI/ConnectConfig.json +2 -2
- package/README.md +164 -1
- package/android/build.gradle +64 -0
- package/android/config.gradle +123 -12
- package/android/src/main/assets/ConnectAdvancedConfig.json +1 -1
- package/android/src/main/assets/ConnectBasicConfig.properties +1 -1
- package/android/src/main/java/com/acousticconnectrn/HybridAcousticConnectRN.kt +210 -20
- package/ios/ConnectRNParsing.swift +229 -0
- package/ios/HybridAcousticConnectRN.swift +125 -27
- package/lib/commonjs/TLTRN.js +26 -3
- package/lib/commonjs/TLTRN.js.map +1 -1
- package/lib/commonjs/index.js +3 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/TLTRN.js +26 -3
- package/lib/module/TLTRN.js.map +1 -1
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/TLTRN.d.ts +22 -1
- package/lib/typescript/src/TLTRN.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts +150 -10
- package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.cpp +5 -9
- package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.hpp +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/acousticconnectrn/HybridAcousticConnectRNSpec.kt +2 -1
- package/nitrogen/generated/ios/AcousticConnectRN-Swift-Cxx-Umbrella.hpp +1 -0
- package/nitrogen/generated/ios/c++/HybridAcousticConnectRNSpecSwift.hpp +2 -1
- package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec_cxx.swift +2 -25
- package/nitrogen/generated/shared/c++/HybridAcousticConnectRNSpec.hpp +2 -1
- package/package.json +2 -1
- package/src/TLTRN.ts +31 -3
- package/src/index.ts +5 -0
- 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.
|
|
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":
|
|
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":
|
|
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 |
|
package/android/build.gradle
CHANGED
|
@@ -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
|
package/android/config.gradle
CHANGED
|
@@ -150,7 +150,33 @@ def updateConnectBasicConfig(mp, json) {
|
|
|
150
150
|
println("Updating:$propertiesFile")
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
|
|
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
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
310
|
+
overrides[config_key] = config_value
|
|
227
311
|
}
|
|
228
312
|
}
|
|
229
313
|
}
|
|
230
314
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
27
|
+
"LibraryVersion": "11.0.21-beta",
|
|
28
28
|
"LogFullRequestResponsePayloads": true,
|
|
29
29
|
"MessageTypeHeader": "WorklightHit",
|
|
30
30
|
"MessageTypes": "4,5",
|