@apex-inc/capacitor-plugin 2.4.1 → 2.5.1
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 +66 -14
- package/android/src/main/java/inc/apex/capacitor/ApexCapacitorPlugin.kt +145 -15
- package/android/src/main/java/inc/apex/capacitor/ApexEvents.kt +11 -4
- package/android/src/main/java/inc/apex/capacitor/DeepLinkManager.kt +27 -0
- package/android/src/main/java/inc/apex/capacitor/TrackStamps.kt +26 -0
- package/dist/deferred-link.d.ts +73 -0
- package/dist/deferred-link.d.ts.map +1 -0
- package/dist/deferred-link.js +71 -0
- package/dist/deferred-link.js.map +1 -0
- package/dist/definitions.d.ts +94 -18
- package/dist/definitions.d.ts.map +1 -1
- package/dist/esm/deferred-link.d.ts +73 -0
- package/dist/esm/deferred-link.d.ts.map +1 -0
- package/dist/esm/deferred-link.js +68 -0
- package/dist/esm/deferred-link.js.map +1 -0
- package/dist/esm/definitions.d.ts +94 -18
- package/dist/esm/definitions.d.ts.map +1 -1
- package/dist/esm/events.d.ts +8 -1
- package/dist/esm/events.d.ts.map +1 -1
- package/dist/esm/events.js +8 -1
- package/dist/esm/events.js.map +1 -1
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +157 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/referrer-link.d.ts +36 -0
- package/dist/esm/referrer-link.d.ts.map +1 -0
- package/dist/esm/referrer-link.js +103 -0
- package/dist/esm/referrer-link.js.map +1 -0
- package/dist/esm/skan-conversion-values.d.ts +175 -0
- package/dist/esm/skan-conversion-values.d.ts.map +1 -0
- package/dist/esm/skan-conversion-values.js +323 -0
- package/dist/esm/skan-conversion-values.js.map +1 -0
- package/dist/esm/web.d.ts +6 -1
- package/dist/esm/web.d.ts.map +1 -1
- package/dist/esm/web.js +27 -3
- package/dist/esm/web.js.map +1 -1
- package/dist/events.d.ts +8 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +8 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +166 -1
- package/dist/index.js.map +1 -1
- package/dist/referrer-link.d.ts +36 -0
- package/dist/referrer-link.d.ts.map +1 -0
- package/dist/referrer-link.js +107 -0
- package/dist/referrer-link.js.map +1 -0
- package/dist/skan-conversion-values.d.ts +175 -0
- package/dist/skan-conversion-values.d.ts.map +1 -0
- package/dist/skan-conversion-values.js +331 -0
- package/dist/skan-conversion-values.js.map +1 -0
- package/dist/web.d.ts +6 -1
- package/dist/web.d.ts.map +1 -1
- package/dist/web.js +27 -3
- package/dist/web.js.map +1 -1
- package/ios/Sources/ApexCapacitorPlugin/ApexEvents.swift +11 -4
- package/ios/Sources/ApexCapacitorPlugin/DeepLinkManager.swift +16 -2
- package/ios/Sources/ApexCapacitorPlugin/SkanManager.swift +18 -4
- package/ios/Sources/ApexCapacitorPluginBridge/ApexCapacitorPlugin.swift +25 -6
- package/ios/Tests/ApexCapacitorPluginTests/DeepLinkManagerTests.swift +26 -0
- package/ios/Tests/ApexCapacitorPluginTests/SkanManagerTests.swift +22 -1
- package/package.json +5 -2
- package/ios/Package.swift +0 -34
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Deferred deep-link resolution.
|
|
4
|
+
*
|
|
5
|
+
* The problem this solves: a user taps a link in Safari or Chrome, does
|
|
6
|
+
* not have your app, installs it from the store, and opens it. The tap
|
|
7
|
+
* and the launch share no cookie and no storage, so by default your app
|
|
8
|
+
* has no idea the user was headed for a specific screen and drops them
|
|
9
|
+
* on your home screen. The tap that cost you money lands nowhere.
|
|
10
|
+
*
|
|
11
|
+
* Apex matches the launch back to the tap server-side and hands you the
|
|
12
|
+
* destination. Call it once, early, and route on the result:
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* const link = await Apex.getDeferredDeepLink();
|
|
16
|
+
* if (link) router.navigateByUrl(link.deepLinkHint ?? new URL(link.url).pathname);
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Two properties worth knowing before you build on it:
|
|
20
|
+
*
|
|
21
|
+
* - **One-shot.** The match key is coarse (network + OS), so a link can
|
|
22
|
+
* only be claimed once. Call this on first launch and persist what
|
|
23
|
+
* you get; a second call returns null.
|
|
24
|
+
* - **Best-effort.** Matching is probabilistic and returns null more
|
|
25
|
+
* often than it returns a link — no network address, a VPN between
|
|
26
|
+
* tap and install, or a slow install all produce a miss. Treat a
|
|
27
|
+
* link as a bonus that improves the first run, never as a
|
|
28
|
+
* precondition for it.
|
|
29
|
+
*
|
|
30
|
+
* Implemented in TypeScript rather than in the native bridges because it
|
|
31
|
+
* is one HTTPS call with no platform APIs involved, and the webview can
|
|
32
|
+
* make it identically on iOS, Android, and in browser preview.
|
|
33
|
+
*/
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.fetchDeferredDeepLink = fetchDeferredDeepLink;
|
|
36
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
37
|
+
async function fetchDeferredDeepLink(options) {
|
|
38
|
+
const { apiUrl, workspaceKey, platform, apiKey } = options;
|
|
39
|
+
if (!workspaceKey)
|
|
40
|
+
return null;
|
|
41
|
+
// First launch is the most latency-sensitive moment in the app's life.
|
|
42
|
+
// A slow or unreachable Apex must never hold up the first screen, so
|
|
43
|
+
// the call is bounded and every failure resolves to null.
|
|
44
|
+
const controller = new AbortController();
|
|
45
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
46
|
+
try {
|
|
47
|
+
const headers = {
|
|
48
|
+
"Content-Type": "application/json",
|
|
49
|
+
"x-apex-workspace": workspaceKey,
|
|
50
|
+
};
|
|
51
|
+
if (apiKey)
|
|
52
|
+
headers["x-apex-api-key"] = apiKey;
|
|
53
|
+
const response = await fetch(`${apiUrl.replace(/\/+$/, "")}/api/mobile/deferred-link`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers,
|
|
56
|
+
body: JSON.stringify({ workspaceKey, platform }),
|
|
57
|
+
signal: controller.signal,
|
|
58
|
+
});
|
|
59
|
+
if (!response.ok)
|
|
60
|
+
return null;
|
|
61
|
+
const payload = (await response.json());
|
|
62
|
+
return payload.data ?? null;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
clearTimeout(timer);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=deferred-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred-link.js","sourceRoot":"","sources":["../src/deferred-link.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;;AA6CH,sDA0CC;AA5CD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEzB,KAAK,UAAU,qBAAqB,CACzC,OAAqC;IAErC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3D,IAAI,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IAE/B,uEAAuE;IACvE,qEAAqE;IACrE,0DAA0D;IAC1D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CACtB,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EACxB,OAAO,CAAC,SAAS,IAAI,kBAAkB,CACxC,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,OAAO,GAA2B;YACtC,cAAc,EAAE,kBAAkB;YAClC,kBAAkB,EAAE,YAAY;SACjC,CAAC;QACF,IAAI,MAAM;YAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,MAAM,CAAC;QAE/C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,2BAA2B,EACxD;YACE,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;YAChD,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CACF,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAC9B,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAErC,CAAC;QACF,OAAO,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
|
package/dist/definitions.d.ts
CHANGED
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
* See `plans/mobile-measurement-platform.md` Phase 1b for scope and rationale.
|
|
11
11
|
*/
|
|
12
12
|
import type { PluginListenerHandle } from "@capacitor/core";
|
|
13
|
+
import type { DeferredDeepLinkResult } from "./deferred-link";
|
|
14
|
+
import type { SkanSchemaSnapshot } from "./skan-conversion-values";
|
|
15
|
+
export type { DeferredDeepLinkResult } from "./deferred-link";
|
|
16
|
+
export type { SkanConversionSchema, SkanConversionValueEntry, SkanConversionWindow, SkanSchemaSnapshot, SkanWindow, } from "./skan-conversion-values";
|
|
13
17
|
/** iOS App Tracking Transparency authorization status. */
|
|
14
18
|
export type AttStatus = "authorized" | "denied" | "restricted" | "not-determined";
|
|
15
19
|
/** User-notification permission state returned by `registerForPushNotifications`. */
|
|
@@ -163,23 +167,20 @@ export interface InitializeOptions {
|
|
|
163
167
|
/** API base URL. Defaults to `https://app.apex.inc`. */
|
|
164
168
|
apiUrl?: string;
|
|
165
169
|
/**
|
|
166
|
-
* Optional
|
|
170
|
+
* Optional app key (`apex_pk_*`), made under Settings, Organization,
|
|
171
|
+
* API keys with the App key preset. Safe to ship in a released app.
|
|
167
172
|
*
|
|
168
173
|
* When set, the plugin attaches it as `x-apex-api-key` on every
|
|
169
|
-
* outbound request to `/api/events` and `/api/identity/stitch`.
|
|
170
|
-
*
|
|
171
|
-
* (
|
|
172
|
-
*
|
|
174
|
+
* outbound request to `/api/events` and `/api/identity/stitch`. It
|
|
175
|
+
* gives the app its own rate limit and lets a `user_signed_up` event
|
|
176
|
+
* with an email add a new person (held until a signed `identify()`).
|
|
177
|
+
* It never touches a person already in Apex, never counts revenue as a
|
|
178
|
+
* server, and never sends anything to ad platforms.
|
|
173
179
|
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* IMPORTANT: only embed API keys in mobile apps when the workspace
|
|
180
|
-
* is dedicated to that app. Treat the value like a publishable key,
|
|
181
|
-
* not a secret — assume it will leak via reverse-engineering. Apex
|
|
182
|
-
* rate-limits per key + per visitor to make leaked keys low-yield.
|
|
180
|
+
* Never ship a server key (`apex_sk_*`) or personal key (`apex_uk_*`)
|
|
181
|
+
* in a released app. Anyone can extract it from the bundle, and either
|
|
182
|
+
* key lets them send purchases Apex counts as revenue and forwards to
|
|
183
|
+
* ad platforms. Send purchases from your server instead.
|
|
183
184
|
*/
|
|
184
185
|
apiKey?: string;
|
|
185
186
|
/**
|
|
@@ -227,6 +228,25 @@ export interface InitializeOptions {
|
|
|
227
228
|
* server stamps `releaseChannelSource: "auto"` regardless.
|
|
228
229
|
*/
|
|
229
230
|
releaseChannel?: ReleaseChannel;
|
|
231
|
+
/**
|
|
232
|
+
* Mobile Measurement P2 — let Apex drive SKAdNetwork conversion values.
|
|
233
|
+
*
|
|
234
|
+
* When true (the default on iOS), the plugin fetches what Apple's 0–63
|
|
235
|
+
* numbers mean for this app — the table Set up Apex derives from "which
|
|
236
|
+
* event means an install was worth it?" — caches it for a day, and
|
|
237
|
+
* calls `updatePostbackConversionValue` whenever `track()` sees an
|
|
238
|
+
* event in that table. The first manual `updateConversionValue` call
|
|
239
|
+
* switches this off for the install, so a hand-rolled ladder always
|
|
240
|
+
* wins. No-op on Android and web.
|
|
241
|
+
*
|
|
242
|
+
* Set false to keep full manual control.
|
|
243
|
+
*/
|
|
244
|
+
autoConversionValues?: boolean;
|
|
245
|
+
/**
|
|
246
|
+
* Which registered app's conversion value table to use, when the
|
|
247
|
+
* workspace has more than one. Defaults to the workspace's first app.
|
|
248
|
+
*/
|
|
249
|
+
mobileAppId?: string;
|
|
230
250
|
}
|
|
231
251
|
/**
|
|
232
252
|
* Options for {@link ApexCapacitorPlugin.identify}.
|
|
@@ -261,6 +281,13 @@ export interface IdentifyOptions {
|
|
|
261
281
|
* source, plan tier, locale). Merged into the Contact's traits.
|
|
262
282
|
*/
|
|
263
283
|
traits?: Record<string, unknown>;
|
|
284
|
+
/**
|
|
285
|
+
* Signed sign-in: the hash your server made from this email with the
|
|
286
|
+
* workspace's sign-in secret. Fetch it from your backend at sign-in;
|
|
287
|
+
* never put the secret in the app. Without it, a workspace that requires
|
|
288
|
+
* signed sign-ins holds the sign-in instead of attaching it to a person.
|
|
289
|
+
*/
|
|
290
|
+
userHash?: string;
|
|
264
291
|
}
|
|
265
292
|
/** Return value of {@link ApexCapacitorPlugin.getAdvertisingId}. */
|
|
266
293
|
export interface AdvertisingIdResult {
|
|
@@ -377,11 +404,19 @@ export interface ApexCapacitorPlugin {
|
|
|
377
404
|
*/
|
|
378
405
|
getAdvertisingId(): Promise<AdvertisingIdResult>;
|
|
379
406
|
/**
|
|
380
|
-
* Android: returns decoded Play Install Referrer string
|
|
381
|
-
*
|
|
407
|
+
* Android: returns the decoded Play Install Referrer string, waiting
|
|
408
|
+
* briefly for Play to connect if the call arrives during first launch.
|
|
409
|
+
* `clickTimestamp` is the Unix-seconds time of the original ad tap
|
|
410
|
+
* (0 when Play didn't report one), which is what makes a stale
|
|
411
|
+
* referrer detectable — Play keeps the string forever.
|
|
412
|
+
*
|
|
413
|
+
* iOS: returns `{ referrer: null, clickTimestamp: 0 }`. The App Store
|
|
414
|
+
* forwards nothing across an install, which is why iOS deferred deep
|
|
415
|
+
* linking has to fall back to a probabilistic server match.
|
|
382
416
|
*/
|
|
383
417
|
getInstallReferrer(): Promise<{
|
|
384
418
|
referrer: string | null;
|
|
419
|
+
clickTimestamp: number;
|
|
385
420
|
}>;
|
|
386
421
|
/** Gets the plugin-managed visitor ID. */
|
|
387
422
|
getVisitorId(): Promise<{
|
|
@@ -411,20 +446,55 @@ export interface ApexCapacitorPlugin {
|
|
|
411
446
|
/**
|
|
412
447
|
* Updates the SKAdNetwork 4.0 postback conversion value. No-op on Android.
|
|
413
448
|
* `fineValue` is 0-63 (fine conversion value); `coarseValue` is optional
|
|
414
|
-
* for SKAN 4.0's coarse-grained reporting
|
|
449
|
+
* for SKAN 4.0's coarse-grained reporting; `lockWindow` asks Apple to
|
|
450
|
+
* send the current window's postback now rather than waiting it out.
|
|
451
|
+
*
|
|
452
|
+
* Calling this yourself turns off `autoConversionValues` for the
|
|
453
|
+
* install — manual always wins.
|
|
415
454
|
*/
|
|
416
455
|
updateConversionValue(options: {
|
|
417
456
|
fineValue: number;
|
|
418
457
|
coarseValue?: SkanCoarseValue;
|
|
458
|
+
lockWindow?: boolean;
|
|
419
459
|
}): Promise<void>;
|
|
460
|
+
/**
|
|
461
|
+
* The conversion value table the plugin is acting on: what each of
|
|
462
|
+
* Apple's numbers means for this app, as set in Set up Apex. `schema`
|
|
463
|
+
* is null until the shop has answered the SKAN question (or before
|
|
464
|
+
* the first fetch lands). Read-only; edit it in the Apex dashboard.
|
|
465
|
+
*/
|
|
466
|
+
getConversionValueSchema(): Promise<SkanSchemaSnapshot>;
|
|
420
467
|
/**
|
|
421
468
|
* Returns the URL the app was opened with on cold start (Universal Link on
|
|
422
469
|
* iOS, App Link on Android). Returns `{ url: null }` if launched without a
|
|
423
470
|
* link. Use the `deepLink` listener for subsequent warm-start links.
|
|
471
|
+
*
|
|
472
|
+
* `deepLinkHint` is the `apex_dl` value the Apex Link carried, already pulled
|
|
473
|
+
* off the query string — null when the link had none. It is whatever the
|
|
474
|
+
* merchant put on the link in Apex; nothing interprets it but your router.
|
|
424
475
|
*/
|
|
425
476
|
getInitialDeepLink(): Promise<{
|
|
426
477
|
url: string | null;
|
|
478
|
+
deepLinkHint: string | null;
|
|
427
479
|
}>;
|
|
480
|
+
/**
|
|
481
|
+
* Resolve the link the user tapped BEFORE they installed the app.
|
|
482
|
+
*
|
|
483
|
+
* `getInitialDeepLink()` above covers the case where the app already
|
|
484
|
+
* exists and the OS hands it a URL. This covers the other case: the
|
|
485
|
+
* user tapped an Apex Link in a browser, did not have the app, went
|
|
486
|
+
* through the store, and is now opening it for the first time. No URL
|
|
487
|
+
* reaches the app in that flow, so Apex matches the launch back to the
|
|
488
|
+
* tap server-side and returns the destination it was headed for.
|
|
489
|
+
*
|
|
490
|
+
* Returns null when there is no match, which is the common case — call
|
|
491
|
+
* it, route on a hit, and carry on normally otherwise. Resolution is
|
|
492
|
+
* one-shot per tap, so call it once at first launch and persist the
|
|
493
|
+
* result rather than calling it again later.
|
|
494
|
+
*
|
|
495
|
+
* See `deferred-link.ts` for the matching properties and their limits.
|
|
496
|
+
*/
|
|
497
|
+
getDeferredDeepLink(): Promise<DeferredDeepLinkResult | null>;
|
|
428
498
|
getDeviceInfo(): Promise<DeviceInfo>;
|
|
429
499
|
/** Force-starts a new session, ending any current one. */
|
|
430
500
|
startSession(): Promise<{
|
|
@@ -514,9 +584,15 @@ export interface ApexCapacitorPlugin {
|
|
|
514
584
|
getConsent(): Promise<{
|
|
515
585
|
granted: boolean;
|
|
516
586
|
}>;
|
|
517
|
-
/**
|
|
587
|
+
/**
|
|
588
|
+
* Fires when a deep link opens the app while it is already running.
|
|
589
|
+
*
|
|
590
|
+
* `deepLinkHint` carries the link's `apex_dl` value when it had one — see
|
|
591
|
+
* `getInitialDeepLink()`.
|
|
592
|
+
*/
|
|
518
593
|
addListener(eventName: "deepLink", listenerFunc: (event: {
|
|
519
594
|
url: string;
|
|
595
|
+
deepLinkHint: string | null;
|
|
520
596
|
}) => void): Promise<PluginListenerHandle>;
|
|
521
597
|
/** Fires when the app moves between foreground and background. */
|
|
522
598
|
addListener(eventName: "appStateChange", listenerFunc: (event: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deferred deep-link resolution.
|
|
3
|
+
*
|
|
4
|
+
* The problem this solves: a user taps a link in Safari or Chrome, does
|
|
5
|
+
* not have your app, installs it from the store, and opens it. The tap
|
|
6
|
+
* and the launch share no cookie and no storage, so by default your app
|
|
7
|
+
* has no idea the user was headed for a specific screen and drops them
|
|
8
|
+
* on your home screen. The tap that cost you money lands nowhere.
|
|
9
|
+
*
|
|
10
|
+
* Apex matches the launch back to the tap server-side and hands you the
|
|
11
|
+
* destination. Call it once, early, and route on the result:
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* const link = await Apex.getDeferredDeepLink();
|
|
15
|
+
* if (link) router.navigateByUrl(link.deepLinkHint ?? new URL(link.url).pathname);
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* Two properties worth knowing before you build on it:
|
|
19
|
+
*
|
|
20
|
+
* - **One-shot.** The match key is coarse (network + OS), so a link can
|
|
21
|
+
* only be claimed once. Call this on first launch and persist what
|
|
22
|
+
* you get; a second call returns null.
|
|
23
|
+
* - **Best-effort.** Matching is probabilistic and returns null more
|
|
24
|
+
* often than it returns a link — no network address, a VPN between
|
|
25
|
+
* tap and install, or a slow install all produce a miss. Treat a
|
|
26
|
+
* link as a bonus that improves the first run, never as a
|
|
27
|
+
* precondition for it.
|
|
28
|
+
*
|
|
29
|
+
* Implemented in TypeScript rather than in the native bridges because it
|
|
30
|
+
* is one HTTPS call with no platform APIs involved, and the webview can
|
|
31
|
+
* make it identically on iOS, Android, and in browser preview.
|
|
32
|
+
*/
|
|
33
|
+
export interface DeferredDeepLinkResult {
|
|
34
|
+
/**
|
|
35
|
+
* The destination the tap was headed for, with Apex's own routing
|
|
36
|
+
* params (`apex_dl`, `apex_link`) already stripped.
|
|
37
|
+
*/
|
|
38
|
+
url: string;
|
|
39
|
+
/**
|
|
40
|
+
* The link's `apex_dl` value — whatever screen identifier you put on
|
|
41
|
+
* the link in Apex. Null when the link carried none.
|
|
42
|
+
*/
|
|
43
|
+
deepLinkHint: string | null;
|
|
44
|
+
/** Apex Link slug the tap came through, when it came through one. */
|
|
45
|
+
slug?: string;
|
|
46
|
+
/** Affiliate handle, for namespaced partner links. */
|
|
47
|
+
handle?: string;
|
|
48
|
+
source?: string;
|
|
49
|
+
campaign?: string;
|
|
50
|
+
/** ISO timestamp of the original tap. */
|
|
51
|
+
clickedAt: string;
|
|
52
|
+
/**
|
|
53
|
+
* How the launch was matched to the tap.
|
|
54
|
+
*
|
|
55
|
+
* `deterministic` means Google Play handed us the exact link the user
|
|
56
|
+
* tapped, via the install referrer — there is no guesswork in it.
|
|
57
|
+
* `probabilistic` means we matched on network address and OS, which is
|
|
58
|
+
* the best available on iOS and can, on a shared network, be wrong.
|
|
59
|
+
* Route on either; only gate irreversible actions (granting a credit,
|
|
60
|
+
* applying a referral bonus) on `deterministic`.
|
|
61
|
+
*/
|
|
62
|
+
matchType: "deterministic" | "probabilistic";
|
|
63
|
+
}
|
|
64
|
+
export interface FetchDeferredDeepLinkOptions {
|
|
65
|
+
apiUrl: string;
|
|
66
|
+
workspaceKey: string;
|
|
67
|
+
platform: "ios" | "android";
|
|
68
|
+
apiKey?: string;
|
|
69
|
+
/** Abort the call after this many ms. Defaults to 5000. */
|
|
70
|
+
timeoutMs?: number;
|
|
71
|
+
}
|
|
72
|
+
export declare function fetchDeferredDeepLink(options: FetchDeferredDeepLinkOptions): Promise<DeferredDeepLinkResult | null>;
|
|
73
|
+
//# sourceMappingURL=deferred-link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred-link.d.ts","sourceRoot":"","sources":["../../src/deferred-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;;;OASG;IACH,SAAS,EAAE,eAAe,GAAG,eAAe,CAAC;CAC9C;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAwCxC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deferred deep-link resolution.
|
|
3
|
+
*
|
|
4
|
+
* The problem this solves: a user taps a link in Safari or Chrome, does
|
|
5
|
+
* not have your app, installs it from the store, and opens it. The tap
|
|
6
|
+
* and the launch share no cookie and no storage, so by default your app
|
|
7
|
+
* has no idea the user was headed for a specific screen and drops them
|
|
8
|
+
* on your home screen. The tap that cost you money lands nowhere.
|
|
9
|
+
*
|
|
10
|
+
* Apex matches the launch back to the tap server-side and hands you the
|
|
11
|
+
* destination. Call it once, early, and route on the result:
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* const link = await Apex.getDeferredDeepLink();
|
|
15
|
+
* if (link) router.navigateByUrl(link.deepLinkHint ?? new URL(link.url).pathname);
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* Two properties worth knowing before you build on it:
|
|
19
|
+
*
|
|
20
|
+
* - **One-shot.** The match key is coarse (network + OS), so a link can
|
|
21
|
+
* only be claimed once. Call this on first launch and persist what
|
|
22
|
+
* you get; a second call returns null.
|
|
23
|
+
* - **Best-effort.** Matching is probabilistic and returns null more
|
|
24
|
+
* often than it returns a link — no network address, a VPN between
|
|
25
|
+
* tap and install, or a slow install all produce a miss. Treat a
|
|
26
|
+
* link as a bonus that improves the first run, never as a
|
|
27
|
+
* precondition for it.
|
|
28
|
+
*
|
|
29
|
+
* Implemented in TypeScript rather than in the native bridges because it
|
|
30
|
+
* is one HTTPS call with no platform APIs involved, and the webview can
|
|
31
|
+
* make it identically on iOS, Android, and in browser preview.
|
|
32
|
+
*/
|
|
33
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
34
|
+
export async function fetchDeferredDeepLink(options) {
|
|
35
|
+
const { apiUrl, workspaceKey, platform, apiKey } = options;
|
|
36
|
+
if (!workspaceKey)
|
|
37
|
+
return null;
|
|
38
|
+
// First launch is the most latency-sensitive moment in the app's life.
|
|
39
|
+
// A slow or unreachable Apex must never hold up the first screen, so
|
|
40
|
+
// the call is bounded and every failure resolves to null.
|
|
41
|
+
const controller = new AbortController();
|
|
42
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
43
|
+
try {
|
|
44
|
+
const headers = {
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
"x-apex-workspace": workspaceKey,
|
|
47
|
+
};
|
|
48
|
+
if (apiKey)
|
|
49
|
+
headers["x-apex-api-key"] = apiKey;
|
|
50
|
+
const response = await fetch(`${apiUrl.replace(/\/+$/, "")}/api/mobile/deferred-link`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers,
|
|
53
|
+
body: JSON.stringify({ workspaceKey, platform }),
|
|
54
|
+
signal: controller.signal,
|
|
55
|
+
});
|
|
56
|
+
if (!response.ok)
|
|
57
|
+
return null;
|
|
58
|
+
const payload = (await response.json());
|
|
59
|
+
return payload.data ?? null;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
clearTimeout(timer);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=deferred-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred-link.js","sourceRoot":"","sources":["../../src/deferred-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AA2CH,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAqC;IAErC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3D,IAAI,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IAE/B,uEAAuE;IACvE,qEAAqE;IACrE,0DAA0D;IAC1D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CACtB,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EACxB,OAAO,CAAC,SAAS,IAAI,kBAAkB,CACxC,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,OAAO,GAA2B;YACtC,cAAc,EAAE,kBAAkB;YAClC,kBAAkB,EAAE,YAAY;SACjC,CAAC;QACF,IAAI,MAAM;YAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,MAAM,CAAC;QAE/C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,2BAA2B,EACxD;YACE,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;YAChD,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CACF,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAC9B,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAErC,CAAC;QACF,OAAO,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
|
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
* See `plans/mobile-measurement-platform.md` Phase 1b for scope and rationale.
|
|
11
11
|
*/
|
|
12
12
|
import type { PluginListenerHandle } from "@capacitor/core";
|
|
13
|
+
import type { DeferredDeepLinkResult } from "./deferred-link";
|
|
14
|
+
import type { SkanSchemaSnapshot } from "./skan-conversion-values";
|
|
15
|
+
export type { DeferredDeepLinkResult } from "./deferred-link";
|
|
16
|
+
export type { SkanConversionSchema, SkanConversionValueEntry, SkanConversionWindow, SkanSchemaSnapshot, SkanWindow, } from "./skan-conversion-values";
|
|
13
17
|
/** iOS App Tracking Transparency authorization status. */
|
|
14
18
|
export type AttStatus = "authorized" | "denied" | "restricted" | "not-determined";
|
|
15
19
|
/** User-notification permission state returned by `registerForPushNotifications`. */
|
|
@@ -163,23 +167,20 @@ export interface InitializeOptions {
|
|
|
163
167
|
/** API base URL. Defaults to `https://app.apex.inc`. */
|
|
164
168
|
apiUrl?: string;
|
|
165
169
|
/**
|
|
166
|
-
* Optional
|
|
170
|
+
* Optional app key (`apex_pk_*`), made under Settings, Organization,
|
|
171
|
+
* API keys with the App key preset. Safe to ship in a released app.
|
|
167
172
|
*
|
|
168
173
|
* When set, the plugin attaches it as `x-apex-api-key` on every
|
|
169
|
-
* outbound request to `/api/events` and `/api/identity/stitch`.
|
|
170
|
-
*
|
|
171
|
-
* (
|
|
172
|
-
*
|
|
174
|
+
* outbound request to `/api/events` and `/api/identity/stitch`. It
|
|
175
|
+
* gives the app its own rate limit and lets a `user_signed_up` event
|
|
176
|
+
* with an email add a new person (held until a signed `identify()`).
|
|
177
|
+
* It never touches a person already in Apex, never counts revenue as a
|
|
178
|
+
* server, and never sends anything to ad platforms.
|
|
173
179
|
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* IMPORTANT: only embed API keys in mobile apps when the workspace
|
|
180
|
-
* is dedicated to that app. Treat the value like a publishable key,
|
|
181
|
-
* not a secret — assume it will leak via reverse-engineering. Apex
|
|
182
|
-
* rate-limits per key + per visitor to make leaked keys low-yield.
|
|
180
|
+
* Never ship a server key (`apex_sk_*`) or personal key (`apex_uk_*`)
|
|
181
|
+
* in a released app. Anyone can extract it from the bundle, and either
|
|
182
|
+
* key lets them send purchases Apex counts as revenue and forwards to
|
|
183
|
+
* ad platforms. Send purchases from your server instead.
|
|
183
184
|
*/
|
|
184
185
|
apiKey?: string;
|
|
185
186
|
/**
|
|
@@ -227,6 +228,25 @@ export interface InitializeOptions {
|
|
|
227
228
|
* server stamps `releaseChannelSource: "auto"` regardless.
|
|
228
229
|
*/
|
|
229
230
|
releaseChannel?: ReleaseChannel;
|
|
231
|
+
/**
|
|
232
|
+
* Mobile Measurement P2 — let Apex drive SKAdNetwork conversion values.
|
|
233
|
+
*
|
|
234
|
+
* When true (the default on iOS), the plugin fetches what Apple's 0–63
|
|
235
|
+
* numbers mean for this app — the table Set up Apex derives from "which
|
|
236
|
+
* event means an install was worth it?" — caches it for a day, and
|
|
237
|
+
* calls `updatePostbackConversionValue` whenever `track()` sees an
|
|
238
|
+
* event in that table. The first manual `updateConversionValue` call
|
|
239
|
+
* switches this off for the install, so a hand-rolled ladder always
|
|
240
|
+
* wins. No-op on Android and web.
|
|
241
|
+
*
|
|
242
|
+
* Set false to keep full manual control.
|
|
243
|
+
*/
|
|
244
|
+
autoConversionValues?: boolean;
|
|
245
|
+
/**
|
|
246
|
+
* Which registered app's conversion value table to use, when the
|
|
247
|
+
* workspace has more than one. Defaults to the workspace's first app.
|
|
248
|
+
*/
|
|
249
|
+
mobileAppId?: string;
|
|
230
250
|
}
|
|
231
251
|
/**
|
|
232
252
|
* Options for {@link ApexCapacitorPlugin.identify}.
|
|
@@ -261,6 +281,13 @@ export interface IdentifyOptions {
|
|
|
261
281
|
* source, plan tier, locale). Merged into the Contact's traits.
|
|
262
282
|
*/
|
|
263
283
|
traits?: Record<string, unknown>;
|
|
284
|
+
/**
|
|
285
|
+
* Signed sign-in: the hash your server made from this email with the
|
|
286
|
+
* workspace's sign-in secret. Fetch it from your backend at sign-in;
|
|
287
|
+
* never put the secret in the app. Without it, a workspace that requires
|
|
288
|
+
* signed sign-ins holds the sign-in instead of attaching it to a person.
|
|
289
|
+
*/
|
|
290
|
+
userHash?: string;
|
|
264
291
|
}
|
|
265
292
|
/** Return value of {@link ApexCapacitorPlugin.getAdvertisingId}. */
|
|
266
293
|
export interface AdvertisingIdResult {
|
|
@@ -377,11 +404,19 @@ export interface ApexCapacitorPlugin {
|
|
|
377
404
|
*/
|
|
378
405
|
getAdvertisingId(): Promise<AdvertisingIdResult>;
|
|
379
406
|
/**
|
|
380
|
-
* Android: returns decoded Play Install Referrer string
|
|
381
|
-
*
|
|
407
|
+
* Android: returns the decoded Play Install Referrer string, waiting
|
|
408
|
+
* briefly for Play to connect if the call arrives during first launch.
|
|
409
|
+
* `clickTimestamp` is the Unix-seconds time of the original ad tap
|
|
410
|
+
* (0 when Play didn't report one), which is what makes a stale
|
|
411
|
+
* referrer detectable — Play keeps the string forever.
|
|
412
|
+
*
|
|
413
|
+
* iOS: returns `{ referrer: null, clickTimestamp: 0 }`. The App Store
|
|
414
|
+
* forwards nothing across an install, which is why iOS deferred deep
|
|
415
|
+
* linking has to fall back to a probabilistic server match.
|
|
382
416
|
*/
|
|
383
417
|
getInstallReferrer(): Promise<{
|
|
384
418
|
referrer: string | null;
|
|
419
|
+
clickTimestamp: number;
|
|
385
420
|
}>;
|
|
386
421
|
/** Gets the plugin-managed visitor ID. */
|
|
387
422
|
getVisitorId(): Promise<{
|
|
@@ -411,20 +446,55 @@ export interface ApexCapacitorPlugin {
|
|
|
411
446
|
/**
|
|
412
447
|
* Updates the SKAdNetwork 4.0 postback conversion value. No-op on Android.
|
|
413
448
|
* `fineValue` is 0-63 (fine conversion value); `coarseValue` is optional
|
|
414
|
-
* for SKAN 4.0's coarse-grained reporting
|
|
449
|
+
* for SKAN 4.0's coarse-grained reporting; `lockWindow` asks Apple to
|
|
450
|
+
* send the current window's postback now rather than waiting it out.
|
|
451
|
+
*
|
|
452
|
+
* Calling this yourself turns off `autoConversionValues` for the
|
|
453
|
+
* install — manual always wins.
|
|
415
454
|
*/
|
|
416
455
|
updateConversionValue(options: {
|
|
417
456
|
fineValue: number;
|
|
418
457
|
coarseValue?: SkanCoarseValue;
|
|
458
|
+
lockWindow?: boolean;
|
|
419
459
|
}): Promise<void>;
|
|
460
|
+
/**
|
|
461
|
+
* The conversion value table the plugin is acting on: what each of
|
|
462
|
+
* Apple's numbers means for this app, as set in Set up Apex. `schema`
|
|
463
|
+
* is null until the shop has answered the SKAN question (or before
|
|
464
|
+
* the first fetch lands). Read-only; edit it in the Apex dashboard.
|
|
465
|
+
*/
|
|
466
|
+
getConversionValueSchema(): Promise<SkanSchemaSnapshot>;
|
|
420
467
|
/**
|
|
421
468
|
* Returns the URL the app was opened with on cold start (Universal Link on
|
|
422
469
|
* iOS, App Link on Android). Returns `{ url: null }` if launched without a
|
|
423
470
|
* link. Use the `deepLink` listener for subsequent warm-start links.
|
|
471
|
+
*
|
|
472
|
+
* `deepLinkHint` is the `apex_dl` value the Apex Link carried, already pulled
|
|
473
|
+
* off the query string — null when the link had none. It is whatever the
|
|
474
|
+
* merchant put on the link in Apex; nothing interprets it but your router.
|
|
424
475
|
*/
|
|
425
476
|
getInitialDeepLink(): Promise<{
|
|
426
477
|
url: string | null;
|
|
478
|
+
deepLinkHint: string | null;
|
|
427
479
|
}>;
|
|
480
|
+
/**
|
|
481
|
+
* Resolve the link the user tapped BEFORE they installed the app.
|
|
482
|
+
*
|
|
483
|
+
* `getInitialDeepLink()` above covers the case where the app already
|
|
484
|
+
* exists and the OS hands it a URL. This covers the other case: the
|
|
485
|
+
* user tapped an Apex Link in a browser, did not have the app, went
|
|
486
|
+
* through the store, and is now opening it for the first time. No URL
|
|
487
|
+
* reaches the app in that flow, so Apex matches the launch back to the
|
|
488
|
+
* tap server-side and returns the destination it was headed for.
|
|
489
|
+
*
|
|
490
|
+
* Returns null when there is no match, which is the common case — call
|
|
491
|
+
* it, route on a hit, and carry on normally otherwise. Resolution is
|
|
492
|
+
* one-shot per tap, so call it once at first launch and persist the
|
|
493
|
+
* result rather than calling it again later.
|
|
494
|
+
*
|
|
495
|
+
* See `deferred-link.ts` for the matching properties and their limits.
|
|
496
|
+
*/
|
|
497
|
+
getDeferredDeepLink(): Promise<DeferredDeepLinkResult | null>;
|
|
428
498
|
getDeviceInfo(): Promise<DeviceInfo>;
|
|
429
499
|
/** Force-starts a new session, ending any current one. */
|
|
430
500
|
startSession(): Promise<{
|
|
@@ -514,9 +584,15 @@ export interface ApexCapacitorPlugin {
|
|
|
514
584
|
getConsent(): Promise<{
|
|
515
585
|
granted: boolean;
|
|
516
586
|
}>;
|
|
517
|
-
/**
|
|
587
|
+
/**
|
|
588
|
+
* Fires when a deep link opens the app while it is already running.
|
|
589
|
+
*
|
|
590
|
+
* `deepLinkHint` carries the link's `apex_dl` value when it had one — see
|
|
591
|
+
* `getInitialDeepLink()`.
|
|
592
|
+
*/
|
|
518
593
|
addListener(eventName: "deepLink", listenerFunc: (event: {
|
|
519
594
|
url: string;
|
|
595
|
+
deepLinkHint: string | null;
|
|
520
596
|
}) => void): Promise<PluginListenerHandle>;
|
|
521
597
|
/** Fires when the app moves between foreground and background. */
|
|
522
598
|
addListener(eventName: "appStateChange", listenerFunc: (event: {
|