@advenue/react-native 0.7.0 → 0.9.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.
- package/README.md +5 -0
- package/android/src/main/java/expo/modules/advenue/AdvenueAndroidModule.kt +48 -4
- package/dist/index.cjs +116 -22
- package/dist/index.d.cts +71 -20
- package/dist/index.d.ts +71 -20
- package/dist/index.js +117 -23
- package/ios/AdvenueIosModule.swift +31 -0
- package/package.json +3 -3
- package/src/aem.ts +33 -0
- package/src/deep-links.ts +11 -2
- package/src/index.ts +193 -45
- package/src/native-types.ts +36 -3
package/README.md
CHANGED
|
@@ -33,6 +33,11 @@ await Advenue.initialize({
|
|
|
33
33
|
Advenue.track('signup_completed', { plan: 'pro' });
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
> The `adv_` event-name prefix (e.g. `adv_meta_aem`) is reserved for
|
|
37
|
+
> Advenue-internal signals — don't name your own custom events with it. Such
|
|
38
|
+
> events are still accepted by `track()` (the pipeline relies on them) but are
|
|
39
|
+
> hidden from analytics surfaces like the dashboard's funnel event picker.
|
|
40
|
+
|
|
36
41
|
## Deep links (Universal Links / App Links)
|
|
37
42
|
|
|
38
43
|
Add the config plugin so install-time deep links resolve on device:
|
|
@@ -215,10 +215,12 @@ class AdvenueAndroidModule : Module() {
|
|
|
215
215
|
|
|
216
216
|
// Play Integrity Standard API — device attestation (G3.1n).
|
|
217
217
|
//
|
|
218
|
-
// `requestHash` MUST be sha256_hex("<
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
218
|
+
// `requestHash` MUST be sha256_hex("<deviceId>") — lowercase hex of SHA-256
|
|
219
|
+
// over the device id alone. The server's mapIntegrityVerdict re-derives the
|
|
220
|
+
// same string and compares it to the token's requestHash field; the strings
|
|
221
|
+
// must match byte-for-byte. No app id is hashed in: the token is decoded
|
|
222
|
+
// against this app's Play package name and must be PLAY_RECOGNIZED, which
|
|
223
|
+
// binds the app already.
|
|
222
224
|
//
|
|
223
225
|
// The provider is warmed in OnCreate (above). If it is null — because the
|
|
224
226
|
// manifest meta-data key is absent, Play Integrity is unsupported, or warming
|
|
@@ -284,6 +286,25 @@ class AdvenueAndroidModule : Module() {
|
|
|
284
286
|
|
|
285
287
|
val ctx = appContext.reactContext?.applicationContext
|
|
286
288
|
if (ctx != null) {
|
|
289
|
+
// Meta CAPI extinfo slots 1-3. versionName is the user-facing version
|
|
290
|
+
// (slot 2, surfaced as the event's appVersion); the version code is the
|
|
291
|
+
// build identifier (slot 3). Best-effort: a missing PackageInfo must
|
|
292
|
+
// not cost the caller the rest of the device metadata.
|
|
293
|
+
map["packageName"] = ctx.packageName
|
|
294
|
+
try {
|
|
295
|
+
val pi = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
|
|
296
|
+
pi.versionName?.let { map["shortVersion"] = it }
|
|
297
|
+
@Suppress("DEPRECATION")
|
|
298
|
+
val code =
|
|
299
|
+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
|
|
300
|
+
pi.longVersionCode
|
|
301
|
+
} else {
|
|
302
|
+
pi.versionCode.toLong()
|
|
303
|
+
}
|
|
304
|
+
map["longVersion"] = code.toString()
|
|
305
|
+
} catch (_: Exception) {
|
|
306
|
+
// package info best-effort
|
|
307
|
+
}
|
|
287
308
|
try {
|
|
288
309
|
val dm = ctx.resources.displayMetrics
|
|
289
310
|
map["screenWidth"] = dm.widthPixels
|
|
@@ -327,6 +348,29 @@ class AdvenueAndroidModule : Module() {
|
|
|
327
348
|
sdkPrefs()?.edit()?.remove(key)?.apply()
|
|
328
349
|
}
|
|
329
350
|
|
|
351
|
+
// IAB TCF v2 data a TCF-compliant CMP (e.g. Google UMP) writes to the
|
|
352
|
+
// *default* SharedPreferences ("<package>_preferences", per the TCF spec) —
|
|
353
|
+
// deliberately not our io.advenue.sdk file. Raw values pass through; the
|
|
354
|
+
// TS side (tcfToConsent) owns the policy mapping.
|
|
355
|
+
Function("getTcfData") { ->
|
|
356
|
+
val ctx = appContext.reactContext?.applicationContext ?: return@Function null
|
|
357
|
+
val prefs = ctx.getSharedPreferences(
|
|
358
|
+
"${ctx.packageName}_preferences", android.content.Context.MODE_PRIVATE
|
|
359
|
+
)
|
|
360
|
+
// prefs.all + map lookup: a missing key reads as null (no default value
|
|
361
|
+
// involved), so "missing" and "0" stay distinguishable. `as? Number`
|
|
362
|
+
// tolerates a CMP writing the value as Int OR Long (SharedPreferences
|
|
363
|
+
// has no fixed numeric type per the TCF spec's own contract) without
|
|
364
|
+
// degrading a Long writer to unknown. runCatching stays as the
|
|
365
|
+
// last-resort crash guard.
|
|
366
|
+
val gdprApplies = runCatching {
|
|
367
|
+
(prefs.all["IABTCF_gdprApplies"] as? Number)?.toInt()
|
|
368
|
+
}.getOrNull()
|
|
369
|
+
val purposeConsents = runCatching { prefs.getString("IABTCF_PurposeConsents", null) }.getOrNull()
|
|
370
|
+
if (gdprApplies == null && purposeConsents == null) return@Function null
|
|
371
|
+
mapOf("gdprApplies" to gdprApplies, "purposeConsents" to purposeConsents)
|
|
372
|
+
}
|
|
373
|
+
|
|
330
374
|
// SSAID (ANDROID_ID): signing-key-scoped, stable across reinstalls, reset
|
|
331
375
|
// only by factory reset. Read by the JS facade ONLY when no usable GAID
|
|
332
376
|
// exists, as a first-party fraud/dedup + reinstall-detection signal (Play
|
package/dist/index.cjs
CHANGED
|
@@ -63,6 +63,7 @@ __export(index_exports, {
|
|
|
63
63
|
getIosNative: () => getIosNative,
|
|
64
64
|
parseDirectLink: () => parseDirectLink,
|
|
65
65
|
resolveAdvertisingId: () => resolveAdvertisingId,
|
|
66
|
+
resolveDmaConsent: () => resolveDmaConsent,
|
|
66
67
|
trackInstall: () => trackInstall
|
|
67
68
|
});
|
|
68
69
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -221,7 +222,7 @@ function sha256Hex(message) {
|
|
|
221
222
|
// package.json
|
|
222
223
|
var package_default = {
|
|
223
224
|
name: "@advenue/react-native",
|
|
224
|
-
version: "0.
|
|
225
|
+
version: "0.9.0",
|
|
225
226
|
description: "Advenue MMP React Native SDK \u2014 attribution, install tracking, and deep links (bundled iOS/Android Expo native modules)",
|
|
226
227
|
type: "module",
|
|
227
228
|
license: "MIT",
|
|
@@ -282,6 +283,17 @@ var package_default = {
|
|
|
282
283
|
"react-native": "./dist/index.cjs"
|
|
283
284
|
};
|
|
284
285
|
|
|
286
|
+
// src/aem.ts
|
|
287
|
+
function extractAemCampaignIds(alApplinkData) {
|
|
288
|
+
try {
|
|
289
|
+
const parsed = JSON.parse(alApplinkData);
|
|
290
|
+
const value = typeof parsed.campaign_ids === "string" && parsed.campaign_ids ? parsed.campaign_ids : typeof parsed.extras?.campaign_ids === "string" && parsed.extras.campaign_ids ? parsed.extras.campaign_ids : null;
|
|
291
|
+
return value && value.length <= 2048 ? value : null;
|
|
292
|
+
} catch {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
285
297
|
// src/deep-links.ts
|
|
286
298
|
function parseDirectLink(url) {
|
|
287
299
|
let deepLinkValue = "";
|
|
@@ -307,11 +319,16 @@ function parseDirectLink(url) {
|
|
|
307
319
|
};
|
|
308
320
|
}
|
|
309
321
|
function setupDeepLinks(setup) {
|
|
310
|
-
const
|
|
322
|
+
const deliverDirect = (url) => {
|
|
323
|
+
const link = parseDirectLink(url);
|
|
324
|
+
setup.onDirectUrl?.(url, link);
|
|
325
|
+
setup.onDeepLink(link);
|
|
326
|
+
};
|
|
327
|
+
const listener = setup.addUrlListener(deliverDirect);
|
|
311
328
|
const ready = (async () => {
|
|
312
329
|
const initial = await setup.getInitialURL();
|
|
313
330
|
if (initial) {
|
|
314
|
-
|
|
331
|
+
deliverDirect(initial);
|
|
315
332
|
return;
|
|
316
333
|
}
|
|
317
334
|
const deferred = await setup.resolveDeferred();
|
|
@@ -458,7 +475,29 @@ async function resolveAdvertisingId() {
|
|
|
458
475
|
}
|
|
459
476
|
client.setAdvertisingId({});
|
|
460
477
|
}
|
|
461
|
-
function
|
|
478
|
+
function consentEquals(a, b) {
|
|
479
|
+
return a.isUserSubjectToGDPR === b.isUserSubjectToGDPR && a.hasConsentForDataUsage === b.hasConsentForDataUsage && a.hasConsentForAdsPersonalization === b.hasConsentForAdsPersonalization && a.hasConsentForAdStorage === b.hasConsentForAdStorage;
|
|
480
|
+
}
|
|
481
|
+
function resolveDmaConsent() {
|
|
482
|
+
if (manualConsentSet) return null;
|
|
483
|
+
const native = getIosNative() ?? getAndroidNative();
|
|
484
|
+
if (!native || typeof native.getTcfData !== "function") return null;
|
|
485
|
+
let consent = null;
|
|
486
|
+
try {
|
|
487
|
+
consent = (0, import_sdk_core.tcfToConsent)(native.getTcfData());
|
|
488
|
+
} catch (err) {
|
|
489
|
+
reportError("consent.tcfRead", err);
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
if (!consent) return null;
|
|
493
|
+
const client = active();
|
|
494
|
+
const current = client.getConsentData();
|
|
495
|
+
if (current && consentEquals(current, consent)) return null;
|
|
496
|
+
client.setConsentData(consent);
|
|
497
|
+
void resolveAdvertisingId().catch((err) => reportError("enrich.advertisingId", err));
|
|
498
|
+
return consent;
|
|
499
|
+
}
|
|
500
|
+
function readNativeDeviceInfo(natives) {
|
|
462
501
|
try {
|
|
463
502
|
if (natives.platform === "android" && natives.android?.getDeviceInfo) {
|
|
464
503
|
return natives.android.getDeviceInfo();
|
|
@@ -470,6 +509,10 @@ function collectDeviceInfo(natives) {
|
|
|
470
509
|
}
|
|
471
510
|
return {};
|
|
472
511
|
}
|
|
512
|
+
function collectDeviceInfo(natives) {
|
|
513
|
+
const { shortVersion: _shortVersion, ...info } = readNativeDeviceInfo(natives);
|
|
514
|
+
return info;
|
|
515
|
+
}
|
|
473
516
|
function applyAppState(client, status) {
|
|
474
517
|
if (status === "active") {
|
|
475
518
|
client.notifyAppActive();
|
|
@@ -486,9 +529,12 @@ var INSTALL_SENT_KEY = "advenue.install_sent";
|
|
|
486
529
|
var installInFlight = false;
|
|
487
530
|
var autoInstallPending = false;
|
|
488
531
|
var autoInstallEnabled = true;
|
|
489
|
-
var
|
|
532
|
+
var manualConsentSet = false;
|
|
533
|
+
var tcfCollectionEnabled = false;
|
|
534
|
+
var ATTEST_CHALLENGE_TIMEOUT_MS = 5e3;
|
|
490
535
|
var configuredApiKey = null;
|
|
491
536
|
var configuredEndpoint = import_sdk_core.DEFAULT_ENDPOINT;
|
|
537
|
+
var aemSeenUrlHashes = /* @__PURE__ */ new Set();
|
|
492
538
|
function active() {
|
|
493
539
|
if (!instance) {
|
|
494
540
|
throw new Error("Advenue.initialize() must be called before tracking events.");
|
|
@@ -525,11 +571,19 @@ function fireAutoInstallIfPending() {
|
|
|
525
571
|
}
|
|
526
572
|
var Advenue = {
|
|
527
573
|
async initialize(config) {
|
|
528
|
-
const {
|
|
574
|
+
const {
|
|
575
|
+
mmkv,
|
|
576
|
+
secureStore: secureMod,
|
|
577
|
+
onDeepLink,
|
|
578
|
+
autoTrackInstall,
|
|
579
|
+
tcfDataCollection,
|
|
580
|
+
...rest
|
|
581
|
+
} = config;
|
|
529
582
|
autoInstallPending = false;
|
|
583
|
+
manualConsentSet = false;
|
|
584
|
+
tcfCollectionEnabled = tcfDataCollection === true;
|
|
530
585
|
autoInstallEnabled = autoTrackInstall !== false;
|
|
531
586
|
const platform = resolvePlatform(rest.platform);
|
|
532
|
-
configuredAppId = appId ?? null;
|
|
533
587
|
configuredApiKey = config.apiKey;
|
|
534
588
|
configuredEndpoint = config.endpoint ?? import_sdk_core.DEFAULT_ENDPOINT;
|
|
535
589
|
appStateSub?.remove();
|
|
@@ -544,20 +598,26 @@ var Advenue = {
|
|
|
544
598
|
secureStore = secureMod ? createSecureStore(secureMod) : createNativeSecureStore(iosMod);
|
|
545
599
|
const deviceId = rest.deviceId ?? await (0, import_sdk_core.resolveDurableDeviceId)(storage, secureStore ?? void 0);
|
|
546
600
|
const osVersion = rest.osVersion ?? getOsVersion() ?? void 0;
|
|
601
|
+
const nativeDeviceInfo = readNativeDeviceInfo({
|
|
602
|
+
platform,
|
|
603
|
+
ios: getIosNative(),
|
|
604
|
+
android: getAndroidNative()
|
|
605
|
+
});
|
|
606
|
+
const { shortVersion, ...deviceInfo } = nativeDeviceInfo;
|
|
607
|
+
const appVersion = rest.appVersion ?? shortVersion ?? void 0;
|
|
547
608
|
instance = new import_sdk_core.AdvenueClient({
|
|
548
609
|
...rest,
|
|
549
610
|
platform,
|
|
550
611
|
deviceId,
|
|
551
612
|
storage,
|
|
552
|
-
...osVersion ? { osVersion } : {}
|
|
613
|
+
...osVersion ? { osVersion } : {},
|
|
614
|
+
...appVersion ? { appVersion } : {},
|
|
615
|
+
// Stamped by the SDK, never by the host app — see AdvenueConfig.sdkVersion.
|
|
616
|
+
sdkVersion: package_default.version
|
|
553
617
|
});
|
|
554
618
|
instance.debugLog(`SDK v${package_default.version} \u2014 events -> ${configuredEndpoint}`);
|
|
619
|
+
if (tcfCollectionEnabled) resolveDmaConsent();
|
|
555
620
|
void resolveAdvertisingId().catch((err) => reportError("enrich.advertisingId", err));
|
|
556
|
-
const deviceInfo = collectDeviceInfo({
|
|
557
|
-
platform,
|
|
558
|
-
ios: getIosNative(),
|
|
559
|
-
android: getAndroidNative()
|
|
560
|
-
});
|
|
561
621
|
if (Object.keys(deviceInfo).length > 0) instance.setDeviceInfo(deviceInfo);
|
|
562
622
|
if (!config.disableAutoSessions) {
|
|
563
623
|
const appState = getAppState();
|
|
@@ -568,10 +628,12 @@ var Advenue = {
|
|
|
568
628
|
if (!instance) return;
|
|
569
629
|
if (status === "background") {
|
|
570
630
|
seenBackground = true;
|
|
631
|
+
if (tcfCollectionEnabled) resolveDmaConsent();
|
|
571
632
|
applyAppState(instance, status);
|
|
572
633
|
} else if (status === "active") {
|
|
573
634
|
if (!seenBackground) return;
|
|
574
635
|
seenBackground = false;
|
|
636
|
+
if (tcfCollectionEnabled) resolveDmaConsent();
|
|
575
637
|
applyAppState(instance, status);
|
|
576
638
|
void resolveAdvertisingId().catch((err) => reportError("enrich.advertisingId", err));
|
|
577
639
|
}
|
|
@@ -582,7 +644,7 @@ var Advenue = {
|
|
|
582
644
|
instance.notifyAppActive();
|
|
583
645
|
}
|
|
584
646
|
}
|
|
585
|
-
|
|
647
|
+
{
|
|
586
648
|
const linking = getLinking();
|
|
587
649
|
if (linking) {
|
|
588
650
|
const client = instance;
|
|
@@ -592,7 +654,19 @@ var Advenue = {
|
|
|
592
654
|
// Deferred deep link: server-side conversion poll (deterministic ids
|
|
593
655
|
// where available, probabilistic otherwise).
|
|
594
656
|
resolveDeferred: () => client.resolveDeferredDeepLink(),
|
|
595
|
-
onDeepLink
|
|
657
|
+
onDeepLink: onDeepLink ?? (() => {
|
|
658
|
+
}),
|
|
659
|
+
onDirectUrl: (url, link) => {
|
|
660
|
+
const raw = link.params?.al_applink_data;
|
|
661
|
+
if (typeof raw !== "string") return;
|
|
662
|
+
const campaignIds = extractAemCampaignIds(raw);
|
|
663
|
+
if (!campaignIds) return;
|
|
664
|
+
const sourceUrlHash = sha256Hex(url);
|
|
665
|
+
if (aemSeenUrlHashes.has(sourceUrlHash)) return;
|
|
666
|
+
if (client.getRequireConsent() && !client.getTrackingConsent()) return;
|
|
667
|
+
client.track("adv_meta_aem", { campaignIds, sourceUrlHash });
|
|
668
|
+
aemSeenUrlHashes.add(sourceUrlHash);
|
|
669
|
+
}
|
|
596
670
|
});
|
|
597
671
|
deepLinkSub.ready.catch((err) => reportError("deepLink.resolve", err));
|
|
598
672
|
}
|
|
@@ -645,12 +719,18 @@ var Advenue = {
|
|
|
645
719
|
}
|
|
646
720
|
},
|
|
647
721
|
setConsentData(consent) {
|
|
722
|
+
manualConsentSet = true;
|
|
648
723
|
active().setConsentData(consent);
|
|
649
724
|
void resolveAdvertisingId().catch((err) => reportError("enrich.advertisingId", err));
|
|
650
725
|
},
|
|
651
726
|
getConsentData: () => active().getConsentData(),
|
|
652
727
|
flush: () => active().flush(),
|
|
653
728
|
getDeviceId: () => active().getDeviceId(),
|
|
729
|
+
/** The Advenue ID — alias of getDeviceId (see AdvenueClient.getAdvenueId). */
|
|
730
|
+
getAdvenueId: () => active().getAdvenueId(),
|
|
731
|
+
/** Which app the server resolved this API key to; null until a batch lands
|
|
732
|
+
* (see AdvenueClient.getResolvedAppId). */
|
|
733
|
+
getResolvedAppId: () => active().getResolvedAppId(),
|
|
654
734
|
shutdown() {
|
|
655
735
|
appStateSub?.remove();
|
|
656
736
|
appStateSub = null;
|
|
@@ -662,9 +742,11 @@ var Advenue = {
|
|
|
662
742
|
installInFlight = false;
|
|
663
743
|
autoInstallPending = false;
|
|
664
744
|
autoInstallEnabled = true;
|
|
665
|
-
|
|
745
|
+
manualConsentSet = false;
|
|
746
|
+
tcfCollectionEnabled = false;
|
|
666
747
|
configuredApiKey = null;
|
|
667
748
|
configuredEndpoint = import_sdk_core.DEFAULT_ENDPOINT;
|
|
749
|
+
aemSeenUrlHashes.clear();
|
|
668
750
|
}
|
|
669
751
|
};
|
|
670
752
|
async function trackInstall() {
|
|
@@ -739,10 +821,10 @@ async function trackInstall() {
|
|
|
739
821
|
}
|
|
740
822
|
await resolveAdvertisingId();
|
|
741
823
|
const trackOpts = { type: "install", ...opts };
|
|
742
|
-
if (
|
|
824
|
+
if (android && typeof android.getIntegrityToken === "function") {
|
|
743
825
|
try {
|
|
744
826
|
const deviceId = client.getDeviceId();
|
|
745
|
-
const requestHash = sha256Hex(
|
|
827
|
+
const requestHash = sha256Hex(deviceId);
|
|
746
828
|
const token = await android.getIntegrityToken(requestHash);
|
|
747
829
|
if (token) {
|
|
748
830
|
trackOpts.attestationToken = token;
|
|
@@ -752,13 +834,24 @@ async function trackInstall() {
|
|
|
752
834
|
reportError("attest.playIntegrity", err);
|
|
753
835
|
}
|
|
754
836
|
}
|
|
755
|
-
if (
|
|
837
|
+
if (configuredApiKey && ios && typeof ios.attestKey === "function") {
|
|
756
838
|
try {
|
|
757
839
|
const deviceId = client.getDeviceId();
|
|
758
840
|
const challengeUrl = `${configuredEndpoint}/v1/attest/challenge?deviceId=${encodeURIComponent(deviceId)}`;
|
|
759
|
-
const
|
|
760
|
-
|
|
761
|
-
|
|
841
|
+
const ac = new AbortController();
|
|
842
|
+
const timer = setTimeout(
|
|
843
|
+
() => ac.abort(new Error("attest challenge timed out")),
|
|
844
|
+
ATTEST_CHALLENGE_TIMEOUT_MS
|
|
845
|
+
);
|
|
846
|
+
let challengeRes;
|
|
847
|
+
try {
|
|
848
|
+
challengeRes = await fetch(challengeUrl, {
|
|
849
|
+
headers: { "x-api-key": configuredApiKey },
|
|
850
|
+
signal: ac.signal
|
|
851
|
+
});
|
|
852
|
+
} finally {
|
|
853
|
+
clearTimeout(timer);
|
|
854
|
+
}
|
|
762
855
|
if (!challengeRes.ok) throw new Error(`challenge HTTP ${challengeRes.status}`);
|
|
763
856
|
const { challenge } = await challengeRes.json();
|
|
764
857
|
const { keyId, attestationObject } = await ios.attestKey(challenge);
|
|
@@ -815,5 +908,6 @@ async function trackInstall() {
|
|
|
815
908
|
getIosNative,
|
|
816
909
|
parseDirectLink,
|
|
817
910
|
resolveAdvertisingId,
|
|
911
|
+
resolveDmaConsent,
|
|
818
912
|
trackInstall
|
|
819
913
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -44,6 +44,14 @@ interface MetaInstallReferrerResult {
|
|
|
44
44
|
* real `DeviceInfo` shape.
|
|
45
45
|
*/
|
|
46
46
|
interface AdvenueDeviceInfo {
|
|
47
|
+
/** Bundle id / package name — Meta CAPI extinfo slot 1. */
|
|
48
|
+
packageName?: string;
|
|
49
|
+
/** User-facing app version (CFBundleShortVersionString / versionName) —
|
|
50
|
+
* extinfo slot 2. Surfaced as the event's top-level `appVersion`, not as
|
|
51
|
+
* part of the deviceInfo blob. */
|
|
52
|
+
shortVersion?: string;
|
|
53
|
+
/** Build identifier (CFBundleVersion / versionCode) — extinfo slot 3. */
|
|
54
|
+
longVersion?: string;
|
|
47
55
|
model?: string;
|
|
48
56
|
locale?: string;
|
|
49
57
|
carrier?: string;
|
|
@@ -55,6 +63,16 @@ interface AdvenueDeviceInfo {
|
|
|
55
63
|
totalStorageGb?: number;
|
|
56
64
|
freeStorageGb?: number;
|
|
57
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Raw IAB TCF v2 CMP values from the platform default store
|
|
68
|
+
* (`UserDefaults.standard` / default SharedPreferences) — where TCF-compliant
|
|
69
|
+
* CMPs (e.g. Google UMP) write `IABTCF_*` keys. Structurally mirrors
|
|
70
|
+
* `TcfData` from `@advenue/sdk-core`.
|
|
71
|
+
*/
|
|
72
|
+
interface NativeTcfData {
|
|
73
|
+
gdprApplies?: number | null;
|
|
74
|
+
purposeConsents?: string | null;
|
|
75
|
+
}
|
|
58
76
|
interface AdvenueAndroidNativeModule {
|
|
59
77
|
/** Raw Play Install Referrer; parse with @advenue/install-referrer. */
|
|
60
78
|
getInstallReferrer(): Promise<InstallReferrerResult | null>;
|
|
@@ -73,9 +91,11 @@ interface AdvenueAndroidNativeModule {
|
|
|
73
91
|
/**
|
|
74
92
|
* Play Integrity Standard API token (G3.1n).
|
|
75
93
|
*
|
|
76
|
-
* `requestHash` MUST be sha256_hex("<
|
|
77
|
-
*
|
|
78
|
-
*
|
|
94
|
+
* `requestHash` MUST be sha256_hex("<deviceId>") — lowercase hex SHA-256 of the
|
|
95
|
+
* device id alone. The server's mapIntegrityVerdict re-derives the same string
|
|
96
|
+
* and compares it byte-for-byte. No app id is hashed in: the token is decoded
|
|
97
|
+
* against the app's Play package name and must be PLAY_RECOGNIZED, which binds
|
|
98
|
+
* the app already.
|
|
79
99
|
*
|
|
80
100
|
* Rejects when:
|
|
81
101
|
* - ECONFIG: `io.advenue.INTEGRITY_CLOUD_PROJECT_NUMBER` meta-data is absent.
|
|
@@ -112,6 +132,12 @@ interface AdvenueAndroidNativeModule {
|
|
|
112
132
|
* policy). Optional: absent on older native builds; feature-detected.
|
|
113
133
|
*/
|
|
114
134
|
getAndroidId?(): string | null;
|
|
135
|
+
/**
|
|
136
|
+
* IAB TCF v2 CMP data, null when no CMP has written TCF keys. Optional:
|
|
137
|
+
* older native builds lack it — callers feature-detect (getAndroidId
|
|
138
|
+
* precedent).
|
|
139
|
+
*/
|
|
140
|
+
getTcfData?(): NativeTcfData | null;
|
|
115
141
|
}
|
|
116
142
|
type TrackingAuthorizationStatus = 'notDetermined' | 'restricted' | 'denied' | 'authorized';
|
|
117
143
|
interface AdvenueIosNativeModule {
|
|
@@ -176,6 +202,12 @@ interface AdvenueIosNativeModule {
|
|
|
176
202
|
secureGetItem?(key: string): string | null;
|
|
177
203
|
secureSetItem?(key: string, value: string): void;
|
|
178
204
|
secureRemoveItem?(key: string): void;
|
|
205
|
+
/**
|
|
206
|
+
* IAB TCF v2 CMP data, null when no CMP has written TCF keys. Optional:
|
|
207
|
+
* older native builds lack it — callers feature-detect (getAndroidId
|
|
208
|
+
* precedent).
|
|
209
|
+
*/
|
|
210
|
+
getTcfData?(): NativeTcfData | null;
|
|
179
211
|
}
|
|
180
212
|
|
|
181
213
|
/**
|
|
@@ -219,6 +251,20 @@ declare function getAndroidNative(): AdvenueAndroidNativeModule | null;
|
|
|
219
251
|
* Fire-and-forget at call sites; errors are suppressed internally.
|
|
220
252
|
*/
|
|
221
253
|
declare function resolveAdvertisingId(): Promise<void>;
|
|
254
|
+
/**
|
|
255
|
+
* Reads IAB TCF v2 consent (written by a TCF-compliant CMP, e.g. Google UMP,
|
|
256
|
+
* to the platform default store), maps it to the DMA Consent shape, and
|
|
257
|
+
* pushes it into the active client. No-op — returning null — when consent was
|
|
258
|
+
* set manually this session, the native module or its getter is absent, no
|
|
259
|
+
* TCF data exists, or the freshly-mapped consent is identical to what the
|
|
260
|
+
* client already has (skip-if-unchanged: avoids re-persisting to storage and
|
|
261
|
+
* re-firing the ad-id resolve on every foreground when nothing changed):
|
|
262
|
+
* absent/unchanged consent must stay untouched, never fabricated or re-churned.
|
|
263
|
+
*
|
|
264
|
+
* Must be called after `Advenue.initialize()` — like every facade method, it
|
|
265
|
+
* throws via the uninitialized guard otherwise.
|
|
266
|
+
*/
|
|
267
|
+
declare function resolveDmaConsent(): Consent | null;
|
|
222
268
|
/**
|
|
223
269
|
* Collects native device metadata (model, locale, screen, cpu, storage, timezone)
|
|
224
270
|
* used to populate Meta CAPI `extinfo`. Reads from the platform-appropriate
|
|
@@ -228,15 +274,19 @@ declare function resolveAdvertisingId(): Promise<void>;
|
|
|
228
274
|
* native-side error degrades to an empty object so callers can unconditionally
|
|
229
275
|
* pass the result through.
|
|
230
276
|
*/
|
|
231
|
-
|
|
277
|
+
type NativeDeviceInfo = Partial<DeviceInfo> & {
|
|
278
|
+
shortVersion?: string;
|
|
279
|
+
};
|
|
280
|
+
type DeviceInfoNatives = {
|
|
232
281
|
platform: 'ios' | 'android' | string;
|
|
233
282
|
ios?: {
|
|
234
|
-
getDeviceInfo?: () =>
|
|
283
|
+
getDeviceInfo?: () => NativeDeviceInfo;
|
|
235
284
|
} | null;
|
|
236
285
|
android?: {
|
|
237
|
-
getDeviceInfo?: () =>
|
|
286
|
+
getDeviceInfo?: () => NativeDeviceInfo;
|
|
238
287
|
} | null;
|
|
239
|
-
}
|
|
288
|
+
};
|
|
289
|
+
declare function collectDeviceInfo(natives: DeviceInfoNatives): DeviceInfo;
|
|
240
290
|
interface RNAdvenueConfig extends Omit<AdvenueConfig, 'storage' | 'platform'> {
|
|
241
291
|
/**
|
|
242
292
|
* Auto-detected from React Native's `Platform.OS` — omit it. Pass explicitly
|
|
@@ -251,18 +301,6 @@ interface RNAdvenueConfig extends Omit<AdvenueConfig, 'storage' | 'platform'> {
|
|
|
251
301
|
* supply storage. When set, it replaces the built-in native storage.
|
|
252
302
|
*/
|
|
253
303
|
mmkv?: MMKVLike;
|
|
254
|
-
/**
|
|
255
|
-
* G3.1n — Play Integrity (Android) / App Attest (iOS) attestation.
|
|
256
|
-
*
|
|
257
|
-
* Your app's Advenue appId (the UUID in Settings → API Keys). When set on
|
|
258
|
-
* Android, the automatic install obtains a Play Integrity Standard token and
|
|
259
|
-
* attaches it to the install event. The requestHash is computed as
|
|
260
|
-
* `sha256Hex("<appId>:<deviceId>")`, matching the server's verification
|
|
261
|
-
* formula exactly (see `makeDecodeAndroid` in the worker).
|
|
262
|
-
*
|
|
263
|
-
* Omit to run without attestation (the server field stays `unavailable`).
|
|
264
|
-
*/
|
|
265
|
-
appId?: string;
|
|
266
304
|
/**
|
|
267
305
|
* @internal Secure-store override (tests / custom embeddings). The SDK uses
|
|
268
306
|
* its own Keychain-backed native storage on iOS for the reinstall-resilient
|
|
@@ -285,6 +323,14 @@ interface RNAdvenueConfig extends Omit<AdvenueConfig, 'storage' | 'platform'> {
|
|
|
285
323
|
* install path deterministically.
|
|
286
324
|
*/
|
|
287
325
|
autoTrackInstall?: boolean;
|
|
326
|
+
/**
|
|
327
|
+
* Auto-collect IAB TCF v2 consent written by a TCF-compliant CMP (e.g.
|
|
328
|
+
* Google UMP) and attach it to every event as DMA consent data (AppsFlyer
|
|
329
|
+
* `enableTCFDataCollection` parity). Read at init and re-read on each
|
|
330
|
+
* foreground, so a CMP decision made after startup lands on later events.
|
|
331
|
+
* A manual `setConsentData()` call always wins. Default false.
|
|
332
|
+
*/
|
|
333
|
+
tcfDataCollection?: boolean;
|
|
288
334
|
}
|
|
289
335
|
/**
|
|
290
336
|
* Maps a React Native AppState status to the client's session lifecycle hooks.
|
|
@@ -317,6 +363,11 @@ declare const Advenue: {
|
|
|
317
363
|
} | null;
|
|
318
364
|
flush: () => Promise<void>;
|
|
319
365
|
getDeviceId: () => string;
|
|
366
|
+
/** The Advenue ID — alias of getDeviceId (see AdvenueClient.getAdvenueId). */
|
|
367
|
+
getAdvenueId: () => string;
|
|
368
|
+
/** Which app the server resolved this API key to; null until a batch lands
|
|
369
|
+
* (see AdvenueClient.getResolvedAppId). */
|
|
370
|
+
getResolvedAppId: () => string | null;
|
|
320
371
|
shutdown(): void;
|
|
321
372
|
};
|
|
322
373
|
/**
|
|
@@ -333,4 +384,4 @@ declare const Advenue: {
|
|
|
333
384
|
*/
|
|
334
385
|
declare function trackInstall(): Promise<void>;
|
|
335
386
|
|
|
336
|
-
export { Advenue, type AdvenueAndroidNativeModule, type AdvenueDeviceInfo, type AdvenueIosNativeModule, type InstallReferrerResult, type MMKVLike, type MetaInstallReferrerResult, type RNAdvenueConfig, type SecureStoreLike, type TrackingAuthorizationStatus, applyAppState, collectDeviceInfo, createMMKVStorage, createSecureStore, getAndroidNative, getIosNative, parseDirectLink, resolveAdvertisingId, trackInstall };
|
|
387
|
+
export { Advenue, type AdvenueAndroidNativeModule, type AdvenueDeviceInfo, type AdvenueIosNativeModule, type InstallReferrerResult, type MMKVLike, type MetaInstallReferrerResult, type NativeTcfData, type RNAdvenueConfig, type SecureStoreLike, type TrackingAuthorizationStatus, applyAppState, collectDeviceInfo, createMMKVStorage, createSecureStore, getAndroidNative, getIosNative, parseDirectLink, resolveAdvertisingId, resolveDmaConsent, trackInstall };
|