@advenue/react-native 0.3.1 → 0.5.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 +2 -2
- package/android/build.gradle +22 -0
- package/android/src/main/AndroidManifest.xml +8 -0
- package/android/src/main/java/expo/modules/advenue/AdvenueAndroidModule.kt +354 -0
- package/dist/index.d.ts +214 -29
- package/dist/index.js +258 -141
- package/expo-module.config.json +9 -0
- package/ios/AdvenueIos.podspec +20 -0
- package/ios/AdvenueIosModule.swift +461 -0
- package/package.json +9 -19
- package/plugin/index.js +4 -8
- package/plugin/links.js +23 -1
- package/src/deep-links.ts +5 -2
- package/src/index.ts +413 -233
- package/src/native-storage.ts +63 -0
- package/src/native-types.ts +169 -0
- package/src/native.ts +27 -8
- package/src/secure-store.ts +7 -0
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseInstallReferrer, extractReferrerProperties, parseMetaInstallReferrer } from '@advenue/install-referrer';
|
|
2
|
-
import { DEFAULT_ENDPOINT, MemoryStorage, resolveDurableDeviceId, AdvenueClient } from '@advenue/sdk-core';
|
|
2
|
+
import { DEVICE_ID_KEY, DEFAULT_ENDPOINT, MemoryStorage, resolveDurableDeviceId, AdvenueClient } from '@advenue/sdk-core';
|
|
3
3
|
|
|
4
4
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
5
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
@@ -174,10 +174,10 @@ function parseDirectLink(url) {
|
|
|
174
174
|
const path = parsed.pathname.replace(/^\/+/, "");
|
|
175
175
|
const isHttp = parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
176
176
|
deepLinkValue = isHttp ? path : [parsed.host, path].filter(Boolean).join("/");
|
|
177
|
-
|
|
177
|
+
parsed.searchParams.forEach((v, k) => {
|
|
178
178
|
params ??= {};
|
|
179
179
|
params[k] = v;
|
|
180
|
-
}
|
|
180
|
+
});
|
|
181
181
|
} catch {
|
|
182
182
|
deepLinkValue = url;
|
|
183
183
|
}
|
|
@@ -217,14 +217,23 @@ function createMMKVStorage(mmkv) {
|
|
|
217
217
|
// src/native.ts
|
|
218
218
|
function getIosNative() {
|
|
219
219
|
try {
|
|
220
|
-
|
|
220
|
+
const core = __require("expo-modules-core");
|
|
221
|
+
return core.requireNativeModule("AdvenueIos");
|
|
221
222
|
} catch {
|
|
222
223
|
return null;
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
226
|
function getAndroidNative() {
|
|
226
227
|
try {
|
|
227
|
-
|
|
228
|
+
const core = __require("expo-modules-core");
|
|
229
|
+
return core.requireNativeModule("AdvenueAndroid");
|
|
230
|
+
} catch {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function getPlatformOS() {
|
|
235
|
+
try {
|
|
236
|
+
return __require("react-native").Platform.OS ?? null;
|
|
228
237
|
} catch {
|
|
229
238
|
return null;
|
|
230
239
|
}
|
|
@@ -244,11 +253,38 @@ function getLinking() {
|
|
|
244
253
|
}
|
|
245
254
|
}
|
|
246
255
|
|
|
256
|
+
// src/native-storage.ts
|
|
257
|
+
function createNativeStorage(mod) {
|
|
258
|
+
const m = mod;
|
|
259
|
+
if (!m || typeof m.storageGetItem !== "function" || typeof m.storageSetItem !== "function" || typeof m.storageRemoveItem !== "function") {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
getItem: (key) => m.storageGetItem?.(key) ?? null,
|
|
264
|
+
setItem: (key, value) => m.storageSetItem?.(key, value),
|
|
265
|
+
removeItem: (key) => m.storageRemoveItem?.(key)
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function createNativeSecureStore(mod) {
|
|
269
|
+
const m = mod;
|
|
270
|
+
if (!m || typeof m.secureGetItem !== "function" || typeof m.secureSetItem !== "function" || typeof m.secureRemoveItem !== "function") {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
getItemAsync: async (key) => m.secureGetItem?.(key) ?? null,
|
|
275
|
+
setItemAsync: async (key, value) => m.secureSetItem?.(key, value),
|
|
276
|
+
deleteItemAsync: async (key) => m.secureRemoveItem?.(key)
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
247
280
|
// src/secure-store.ts
|
|
248
281
|
function createSecureStore(secureStore2) {
|
|
249
282
|
return {
|
|
250
283
|
getItemAsync: async (key) => await secureStore2.getItemAsync(key) ?? null,
|
|
251
|
-
setItemAsync: (key, value) => secureStore2.setItemAsync(key, value)
|
|
284
|
+
setItemAsync: (key, value) => secureStore2.setItemAsync(key, value),
|
|
285
|
+
...secureStore2.deleteItemAsync ? {
|
|
286
|
+
deleteItemAsync: (key) => secureStore2.deleteItemAsync?.(key) ?? Promise.resolve()
|
|
287
|
+
} : {}
|
|
252
288
|
};
|
|
253
289
|
}
|
|
254
290
|
|
|
@@ -276,7 +312,14 @@ async function resolveAdvertisingId() {
|
|
|
276
312
|
const r = await android.getAdvertisingId();
|
|
277
313
|
const vendorId = typeof android.getAppSetId === "function" ? await android.getAppSetId() : null;
|
|
278
314
|
const adFields = r ? r.limitAdTracking ? { limitAdTracking: true } : { gaid: r.id } : {};
|
|
279
|
-
|
|
315
|
+
const hasUsableGaid = !!r && !r.limitAdTracking;
|
|
316
|
+
const rawAndroidId = !hasUsableGaid && typeof android.getAndroidId === "function" ? android.getAndroidId() : null;
|
|
317
|
+
const androidId = rawAndroidId && /^[0-9a-fA-F]{8,32}$/.test(rawAndroidId) ? rawAndroidId : null;
|
|
318
|
+
client.setAdvertisingId({
|
|
319
|
+
...adFields,
|
|
320
|
+
...vendorId ? { vendorId } : {},
|
|
321
|
+
...androidId ? { androidId } : {}
|
|
322
|
+
});
|
|
280
323
|
return;
|
|
281
324
|
}
|
|
282
325
|
client.setAdvertisingId({});
|
|
@@ -300,7 +343,14 @@ async function resolveClipboardMatch() {
|
|
|
300
343
|
if (!ios || typeof ios.getPasteboardMatchToken !== "function") {
|
|
301
344
|
return null;
|
|
302
345
|
}
|
|
303
|
-
|
|
346
|
+
let token;
|
|
347
|
+
try {
|
|
348
|
+
token = ios.getPasteboardMatchToken();
|
|
349
|
+
} catch (err) {
|
|
350
|
+
reportError("enrich.clipboardMatch", err);
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
const matchId = parseMatchToken(token);
|
|
304
354
|
if (!matchId) return null;
|
|
305
355
|
return client.exchangeClipboardMatch(matchId);
|
|
306
356
|
}
|
|
@@ -318,6 +368,8 @@ var secureStore = null;
|
|
|
318
368
|
var installFlagStore = null;
|
|
319
369
|
var INSTALL_SENT_KEY = "advenue.install_sent";
|
|
320
370
|
var installInFlight = false;
|
|
371
|
+
var autoInstallPending = false;
|
|
372
|
+
var autoInstallEnabled = true;
|
|
321
373
|
var configuredAppId = null;
|
|
322
374
|
var configuredApiKey = null;
|
|
323
375
|
var configuredEndpoint = DEFAULT_ENDPOINT;
|
|
@@ -330,9 +382,37 @@ function active() {
|
|
|
330
382
|
function reportError(context, cause) {
|
|
331
383
|
instance?.report(context, cause);
|
|
332
384
|
}
|
|
385
|
+
function fireAutoInstall() {
|
|
386
|
+
void trackInstall().catch((err) => reportError("install.auto", err));
|
|
387
|
+
}
|
|
388
|
+
function resolvePlatform(explicit) {
|
|
389
|
+
if (explicit) {
|
|
390
|
+
return explicit;
|
|
391
|
+
}
|
|
392
|
+
const os = getPlatformOS();
|
|
393
|
+
if (os === "ios" || os === "android") {
|
|
394
|
+
return os;
|
|
395
|
+
}
|
|
396
|
+
if (os) {
|
|
397
|
+
return "web";
|
|
398
|
+
}
|
|
399
|
+
throw new Error(
|
|
400
|
+
"Advenue.initialize(): platform could not be detected (react-native unavailable) \u2014 pass platform: 'ios' | 'android' | 'web'."
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
function fireAutoInstallIfPending() {
|
|
404
|
+
if (!autoInstallPending) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
autoInstallPending = false;
|
|
408
|
+
fireAutoInstall();
|
|
409
|
+
}
|
|
333
410
|
var Advenue = {
|
|
334
411
|
async initialize(config) {
|
|
335
|
-
const { mmkv, secureStore: secureMod, onDeepLink, appId, ...rest } = config;
|
|
412
|
+
const { mmkv, secureStore: secureMod, onDeepLink, appId, autoTrackInstall, ...rest } = config;
|
|
413
|
+
autoInstallPending = false;
|
|
414
|
+
autoInstallEnabled = autoTrackInstall !== false;
|
|
415
|
+
const platform = resolvePlatform(rest.platform);
|
|
336
416
|
configuredAppId = appId ?? null;
|
|
337
417
|
configuredApiKey = config.apiKey;
|
|
338
418
|
configuredEndpoint = config.endpoint ?? DEFAULT_ENDPOINT;
|
|
@@ -341,14 +421,16 @@ var Advenue = {
|
|
|
341
421
|
deepLinkSub?.remove();
|
|
342
422
|
deepLinkSub = null;
|
|
343
423
|
instance?.shutdown();
|
|
344
|
-
const
|
|
424
|
+
const iosMod = getIosNative();
|
|
425
|
+
const androidMod = getAndroidNative();
|
|
426
|
+
const storage = mmkv ? createMMKVStorage(mmkv) : createNativeStorage(iosMod ?? androidMod) ?? new MemoryStorage();
|
|
345
427
|
installFlagStore = storage;
|
|
346
|
-
secureStore = secureMod ? createSecureStore(secureMod) :
|
|
428
|
+
secureStore = secureMod ? createSecureStore(secureMod) : createNativeSecureStore(iosMod);
|
|
347
429
|
const deviceId = rest.deviceId ?? await resolveDurableDeviceId(storage, secureStore ?? void 0);
|
|
348
|
-
instance = new AdvenueClient({ ...rest, deviceId, storage });
|
|
430
|
+
instance = new AdvenueClient({ ...rest, platform, deviceId, storage });
|
|
349
431
|
void resolveAdvertisingId().catch((err) => reportError("enrich.advertisingId", err));
|
|
350
432
|
const deviceInfo = collectDeviceInfo({
|
|
351
|
-
platform
|
|
433
|
+
platform,
|
|
352
434
|
ios: getIosNative(),
|
|
353
435
|
android: getAndroidNative()
|
|
354
436
|
});
|
|
@@ -388,6 +470,14 @@ var Advenue = {
|
|
|
388
470
|
resolveDeferred: async () => await resolveClipboardMatch() ?? client.resolveDeferredDeepLink(),
|
|
389
471
|
onDeepLink
|
|
390
472
|
});
|
|
473
|
+
deepLinkSub.ready.catch((err) => reportError("deepLink.resolve", err));
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (autoTrackInstall !== false) {
|
|
477
|
+
if (instance.getRequireConsent() && !instance.getTrackingConsent()) {
|
|
478
|
+
autoInstallPending = true;
|
|
479
|
+
} else {
|
|
480
|
+
fireAutoInstall();
|
|
391
481
|
}
|
|
392
482
|
}
|
|
393
483
|
return instance;
|
|
@@ -402,142 +492,33 @@ var Advenue = {
|
|
|
402
492
|
const status = ios ? await ios.requestTrackingAuthorization() : "authorized";
|
|
403
493
|
active().setTrackingConsent(status === "authorized");
|
|
404
494
|
void resolveAdvertisingId().catch((err) => reportError("enrich.advertisingId", err));
|
|
495
|
+
if (status === "authorized") {
|
|
496
|
+
fireAutoInstallIfPending();
|
|
497
|
+
}
|
|
405
498
|
return status;
|
|
406
499
|
},
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
* most once per device (reinstall-resilient on iOS via Keychain; Android
|
|
412
|
-
* re-fires after a reinstall, which is unavoidable post-GAID).
|
|
413
|
-
*/
|
|
414
|
-
async trackInstall(properties) {
|
|
415
|
-
const client = active();
|
|
416
|
-
let sent = installFlagStore?.getItem(INSTALL_SENT_KEY) === "1";
|
|
417
|
-
if (!sent && secureStore) {
|
|
418
|
-
try {
|
|
419
|
-
sent = await secureStore.getItemAsync(INSTALL_SENT_KEY) === "1";
|
|
420
|
-
} catch (err) {
|
|
421
|
-
reportError("install.guardRead", err);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
if (sent) {
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
if (installInFlight) {
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
installInFlight = true;
|
|
431
|
-
const opts = {};
|
|
432
|
-
const props = { ...properties };
|
|
433
|
-
const android = getAndroidNative();
|
|
434
|
-
if (android) {
|
|
435
|
-
try {
|
|
436
|
-
const result = await android.getInstallReferrer();
|
|
437
|
-
if (result) {
|
|
438
|
-
const parsed = parseInstallReferrer(result.referrer);
|
|
439
|
-
if (parsed.network) opts.network = parsed.network;
|
|
440
|
-
if (parsed.campaign) opts.campaign = parsed.campaign;
|
|
441
|
-
if (parsed.gclid) props.gclid = parsed.gclid;
|
|
442
|
-
if (parsed.fbclid) props.fbclid = parsed.fbclid;
|
|
443
|
-
Object.assign(props, extractReferrerProperties(result));
|
|
444
|
-
}
|
|
445
|
-
} catch (err) {
|
|
446
|
-
reportError("enrich.installReferrer", err);
|
|
447
|
-
}
|
|
448
|
-
try {
|
|
449
|
-
const meta = await android.getMetaInstallReferrer();
|
|
450
|
-
const parsedMeta = meta ? parseMetaInstallReferrer(meta) : null;
|
|
451
|
-
if (parsedMeta) {
|
|
452
|
-
props.metaInstallReferrer = parsedMeta.raw;
|
|
453
|
-
if (parsedMeta.encryptedData) props.metaReferrerData = parsedMeta.encryptedData;
|
|
454
|
-
if (parsedMeta.nonce) props.metaReferrerNonce = parsedMeta.nonce;
|
|
455
|
-
if (!opts.network && parsedMeta.isClickThrough) {
|
|
456
|
-
opts.network = "meta";
|
|
457
|
-
if (parsedMeta.campaign) opts.campaign = parsedMeta.campaign;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
} catch (err) {
|
|
461
|
-
reportError("enrich.metaReferrer", err);
|
|
462
|
-
}
|
|
500
|
+
setTrackingConsent(granted) {
|
|
501
|
+
active().setTrackingConsent(granted);
|
|
502
|
+
if (granted) {
|
|
503
|
+
fireAutoInstallIfPending();
|
|
463
504
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
reportError("enrich.skanRegister", err);
|
|
470
|
-
}
|
|
471
|
-
try {
|
|
472
|
-
const asaToken = await ios.getAttributionToken();
|
|
473
|
-
if (asaToken) {
|
|
474
|
-
opts.adservicesToken = asaToken;
|
|
475
|
-
}
|
|
476
|
-
} catch (err) {
|
|
477
|
-
reportError("enrich.adservicesToken", err);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
await resolveAdvertisingId();
|
|
481
|
-
const trackOpts = { type: "install", ...opts };
|
|
482
|
-
if (configuredAppId && android && typeof android.getIntegrityToken === "function") {
|
|
483
|
-
try {
|
|
484
|
-
const deviceId = client.getDeviceId();
|
|
485
|
-
const requestHash = sha256Hex(`${configuredAppId}:${deviceId}`);
|
|
486
|
-
const token = await android.getIntegrityToken(requestHash);
|
|
487
|
-
if (token) {
|
|
488
|
-
trackOpts.attestationToken = token;
|
|
489
|
-
trackOpts.attestationType = "play-integrity";
|
|
490
|
-
}
|
|
491
|
-
} catch (err) {
|
|
492
|
-
reportError("attest.playIntegrity", err);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
if (configuredAppId && configuredApiKey && ios && typeof ios.attestKey === "function") {
|
|
496
|
-
try {
|
|
497
|
-
const deviceId = client.getDeviceId();
|
|
498
|
-
const challengeUrl = `${configuredEndpoint}/v1/attest/challenge?deviceId=${encodeURIComponent(deviceId)}`;
|
|
499
|
-
const challengeRes = await fetch(challengeUrl, {
|
|
500
|
-
headers: { "x-api-key": configuredApiKey }
|
|
501
|
-
});
|
|
502
|
-
if (!challengeRes.ok) throw new Error(`challenge HTTP ${challengeRes.status}`);
|
|
503
|
-
const { challenge } = await challengeRes.json();
|
|
504
|
-
const { keyId, attestationObject } = await ios.attestKey(challenge);
|
|
505
|
-
trackOpts.attestationToken = attestationObject;
|
|
506
|
-
trackOpts.attestationType = "app-attest";
|
|
507
|
-
trackOpts.attestationKeyId = keyId;
|
|
508
|
-
trackOpts.attestationChallenge = challenge;
|
|
509
|
-
} catch (err) {
|
|
510
|
-
reportError("attest.appAttest", err);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
if (ios && typeof ios.getDeviceCheckToken === "function") {
|
|
514
|
-
try {
|
|
515
|
-
const token = await ios.getDeviceCheckToken();
|
|
516
|
-
if (token) {
|
|
517
|
-
trackOpts.deviceCheckToken = token;
|
|
518
|
-
}
|
|
519
|
-
} catch (err) {
|
|
520
|
-
reportError("attest.deviceCheck", err);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
client.track("install", props, trackOpts);
|
|
505
|
+
},
|
|
506
|
+
getTrackingConsent: () => active().getTrackingConsent(),
|
|
507
|
+
/** GDPR/CCPA erasure: stop tracking and wipe local identifiers/queue. */
|
|
508
|
+
forgetMe() {
|
|
509
|
+
active().forgetMe();
|
|
524
510
|
try {
|
|
525
|
-
installFlagStore?.
|
|
511
|
+
installFlagStore?.removeItem(INSTALL_SENT_KEY);
|
|
526
512
|
} catch (err) {
|
|
527
|
-
reportError("
|
|
513
|
+
reportError("forget.wipe", err);
|
|
528
514
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
reportError("install.flagPersistSecure", err);
|
|
515
|
+
const secure = secureStore;
|
|
516
|
+
if (secure?.deleteItemAsync) {
|
|
517
|
+
for (const key of [DEVICE_ID_KEY, INSTALL_SENT_KEY]) {
|
|
518
|
+
void secure.deleteItemAsync(key).catch((err) => reportError("forget.secureWipe", err));
|
|
534
519
|
}
|
|
535
520
|
}
|
|
536
521
|
},
|
|
537
|
-
setTrackingConsent: (granted) => active().setTrackingConsent(granted),
|
|
538
|
-
getTrackingConsent: () => active().getTrackingConsent(),
|
|
539
|
-
/** GDPR/CCPA erasure: stop tracking and wipe local identifiers/queue. */
|
|
540
|
-
forgetMe: () => active().forgetMe(),
|
|
541
522
|
setConsentData(consent) {
|
|
542
523
|
active().setConsentData(consent);
|
|
543
524
|
void resolveAdvertisingId().catch((err) => reportError("enrich.advertisingId", err));
|
|
@@ -554,10 +535,146 @@ var Advenue = {
|
|
|
554
535
|
instance = null;
|
|
555
536
|
secureStore = null;
|
|
556
537
|
installInFlight = false;
|
|
538
|
+
autoInstallPending = false;
|
|
539
|
+
autoInstallEnabled = true;
|
|
557
540
|
configuredAppId = null;
|
|
558
541
|
configuredApiKey = null;
|
|
559
542
|
configuredEndpoint = DEFAULT_ENDPOINT;
|
|
560
543
|
}
|
|
561
544
|
};
|
|
545
|
+
async function trackInstall() {
|
|
546
|
+
const client = active();
|
|
547
|
+
if (client.getRequireConsent() && !client.getTrackingConsent()) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
let sent = installFlagStore?.getItem(INSTALL_SENT_KEY) === "1";
|
|
551
|
+
if (!sent && secureStore) {
|
|
552
|
+
try {
|
|
553
|
+
sent = await secureStore.getItemAsync(INSTALL_SENT_KEY) === "1";
|
|
554
|
+
} catch (err) {
|
|
555
|
+
reportError("install.guardRead", err);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
if (sent) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
if (installInFlight) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
installInFlight = true;
|
|
565
|
+
const opts = {};
|
|
566
|
+
const props = {};
|
|
567
|
+
const android = getAndroidNative();
|
|
568
|
+
if (android) {
|
|
569
|
+
try {
|
|
570
|
+
const result = await android.getInstallReferrer();
|
|
571
|
+
if (result) {
|
|
572
|
+
const parsed = parseInstallReferrer(result.referrer);
|
|
573
|
+
if (parsed.network) opts.network = parsed.network;
|
|
574
|
+
if (parsed.campaign) opts.campaign = parsed.campaign;
|
|
575
|
+
if (parsed.gclid) props.gclid = parsed.gclid;
|
|
576
|
+
if (parsed.fbclid) props.fbclid = parsed.fbclid;
|
|
577
|
+
Object.assign(props, extractReferrerProperties(result));
|
|
578
|
+
}
|
|
579
|
+
} catch (err) {
|
|
580
|
+
reportError("enrich.installReferrer", err);
|
|
581
|
+
}
|
|
582
|
+
try {
|
|
583
|
+
const meta = await android.getMetaInstallReferrer();
|
|
584
|
+
const parsedMeta = meta ? parseMetaInstallReferrer(meta) : null;
|
|
585
|
+
if (parsedMeta) {
|
|
586
|
+
props.metaInstallReferrer = parsedMeta.raw;
|
|
587
|
+
if (parsedMeta.encryptedData) props.metaReferrerData = parsedMeta.encryptedData;
|
|
588
|
+
if (parsedMeta.nonce) props.metaReferrerNonce = parsedMeta.nonce;
|
|
589
|
+
if (!opts.network && parsedMeta.isClickThrough) {
|
|
590
|
+
opts.network = "meta";
|
|
591
|
+
if (parsedMeta.campaign) opts.campaign = parsedMeta.campaign;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
} catch (err) {
|
|
595
|
+
reportError("enrich.metaReferrer", err);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
const ios = getIosNative();
|
|
599
|
+
if (ios) {
|
|
600
|
+
try {
|
|
601
|
+
ios.registerAppForAttribution();
|
|
602
|
+
} catch (err) {
|
|
603
|
+
reportError("enrich.skanRegister", err);
|
|
604
|
+
}
|
|
605
|
+
try {
|
|
606
|
+
const asaToken = await ios.getAttributionToken();
|
|
607
|
+
if (asaToken) {
|
|
608
|
+
opts.adservicesToken = asaToken;
|
|
609
|
+
}
|
|
610
|
+
} catch (err) {
|
|
611
|
+
reportError("enrich.adservicesToken", err);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
await resolveAdvertisingId();
|
|
615
|
+
const trackOpts = { type: "install", ...opts };
|
|
616
|
+
if (configuredAppId && android && typeof android.getIntegrityToken === "function") {
|
|
617
|
+
try {
|
|
618
|
+
const deviceId = client.getDeviceId();
|
|
619
|
+
const requestHash = sha256Hex(`${configuredAppId}:${deviceId}`);
|
|
620
|
+
const token = await android.getIntegrityToken(requestHash);
|
|
621
|
+
if (token) {
|
|
622
|
+
trackOpts.attestationToken = token;
|
|
623
|
+
trackOpts.attestationType = "play-integrity";
|
|
624
|
+
}
|
|
625
|
+
} catch (err) {
|
|
626
|
+
reportError("attest.playIntegrity", err);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
if (configuredAppId && configuredApiKey && ios && typeof ios.attestKey === "function") {
|
|
630
|
+
try {
|
|
631
|
+
const deviceId = client.getDeviceId();
|
|
632
|
+
const challengeUrl = `${configuredEndpoint}/v1/attest/challenge?deviceId=${encodeURIComponent(deviceId)}`;
|
|
633
|
+
const challengeRes = await fetch(challengeUrl, {
|
|
634
|
+
headers: { "x-api-key": configuredApiKey }
|
|
635
|
+
});
|
|
636
|
+
if (!challengeRes.ok) throw new Error(`challenge HTTP ${challengeRes.status}`);
|
|
637
|
+
const { challenge } = await challengeRes.json();
|
|
638
|
+
const { keyId, attestationObject } = await ios.attestKey(challenge);
|
|
639
|
+
trackOpts.attestationToken = attestationObject;
|
|
640
|
+
trackOpts.attestationType = "app-attest";
|
|
641
|
+
trackOpts.attestationKeyId = keyId;
|
|
642
|
+
trackOpts.attestationChallenge = challenge;
|
|
643
|
+
} catch (err) {
|
|
644
|
+
reportError("attest.appAttest", err);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (ios && typeof ios.getDeviceCheckToken === "function") {
|
|
648
|
+
try {
|
|
649
|
+
const token = await ios.getDeviceCheckToken();
|
|
650
|
+
if (token) {
|
|
651
|
+
trackOpts.deviceCheckToken = token;
|
|
652
|
+
}
|
|
653
|
+
} catch (err) {
|
|
654
|
+
reportError("attest.deviceCheck", err);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
const pendingBefore = client.pendingCount;
|
|
658
|
+
client.track("install", props, trackOpts);
|
|
659
|
+
if (client.pendingCount === pendingBefore) {
|
|
660
|
+
installInFlight = false;
|
|
661
|
+
if (autoInstallEnabled && client.getRequireConsent() && !client.getTrackingConsent()) {
|
|
662
|
+
autoInstallPending = true;
|
|
663
|
+
}
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
try {
|
|
667
|
+
installFlagStore?.setItem(INSTALL_SENT_KEY, "1");
|
|
668
|
+
} catch (err) {
|
|
669
|
+
reportError("install.flagPersist", err);
|
|
670
|
+
}
|
|
671
|
+
if (secureStore) {
|
|
672
|
+
try {
|
|
673
|
+
await secureStore.setItemAsync(INSTALL_SENT_KEY, "1");
|
|
674
|
+
} catch (err) {
|
|
675
|
+
reportError("install.flagPersistSecure", err);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
562
679
|
|
|
563
|
-
export { Advenue, applyAppState, collectDeviceInfo, createMMKVStorage, createSecureStore, getAndroidNative, getIosNative, parseDirectLink, resolveAdvertisingId, resolveClipboardMatch };
|
|
680
|
+
export { Advenue, applyAppState, collectDeviceInfo, createMMKVStorage, createSecureStore, getAndroidNative, getIosNative, parseDirectLink, resolveAdvertisingId, resolveClipboardMatch, trackInstall };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'AdvenueIos'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.license = package['license']
|
|
10
|
+
s.author = 'Advenue'
|
|
11
|
+
s.homepage = 'https://github.com/broverse/advenue'
|
|
12
|
+
s.platforms = { :ios => '15.1' }
|
|
13
|
+
s.swift_version = '5.4'
|
|
14
|
+
s.source = { git: 'https://github.com/broverse/advenue.git' }
|
|
15
|
+
s.static_framework = true
|
|
16
|
+
|
|
17
|
+
s.dependency 'ExpoModulesCore'
|
|
18
|
+
|
|
19
|
+
s.source_files = '**/*.{h,m,swift}'
|
|
20
|
+
end
|