@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
package/RNKontext.podspec
CHANGED
package/android/build.gradle
CHANGED
|
@@ -86,4 +86,5 @@ dependencies {
|
|
|
86
86
|
implementation "com.facebook.react:react-android"
|
|
87
87
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
88
88
|
implementation "androidx.preference:preference:1.2.1"
|
|
89
|
+
implementation "com.google.android.gms:play-services-ads-identifier:18.0.1"
|
|
89
90
|
}
|
|
@@ -1,16 +1,50 @@
|
|
|
1
1
|
package so.kontext.react
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.os.Handler
|
|
5
|
+
import android.os.Looper
|
|
4
6
|
import android.media.AudioManager
|
|
5
7
|
import androidx.preference.PreferenceManager
|
|
6
8
|
import com.facebook.react.bridge.Arguments
|
|
7
9
|
import com.facebook.react.bridge.Promise
|
|
8
10
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
9
11
|
import com.facebook.react.bridge.WritableMap
|
|
12
|
+
import com.google.android.gms.ads.identifier.AdvertisingIdClient
|
|
13
|
+
import java.util.concurrent.Executors
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
class RNKontextModuleImpl(private val reactContext: ReactApplicationContext) {
|
|
13
17
|
|
|
18
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
19
|
+
private val executor = Executors.newSingleThreadExecutor()
|
|
20
|
+
|
|
21
|
+
fun getAdvertisingId(promise: Promise?) {
|
|
22
|
+
if (promise == null) return
|
|
23
|
+
executor.execute {
|
|
24
|
+
val id = try {
|
|
25
|
+
val info = AdvertisingIdClient.getAdvertisingIdInfo(reactContext.applicationContext)
|
|
26
|
+
if (info.isLimitAdTrackingEnabled) null else info.id
|
|
27
|
+
} catch (_: Exception) {
|
|
28
|
+
null
|
|
29
|
+
}
|
|
30
|
+
mainHandler.post { promise.resolve(id) }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Android has no IDFV equivalent — iOS only
|
|
35
|
+
fun getVendorId(promise: Promise?) {
|
|
36
|
+
promise?.resolve(null)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Android has no ATT — iOS only
|
|
40
|
+
fun getTrackingAuthorizationStatus(promise: Promise?) {
|
|
41
|
+
promise?.resolve(4) // TrackingStatus.NotSupported
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fun requestTrackingAuthorization(promise: Promise?) {
|
|
45
|
+
promise?.resolve(4) // TrackingStatus.NotSupported
|
|
46
|
+
}
|
|
47
|
+
|
|
14
48
|
fun isSoundOn(promise: Promise?) {
|
|
15
49
|
val audioManager = reactContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
16
50
|
val current = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
|
@@ -12,6 +12,22 @@ class RNKontextModule(reactContext: ReactApplicationContext) :
|
|
|
12
12
|
|
|
13
13
|
override fun getName(): String = NAME
|
|
14
14
|
|
|
15
|
+
override fun getAdvertisingId(promise: Promise?) {
|
|
16
|
+
impl.getAdvertisingId(promise)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override fun getVendorId(promise: Promise?) {
|
|
20
|
+
impl.getVendorId(promise)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
override fun getTrackingAuthorizationStatus(promise: Promise?) {
|
|
24
|
+
impl.getTrackingAuthorizationStatus(promise)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
override fun requestTrackingAuthorization(promise: Promise?) {
|
|
28
|
+
impl.requestTrackingAuthorization(promise)
|
|
29
|
+
}
|
|
30
|
+
|
|
15
31
|
override fun isSoundOn(promise: Promise?) {
|
|
16
32
|
impl.isSoundOn(promise)
|
|
17
33
|
}
|
|
@@ -38,6 +54,23 @@ class RNKontextModule(reactContext: ReactApplicationContext) :
|
|
|
38
54
|
promise?.resolve(false)
|
|
39
55
|
}
|
|
40
56
|
|
|
57
|
+
// ---------- iOS-only: SKAdNetwork ----------
|
|
58
|
+
override fun initSkAdNetworkImpression(params: com.facebook.react.bridge.ReadableMap, promise: Promise?) {
|
|
59
|
+
promise?.resolve(false)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
override fun startSkAdNetworkImpression(promise: Promise?) {
|
|
63
|
+
promise?.resolve(false)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
override fun endSkAdNetworkImpression(promise: Promise?) {
|
|
67
|
+
promise?.resolve(false)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
override fun disposeSkAdNetwork(promise: Promise?) {
|
|
71
|
+
promise?.resolve(false)
|
|
72
|
+
}
|
|
73
|
+
|
|
41
74
|
companion object {
|
|
42
75
|
const val NAME = "RNKontext"
|
|
43
76
|
}
|
|
@@ -14,6 +14,26 @@ class RNKontextModule(reactContext: ReactApplicationContext) :
|
|
|
14
14
|
|
|
15
15
|
override fun getName(): String = NAME
|
|
16
16
|
|
|
17
|
+
@ReactMethod
|
|
18
|
+
fun getAdvertisingId(promise: Promise?) {
|
|
19
|
+
impl.getAdvertisingId(promise)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@ReactMethod
|
|
23
|
+
fun getVendorId(promise: Promise?) {
|
|
24
|
+
impl.getVendorId(promise)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@ReactMethod
|
|
28
|
+
fun getTrackingAuthorizationStatus(promise: Promise?) {
|
|
29
|
+
impl.getTrackingAuthorizationStatus(promise)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@ReactMethod
|
|
33
|
+
fun requestTrackingAuthorization(promise: Promise?) {
|
|
34
|
+
impl.requestTrackingAuthorization(promise)
|
|
35
|
+
}
|
|
36
|
+
|
|
17
37
|
@ReactMethod
|
|
18
38
|
fun isSoundOn(promise: Promise?) {
|
|
19
39
|
impl.isSoundOn(promise)
|
|
@@ -46,6 +66,27 @@ class RNKontextModule(reactContext: ReactApplicationContext) :
|
|
|
46
66
|
impl.getTcfData(promise)
|
|
47
67
|
}
|
|
48
68
|
|
|
69
|
+
// ---------- iOS-only: SKAdNetwork ----------
|
|
70
|
+
@ReactMethod
|
|
71
|
+
fun initSkAdNetworkImpression(params: com.facebook.react.bridge.ReadableMap, promise: Promise?) {
|
|
72
|
+
promise?.resolve(false)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@ReactMethod
|
|
76
|
+
fun startSkAdNetworkImpression(promise: Promise?) {
|
|
77
|
+
promise?.resolve(false)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@ReactMethod
|
|
81
|
+
fun endSkAdNetworkImpression(promise: Promise?) {
|
|
82
|
+
promise?.resolve(false)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@ReactMethod
|
|
86
|
+
fun disposeSkAdNetwork(promise: Promise?) {
|
|
87
|
+
promise?.resolve(false)
|
|
88
|
+
}
|
|
89
|
+
|
|
49
90
|
companion object {
|
|
50
91
|
const val NAME = "RNKontext"
|
|
51
92
|
}
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ var __export = (target, all) => {
|
|
|
11
11
|
};
|
|
12
12
|
var __copyProps = (to, from, except, desc) => {
|
|
13
13
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (
|
|
14
|
+
for (const key of __getOwnPropNames(from))
|
|
15
15
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
16
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
17
|
}
|
|
@@ -684,13 +684,92 @@ var InlineAd_default = InlineAd;
|
|
|
684
684
|
// src/context/AdsProvider.tsx
|
|
685
685
|
var import_sdk_react2 = require("@kontextso/sdk-react");
|
|
686
686
|
var import_netinfo = require("@react-native-community/netinfo");
|
|
687
|
-
var
|
|
687
|
+
var import_react_native7 = require("react-native");
|
|
688
688
|
var import_react_native_device_info = __toESM(require("react-native-device-info"));
|
|
689
689
|
|
|
690
690
|
// package.json
|
|
691
|
-
var version = "3.
|
|
691
|
+
var version = "3.4.0-rc.0";
|
|
692
|
+
|
|
693
|
+
// src/services/Att.ts
|
|
694
|
+
var import_react_native6 = require("react-native");
|
|
695
|
+
var ZERO_UUID = "00000000-0000-0000-0000-000000000000";
|
|
696
|
+
var didRunStartupFlow = false;
|
|
697
|
+
var startupFlowPromise = null;
|
|
698
|
+
function requestTrackingAuthorization() {
|
|
699
|
+
if (didRunStartupFlow) {
|
|
700
|
+
return startupFlowPromise ?? Promise.resolve();
|
|
701
|
+
}
|
|
702
|
+
didRunStartupFlow = true;
|
|
703
|
+
startupFlowPromise = _runStartupFlow();
|
|
704
|
+
return startupFlowPromise;
|
|
705
|
+
}
|
|
706
|
+
async function getTrackingAuthorizationStatus() {
|
|
707
|
+
if (import_react_native6.Platform.OS !== "ios") {
|
|
708
|
+
return 4 /* NotSupported */;
|
|
709
|
+
}
|
|
710
|
+
try {
|
|
711
|
+
const raw = await NativeRNKontext_default.getTrackingAuthorizationStatus();
|
|
712
|
+
return _mapRawStatus(raw);
|
|
713
|
+
} catch (error) {
|
|
714
|
+
console.error(error);
|
|
715
|
+
return 4 /* NotSupported */;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
async function getAdvertisingId() {
|
|
719
|
+
try {
|
|
720
|
+
const id = await NativeRNKontext_default.getAdvertisingId();
|
|
721
|
+
return _normalizeId(id);
|
|
722
|
+
} catch (error) {
|
|
723
|
+
console.error(error);
|
|
724
|
+
return null;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
async function getVendorId() {
|
|
728
|
+
if (import_react_native6.Platform.OS !== "ios") {
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
try {
|
|
732
|
+
const id = await NativeRNKontext_default.getVendorId();
|
|
733
|
+
return _normalizeId(id);
|
|
734
|
+
} catch (error) {
|
|
735
|
+
console.error(error);
|
|
736
|
+
return null;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
async function resolveIds(fallbacks) {
|
|
740
|
+
const [vendorId, advertisingId] = await Promise.all([getVendorId(), getAdvertisingId()]);
|
|
741
|
+
return {
|
|
742
|
+
vendorId: vendorId ?? _normalizeId(fallbacks?.vendorId),
|
|
743
|
+
advertisingId: advertisingId ?? _normalizeId(fallbacks?.advertisingId)
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
async function _runStartupFlow() {
|
|
747
|
+
if (import_react_native6.Platform.OS !== "ios") return;
|
|
748
|
+
try {
|
|
749
|
+
if (!_isVersionAtLeast145(import_react_native6.Platform.Version)) return;
|
|
750
|
+
const status = await getTrackingAuthorizationStatus();
|
|
751
|
+
if (status !== 0 /* NotDetermined */) return;
|
|
752
|
+
await NativeRNKontext_default.requestTrackingAuthorization();
|
|
753
|
+
} catch (error) {
|
|
754
|
+
console.error(error);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
function _isVersionAtLeast145(version2) {
|
|
758
|
+
const [major = 0, minor = 0] = version2.split(".").map(Number);
|
|
759
|
+
return major > 14 || major === 14 && minor >= 5;
|
|
760
|
+
}
|
|
761
|
+
function _mapRawStatus(raw) {
|
|
762
|
+
if (raw >= 0 && raw <= 4) return raw;
|
|
763
|
+
return 4 /* NotSupported */;
|
|
764
|
+
}
|
|
765
|
+
function _normalizeId(id) {
|
|
766
|
+
if (!id || id.trim() === "") return null;
|
|
767
|
+
if (id.toLowerCase() === ZERO_UUID) return null;
|
|
768
|
+
return id;
|
|
769
|
+
}
|
|
692
770
|
|
|
693
771
|
// src/context/AdsProvider.tsx
|
|
772
|
+
var import_react3 = require("react");
|
|
694
773
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
695
774
|
ErrorUtils.setGlobalHandler((error, isFatal) => {
|
|
696
775
|
if (!isFatal) {
|
|
@@ -709,7 +788,7 @@ var getDevice = async () => {
|
|
|
709
788
|
const powerState = await import_react_native_device_info.default.getPowerState();
|
|
710
789
|
const deviceType = import_react_native_device_info.default.getDeviceType();
|
|
711
790
|
const soundOn = await NativeRNKontext_default.isSoundOn();
|
|
712
|
-
const screen =
|
|
791
|
+
const screen = import_react_native7.Dimensions.get("screen");
|
|
713
792
|
const networkInfo = await (0, import_netinfo.fetch)();
|
|
714
793
|
const mapDeviceTypeToHardwareType = () => {
|
|
715
794
|
switch (deviceType) {
|
|
@@ -746,14 +825,14 @@ var getDevice = async () => {
|
|
|
746
825
|
detail: networkInfo.type === import_netinfo.NetInfoStateType.cellular && networkInfo.details.cellularGeneration || void 0
|
|
747
826
|
},
|
|
748
827
|
os: {
|
|
749
|
-
name:
|
|
828
|
+
name: import_react_native7.Platform.OS,
|
|
750
829
|
version: import_react_native_device_info.default.getSystemVersion(),
|
|
751
830
|
locale: Intl.DateTimeFormat().resolvedOptions().locale,
|
|
752
831
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
753
832
|
},
|
|
754
833
|
screen: {
|
|
755
|
-
darkMode:
|
|
756
|
-
dpr:
|
|
834
|
+
darkMode: import_react_native7.Appearance.getColorScheme() === "dark",
|
|
835
|
+
dpr: import_react_native7.PixelRatio.get(),
|
|
757
836
|
height: screen.height,
|
|
758
837
|
width: screen.width,
|
|
759
838
|
orientation: screen.width > screen.height ? "landscape" : "portrait"
|
|
@@ -786,7 +865,7 @@ var getApp = async () => {
|
|
|
786
865
|
};
|
|
787
866
|
var getSdk = async () => ({
|
|
788
867
|
name: "sdk-react-native",
|
|
789
|
-
platform:
|
|
868
|
+
platform: import_react_native7.Platform.OS === "ios" ? "ios" : "android",
|
|
790
869
|
version
|
|
791
870
|
});
|
|
792
871
|
var getTcf = async () => {
|
|
@@ -804,7 +883,38 @@ var getTcf = async () => {
|
|
|
804
883
|
}
|
|
805
884
|
};
|
|
806
885
|
var AdsProvider = (props) => {
|
|
807
|
-
|
|
886
|
+
const [advertisingId, setAdvertisingId] = (0, import_react3.useState)();
|
|
887
|
+
const [vendorId, setVendorId] = (0, import_react3.useState)();
|
|
888
|
+
const initializeIfa = async () => {
|
|
889
|
+
try {
|
|
890
|
+
if (import_react_native7.Platform.OS === "ios") {
|
|
891
|
+
await requestTrackingAuthorization();
|
|
892
|
+
}
|
|
893
|
+
const ids = await resolveIds({
|
|
894
|
+
advertisingId: props.advertisingId ?? void 0,
|
|
895
|
+
vendorId: props.vendorId ?? void 0
|
|
896
|
+
});
|
|
897
|
+
setAdvertisingId(ids.advertisingId);
|
|
898
|
+
setVendorId(ids.vendorId);
|
|
899
|
+
} catch (error) {
|
|
900
|
+
console.error(error);
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
(0, import_react3.useEffect)(() => {
|
|
904
|
+
initializeIfa();
|
|
905
|
+
}, []);
|
|
906
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
907
|
+
import_sdk_react2.AdsProviderInternal,
|
|
908
|
+
{
|
|
909
|
+
...props,
|
|
910
|
+
advertisingId,
|
|
911
|
+
vendorId,
|
|
912
|
+
getDevice,
|
|
913
|
+
getSdk,
|
|
914
|
+
getApp,
|
|
915
|
+
getTcf
|
|
916
|
+
}
|
|
917
|
+
);
|
|
808
918
|
};
|
|
809
919
|
// Annotate the CommonJS export names for ESM import in node:
|
|
810
920
|
0 && (module.exports = {
|
package/dist/index.mjs
CHANGED
|
@@ -656,13 +656,92 @@ import {
|
|
|
656
656
|
log
|
|
657
657
|
} from "@kontextso/sdk-react";
|
|
658
658
|
import { fetch as fetchNetworkInfo, NetInfoStateType } from "@react-native-community/netinfo";
|
|
659
|
-
import { Appearance, Dimensions, PixelRatio, Platform as
|
|
659
|
+
import { Appearance, Dimensions, PixelRatio, Platform as Platform4 } from "react-native";
|
|
660
660
|
import DeviceInfo from "react-native-device-info";
|
|
661
661
|
|
|
662
662
|
// package.json
|
|
663
|
-
var version = "3.
|
|
663
|
+
var version = "3.4.0-rc.0";
|
|
664
|
+
|
|
665
|
+
// src/services/Att.ts
|
|
666
|
+
import { Platform as Platform3 } from "react-native";
|
|
667
|
+
var ZERO_UUID = "00000000-0000-0000-0000-000000000000";
|
|
668
|
+
var didRunStartupFlow = false;
|
|
669
|
+
var startupFlowPromise = null;
|
|
670
|
+
function requestTrackingAuthorization() {
|
|
671
|
+
if (didRunStartupFlow) {
|
|
672
|
+
return startupFlowPromise ?? Promise.resolve();
|
|
673
|
+
}
|
|
674
|
+
didRunStartupFlow = true;
|
|
675
|
+
startupFlowPromise = _runStartupFlow();
|
|
676
|
+
return startupFlowPromise;
|
|
677
|
+
}
|
|
678
|
+
async function getTrackingAuthorizationStatus() {
|
|
679
|
+
if (Platform3.OS !== "ios") {
|
|
680
|
+
return 4 /* NotSupported */;
|
|
681
|
+
}
|
|
682
|
+
try {
|
|
683
|
+
const raw = await NativeRNKontext_default.getTrackingAuthorizationStatus();
|
|
684
|
+
return _mapRawStatus(raw);
|
|
685
|
+
} catch (error) {
|
|
686
|
+
console.error(error);
|
|
687
|
+
return 4 /* NotSupported */;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
async function getAdvertisingId() {
|
|
691
|
+
try {
|
|
692
|
+
const id = await NativeRNKontext_default.getAdvertisingId();
|
|
693
|
+
return _normalizeId(id);
|
|
694
|
+
} catch (error) {
|
|
695
|
+
console.error(error);
|
|
696
|
+
return null;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
async function getVendorId() {
|
|
700
|
+
if (Platform3.OS !== "ios") {
|
|
701
|
+
return null;
|
|
702
|
+
}
|
|
703
|
+
try {
|
|
704
|
+
const id = await NativeRNKontext_default.getVendorId();
|
|
705
|
+
return _normalizeId(id);
|
|
706
|
+
} catch (error) {
|
|
707
|
+
console.error(error);
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
async function resolveIds(fallbacks) {
|
|
712
|
+
const [vendorId, advertisingId] = await Promise.all([getVendorId(), getAdvertisingId()]);
|
|
713
|
+
return {
|
|
714
|
+
vendorId: vendorId ?? _normalizeId(fallbacks?.vendorId),
|
|
715
|
+
advertisingId: advertisingId ?? _normalizeId(fallbacks?.advertisingId)
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
async function _runStartupFlow() {
|
|
719
|
+
if (Platform3.OS !== "ios") return;
|
|
720
|
+
try {
|
|
721
|
+
if (!_isVersionAtLeast145(Platform3.Version)) return;
|
|
722
|
+
const status = await getTrackingAuthorizationStatus();
|
|
723
|
+
if (status !== 0 /* NotDetermined */) return;
|
|
724
|
+
await NativeRNKontext_default.requestTrackingAuthorization();
|
|
725
|
+
} catch (error) {
|
|
726
|
+
console.error(error);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
function _isVersionAtLeast145(version2) {
|
|
730
|
+
const [major = 0, minor = 0] = version2.split(".").map(Number);
|
|
731
|
+
return major > 14 || major === 14 && minor >= 5;
|
|
732
|
+
}
|
|
733
|
+
function _mapRawStatus(raw) {
|
|
734
|
+
if (raw >= 0 && raw <= 4) return raw;
|
|
735
|
+
return 4 /* NotSupported */;
|
|
736
|
+
}
|
|
737
|
+
function _normalizeId(id) {
|
|
738
|
+
if (!id || id.trim() === "") return null;
|
|
739
|
+
if (id.toLowerCase() === ZERO_UUID) return null;
|
|
740
|
+
return id;
|
|
741
|
+
}
|
|
664
742
|
|
|
665
743
|
// src/context/AdsProvider.tsx
|
|
744
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
666
745
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
667
746
|
ErrorUtils.setGlobalHandler((error, isFatal) => {
|
|
668
747
|
if (!isFatal) {
|
|
@@ -718,7 +797,7 @@ var getDevice = async () => {
|
|
|
718
797
|
detail: networkInfo.type === NetInfoStateType.cellular && networkInfo.details.cellularGeneration || void 0
|
|
719
798
|
},
|
|
720
799
|
os: {
|
|
721
|
-
name:
|
|
800
|
+
name: Platform4.OS,
|
|
722
801
|
version: DeviceInfo.getSystemVersion(),
|
|
723
802
|
locale: Intl.DateTimeFormat().resolvedOptions().locale,
|
|
724
803
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
@@ -758,7 +837,7 @@ var getApp = async () => {
|
|
|
758
837
|
};
|
|
759
838
|
var getSdk = async () => ({
|
|
760
839
|
name: "sdk-react-native",
|
|
761
|
-
platform:
|
|
840
|
+
platform: Platform4.OS === "ios" ? "ios" : "android",
|
|
762
841
|
version
|
|
763
842
|
});
|
|
764
843
|
var getTcf = async () => {
|
|
@@ -776,7 +855,38 @@ var getTcf = async () => {
|
|
|
776
855
|
}
|
|
777
856
|
};
|
|
778
857
|
var AdsProvider = (props) => {
|
|
779
|
-
|
|
858
|
+
const [advertisingId, setAdvertisingId] = useState2();
|
|
859
|
+
const [vendorId, setVendorId] = useState2();
|
|
860
|
+
const initializeIfa = async () => {
|
|
861
|
+
try {
|
|
862
|
+
if (Platform4.OS === "ios") {
|
|
863
|
+
await requestTrackingAuthorization();
|
|
864
|
+
}
|
|
865
|
+
const ids = await resolveIds({
|
|
866
|
+
advertisingId: props.advertisingId ?? void 0,
|
|
867
|
+
vendorId: props.vendorId ?? void 0
|
|
868
|
+
});
|
|
869
|
+
setAdvertisingId(ids.advertisingId);
|
|
870
|
+
setVendorId(ids.vendorId);
|
|
871
|
+
} catch (error) {
|
|
872
|
+
console.error(error);
|
|
873
|
+
}
|
|
874
|
+
};
|
|
875
|
+
useEffect2(() => {
|
|
876
|
+
initializeIfa();
|
|
877
|
+
}, []);
|
|
878
|
+
return /* @__PURE__ */ jsx4(
|
|
879
|
+
AdsProviderInternal,
|
|
880
|
+
{
|
|
881
|
+
...props,
|
|
882
|
+
advertisingId,
|
|
883
|
+
vendorId,
|
|
884
|
+
getDevice,
|
|
885
|
+
getSdk,
|
|
886
|
+
getApp,
|
|
887
|
+
getTcf
|
|
888
|
+
}
|
|
889
|
+
);
|
|
780
890
|
};
|
|
781
891
|
export {
|
|
782
892
|
AdsProvider,
|
package/ios/KontextSDK.swift
CHANGED
|
@@ -3,6 +3,8 @@ import AVFoundation
|
|
|
3
3
|
import StoreKit
|
|
4
4
|
import UIKit
|
|
5
5
|
import React
|
|
6
|
+
import AdSupport
|
|
7
|
+
import AppTrackingTransparency
|
|
6
8
|
|
|
7
9
|
@objc(KontextSDK)
|
|
8
10
|
public class KontextSDK: NSObject {
|
|
@@ -98,6 +100,65 @@ public class KontextSDK: NSObject {
|
|
|
98
100
|
}
|
|
99
101
|
}
|
|
100
102
|
|
|
103
|
+
// MARK: - SKAdNetwork
|
|
104
|
+
|
|
105
|
+
@objc
|
|
106
|
+
public static func initSkAdNetworkImpression(
|
|
107
|
+
_ params: [String: Any],
|
|
108
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
109
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
110
|
+
) {
|
|
111
|
+
SKAdNetworkManager.shared.initImpression(params: params) { success, error in
|
|
112
|
+
if let error = error {
|
|
113
|
+
reject("SKAN_INIT_IMPRESSION_FAILED", error.localizedDescription, error)
|
|
114
|
+
} else {
|
|
115
|
+
resolve(success)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@objc
|
|
121
|
+
public static func startSkAdNetworkImpression(
|
|
122
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
123
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
124
|
+
) {
|
|
125
|
+
SKAdNetworkManager.shared.startImpression { success, error in
|
|
126
|
+
if let error = error {
|
|
127
|
+
reject("SKAN_START_IMPRESSION_FAILED", error.localizedDescription, error)
|
|
128
|
+
} else {
|
|
129
|
+
resolve(success)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@objc
|
|
135
|
+
public static func endSkAdNetworkImpression(
|
|
136
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
137
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
138
|
+
) {
|
|
139
|
+
SKAdNetworkManager.shared.endImpression { success, error in
|
|
140
|
+
if let error = error {
|
|
141
|
+
reject("SKAN_END_IMPRESSION_FAILED", error.localizedDescription, error)
|
|
142
|
+
} else {
|
|
143
|
+
resolve(success)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@objc
|
|
149
|
+
public static func disposeSkAdNetwork(
|
|
150
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
151
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
152
|
+
) {
|
|
153
|
+
SKAdNetworkManager.shared.dispose { success, error in
|
|
154
|
+
if let error = error {
|
|
155
|
+
reject("SKAN_DISPOSE_FAILED", error.localizedDescription, error)
|
|
156
|
+
} else {
|
|
157
|
+
resolve(success)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
101
162
|
// MARK: - TCF (minimal: GDPR applies + TC string)
|
|
102
163
|
|
|
103
164
|
/// Returns minimal TCF data needed for RTB:
|
|
@@ -134,4 +195,49 @@ public class KontextSDK: NSObject {
|
|
|
134
195
|
return out
|
|
135
196
|
}
|
|
136
197
|
|
|
198
|
+
// MARK: - ATT / IFA
|
|
199
|
+
|
|
200
|
+
private static let notSupportedStatus = 4
|
|
201
|
+
|
|
202
|
+
@objc
|
|
203
|
+
public static func getTrackingAuthorizationStatus() -> NSNumber {
|
|
204
|
+
if #available(iOS 14, *) {
|
|
205
|
+
return NSNumber(value: ATTrackingManager.trackingAuthorizationStatus.rawValue)
|
|
206
|
+
}
|
|
207
|
+
return NSNumber(value: notSupportedStatus)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@objc
|
|
211
|
+
public static func requestTrackingAuthorization(
|
|
212
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
213
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
214
|
+
) {
|
|
215
|
+
if #available(iOS 14, *) {
|
|
216
|
+
TrackingAuthorizationManager.shared.requestTrackingAuthorization { statusRaw in
|
|
217
|
+
resolve(NSNumber(value: statusRaw))
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
resolve(NSNumber(value: notSupportedStatus))
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
@objc
|
|
225
|
+
public static func getAdvertisingId() -> String? {
|
|
226
|
+
let manager = ASIdentifierManager.shared()
|
|
227
|
+
if #available(iOS 14.0, *) {
|
|
228
|
+
guard ATTrackingManager.trackingAuthorizationStatus == .authorized else {
|
|
229
|
+
return nil
|
|
230
|
+
}
|
|
231
|
+
return manager.advertisingIdentifier.uuidString
|
|
232
|
+
}
|
|
233
|
+
return manager.isAdvertisingTrackingEnabled
|
|
234
|
+
? manager.advertisingIdentifier.uuidString
|
|
235
|
+
: nil
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@objc
|
|
239
|
+
public static func getVendorId() -> String? {
|
|
240
|
+
return UIDevice.current.identifierForVendor?.uuidString
|
|
241
|
+
}
|
|
242
|
+
|
|
137
243
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
|
|
6
|
+
<key>NSPrivacyTracking</key><true/>
|
|
7
|
+
|
|
8
|
+
<key>NSPrivacyTrackingDomains</key>
|
|
9
|
+
<array>
|
|
10
|
+
<string>megabrain.co</string>
|
|
11
|
+
</array>
|
|
12
|
+
|
|
13
|
+
<key>NSPrivacyCollectedDataTypes</key>
|
|
14
|
+
<array>
|
|
15
|
+
|
|
16
|
+
<dict>
|
|
17
|
+
<key>NSPrivacyCollectedDataType</key>
|
|
18
|
+
<string>NSPrivacyCollectedDataTypeDeviceID</string>
|
|
19
|
+
<key>NSPrivacyCollectedDataTypeLinked</key><true/>
|
|
20
|
+
<key>NSPrivacyCollectedDataTypeTracking</key><true/>
|
|
21
|
+
<key>NSPrivacyCollectedDataTypePurposes</key>
|
|
22
|
+
<array>
|
|
23
|
+
<string>NSPrivacyCollectedDataTypePurposeThirdPartyAdvertising</string>
|
|
24
|
+
</array>
|
|
25
|
+
</dict>
|
|
26
|
+
|
|
27
|
+
<dict>
|
|
28
|
+
<key>NSPrivacyCollectedDataType</key>
|
|
29
|
+
<string>NSPrivacyCollectedDataTypeOtherAppInfo</string>
|
|
30
|
+
<key>NSPrivacyCollectedDataTypeLinked</key><false/>
|
|
31
|
+
<key>NSPrivacyCollectedDataTypeTracking</key><false/>
|
|
32
|
+
<key>NSPrivacyCollectedDataTypePurposes</key>
|
|
33
|
+
<array>
|
|
34
|
+
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
|
|
35
|
+
</array>
|
|
36
|
+
</dict>
|
|
37
|
+
|
|
38
|
+
<dict>
|
|
39
|
+
<key>NSPrivacyCollectedDataType</key>
|
|
40
|
+
<string>NSPrivacyCollectedDataTypeOtherDiagnosticData</string>
|
|
41
|
+
<key>NSPrivacyCollectedDataTypeLinked</key><false/>
|
|
42
|
+
<key>NSPrivacyCollectedDataTypeTracking</key><false/>
|
|
43
|
+
<key>NSPrivacyCollectedDataTypePurposes</key>
|
|
44
|
+
<array>
|
|
45
|
+
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
|
|
46
|
+
</array>
|
|
47
|
+
</dict>
|
|
48
|
+
|
|
49
|
+
</array>
|
|
50
|
+
|
|
51
|
+
<key>NSPrivacyAccessedAPITypes</key>
|
|
52
|
+
<array>
|
|
53
|
+
<dict>
|
|
54
|
+
<key>NSPrivacyAccessedAPIType</key>
|
|
55
|
+
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
|
56
|
+
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
57
|
+
<array>
|
|
58
|
+
<string>CA92.1</string>
|
|
59
|
+
</array>
|
|
60
|
+
</dict>
|
|
61
|
+
</array>
|
|
62
|
+
|
|
63
|
+
</dict>
|
|
64
|
+
</plist>
|