@kontextso/sdk-react-native 3.3.1-rc.0 → 3.4.0-rc.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/RNKontext.podspec +1 -0
- package/android/build.gradle +1 -0
- package/android/src/main/AndroidManifest.xml +2 -1
- package/android/src/main/java/so/kontext/react/RNKontextModuleImpl.kt +34 -0
- package/android/src/newarch/java/so/kontext/react/RNKontextModule.kt +33 -0
- package/android/src/oldarch/java/so/kontext/react/RNKontextModule.kt +41 -0
- package/dist/index.js +119 -9
- package/dist/index.mjs +115 -5
- package/ios/KontextSDK.swift +106 -0
- package/ios/PrivacyInfo.xcprivacy +64 -0
- package/ios/RNKontext.mm +82 -0
- package/ios/SkAdNetworkManager.swift +257 -0
- package/ios/TrackingAuthorizationManager.swift +46 -0
- package/package.json +4 -4
- package/src/NativeRNKontext.ts +20 -0
- package/src/context/AdsProvider.tsx +33 -1
- package/src/formats/Format.tsx +62 -0
- package/src/services/Att.ts +117 -0
- package/src/services/SkAdNetwork.ts +75 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Platform } from 'react-native'
|
|
2
|
+
import NativeRNKontext from '../NativeRNKontext'
|
|
3
|
+
|
|
4
|
+
const ZERO_UUID = '00000000-0000-0000-0000-000000000000'
|
|
5
|
+
|
|
6
|
+
// Mirrors TrackingStatus enum from Flutter / ATTrackingManager raw values
|
|
7
|
+
export enum TrackingStatus {
|
|
8
|
+
NotDetermined = 0,
|
|
9
|
+
Restricted = 1,
|
|
10
|
+
Denied = 2,
|
|
11
|
+
Authorized = 3,
|
|
12
|
+
NotSupported = 4, // iOS < 14 or non-iOS
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let didRunStartupFlow = false
|
|
16
|
+
let startupFlowPromise: Promise<void> | null = null
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Requests ATT authorization on iOS >= 14.5.
|
|
20
|
+
* On iOS 14.0–14.4 we intentionally skip the request: the dialog is not
|
|
21
|
+
* required to read IDFA on those versions, and asking only to get denied
|
|
22
|
+
* would permanently revoke access.
|
|
23
|
+
* Guaranteed to run only once per app session regardless of call count.
|
|
24
|
+
*/
|
|
25
|
+
export function requestTrackingAuthorization(): Promise<void> {
|
|
26
|
+
if (didRunStartupFlow) {
|
|
27
|
+
return startupFlowPromise ?? Promise.resolve()
|
|
28
|
+
}
|
|
29
|
+
didRunStartupFlow = true
|
|
30
|
+
startupFlowPromise = _runStartupFlow()
|
|
31
|
+
return startupFlowPromise
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function getTrackingAuthorizationStatus(): Promise<TrackingStatus> {
|
|
35
|
+
if (Platform.OS !== 'ios') {
|
|
36
|
+
return TrackingStatus.NotSupported
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const raw = await NativeRNKontext.getTrackingAuthorizationStatus()
|
|
40
|
+
return _mapRawStatus(raw)
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error(error)
|
|
43
|
+
return TrackingStatus.NotSupported
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function getAdvertisingId(): Promise<string | null> {
|
|
48
|
+
try {
|
|
49
|
+
const id = await NativeRNKontext.getAdvertisingId()
|
|
50
|
+
return _normalizeId(id)
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error(error)
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function getVendorId(): Promise<string | null> {
|
|
58
|
+
if (Platform.OS !== 'ios') {
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const id = await NativeRNKontext.getVendorId()
|
|
63
|
+
return _normalizeId(id)
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error(error)
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function resolveIds(fallbacks?: {
|
|
71
|
+
vendorId?: string | undefined
|
|
72
|
+
advertisingId?: string | undefined
|
|
73
|
+
}): Promise<{ vendorId: string | null; advertisingId: string | null }> {
|
|
74
|
+
const [vendorId, advertisingId] = await Promise.all([getVendorId(), getAdvertisingId()])
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
vendorId: vendorId ?? _normalizeId(fallbacks?.vendorId),
|
|
78
|
+
advertisingId: advertisingId ?? _normalizeId(fallbacks?.advertisingId),
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ─── internal ────────────────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
async function _runStartupFlow(): Promise<void> {
|
|
85
|
+
if (Platform.OS !== 'ios') return
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
if (!_isVersionAtLeast145(Platform.Version)) return
|
|
89
|
+
|
|
90
|
+
const status = await getTrackingAuthorizationStatus()
|
|
91
|
+
if (status !== TrackingStatus.NotDetermined) return
|
|
92
|
+
|
|
93
|
+
await NativeRNKontext.requestTrackingAuthorization()
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.error(error)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* iOS 14.0–14.4: ATT dialog not required for IDFA access.
|
|
101
|
+
* Requesting it risks permanent denial, so we only request on >= 14.5.
|
|
102
|
+
*/
|
|
103
|
+
function _isVersionAtLeast145(version: string): boolean {
|
|
104
|
+
const [major = 0, minor = 0] = version.split('.').map(Number)
|
|
105
|
+
return major > 14 || (major === 14 && minor >= 5)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function _mapRawStatus(raw: number): TrackingStatus {
|
|
109
|
+
if (raw >= 0 && raw <= 4) return raw as TrackingStatus
|
|
110
|
+
return TrackingStatus.NotSupported
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function _normalizeId(id: string | null | undefined): string | null {
|
|
114
|
+
if (!id || id.trim() === '') return null
|
|
115
|
+
if (id.toLowerCase() === ZERO_UUID) return null
|
|
116
|
+
return id
|
|
117
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Platform } from 'react-native'
|
|
2
|
+
import NativeRNKontext from '../NativeRNKontext'
|
|
3
|
+
|
|
4
|
+
export interface SkAdNetworkFidelity {
|
|
5
|
+
fidelity: number
|
|
6
|
+
signature: string
|
|
7
|
+
nonce: string
|
|
8
|
+
timestamp: string | number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SkAdNetworkImpressionParams {
|
|
12
|
+
// Required
|
|
13
|
+
version: string
|
|
14
|
+
network: string
|
|
15
|
+
itunesItem: string | number
|
|
16
|
+
sourceApp: string | number
|
|
17
|
+
// Optional
|
|
18
|
+
sourceIdentifier?: string | number
|
|
19
|
+
campaign?: string | number
|
|
20
|
+
fidelities?: SkAdNetworkFidelity[]
|
|
21
|
+
nonce?: string
|
|
22
|
+
timestamp?: string | number
|
|
23
|
+
signature?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let impressionReady = false
|
|
27
|
+
|
|
28
|
+
export async function initSkAdNetworkImpression(params: SkAdNetworkImpressionParams): Promise<boolean> {
|
|
29
|
+
if (Platform.OS !== 'ios') return false
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const result = await NativeRNKontext.initSkAdNetworkImpression(params)
|
|
33
|
+
impressionReady = result
|
|
34
|
+
return result
|
|
35
|
+
} catch (e) {
|
|
36
|
+
impressionReady = false
|
|
37
|
+
console.error('[SKAdNetwork] Error initializing impression:', e)
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function startSkAdNetworkImpression(): Promise<boolean> {
|
|
43
|
+
if (Platform.OS !== 'ios' || !impressionReady) return false
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
return await NativeRNKontext.startSkAdNetworkImpression()
|
|
47
|
+
} catch (e) {
|
|
48
|
+
console.error('[SKAdNetwork] Error starting impression:', e)
|
|
49
|
+
return false
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function endSkAdNetworkImpression(): Promise<boolean> {
|
|
54
|
+
if (Platform.OS !== 'ios' || !impressionReady) return false
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
return await NativeRNKontext.endSkAdNetworkImpression()
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.error('[SKAdNetwork] Error ending impression:', e)
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function disposeSkAdNetwork(): Promise<boolean> {
|
|
65
|
+
impressionReady = false
|
|
66
|
+
|
|
67
|
+
if (Platform.OS !== 'ios') return false
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
return await NativeRNKontext.disposeSkAdNetwork()
|
|
71
|
+
} catch (e) {
|
|
72
|
+
console.error('[SKAdNetwork] Error disposing:', e)
|
|
73
|
+
return false
|
|
74
|
+
}
|
|
75
|
+
}
|