react-native-nami-sdk 2.0.4 → 3.0.8
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/.github/workflows/app_stg.yaml +203 -0
- package/.github/workflows/build.yml +2 -2
- package/.pre-commit-config.yaml +25 -0
- package/android/build.gradle +24 -13
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -1
- package/android/src/main/java/com/nami/reactlibrary/Constants.kt +1 -1
- package/android/src/main/java/com/nami/reactlibrary/NamiBridgeModule.kt +6 -50
- package/android/src/main/java/com/nami/reactlibrary/NamiBridgePackage.java +1 -3
- package/android/src/main/java/com/nami/reactlibrary/NamiCampaignManagerBridge.kt +133 -0
- package/android/src/main/java/com/nami/reactlibrary/NamiCustomerManagerBridge.kt +89 -20
- package/android/src/main/java/com/nami/reactlibrary/NamiEmitter.kt +25 -25
- package/android/src/main/java/com/nami/reactlibrary/NamiEntitlementManagerBridgeModule.kt +31 -130
- package/android/src/main/java/com/nami/reactlibrary/NamiMLManagerBridgeModule.kt +1 -1
- package/android/src/main/java/com/nami/reactlibrary/NamiPaywallManagerBridgeModule.kt +36 -147
- package/android/src/main/java/com/nami/reactlibrary/NamiPurchaseManagerBridge.kt +37 -39
- package/android/src/main/java/com/nami/reactlibrary/NamiUtil.kt +50 -180
- package/build-utils/get_version_code.py +140 -0
- package/index.d.ts +20 -0
- package/index.js +7 -6
- package/ios/Nami.m +18 -72
- package/ios/NamiBridgeUtil.h +4 -6
- package/ios/NamiBridgeUtil.m +37 -99
- package/ios/NamiCampaignManagerBridge.m +26 -0
- package/ios/NamiCampaignManagerBridge.swift +107 -0
- package/ios/NamiCustomerManager.m +19 -24
- package/ios/NamiCustomerManager.swift +122 -0
- package/ios/NamiEmitter.m +85 -95
- package/ios/NamiEntitlementManagerBridge.m +7 -107
- package/ios/NamiEntitlementManagerBridge.swift +74 -0
- package/ios/NamiMLManagerBridge.m +2 -2
- package/ios/NamiPaywallManagerBridge.m +22 -94
- package/ios/NamiPaywallManagerBridge.swift +93 -0
- package/ios/NamiPurchaseManagerBridge.m +40 -71
- package/ios/NamiPurchaseManagerBridge.swift +174 -0
- package/ios/Podfile +2 -2
- package/ios/RNNami-Bridging-Header.h +5 -0
- package/ios/RNNami.h +0 -1
- package/ios/RNNami.m +1 -1
- package/ios/RNNami.xcodeproj/project.pbxproj +84 -8
- package/ios/RNNami.xcodeproj/xcshareddata/xcschemes/RNNami.xcscheme +67 -0
- package/package.json +1 -1
- package/react-native-nami-sdk.podspec +3 -3
- package/src/Nami.d.ts +112 -0
- package/src/Nami.js +10 -0
- package/src/NamiCampaignManager.d.ts +54 -0
- package/src/NamiCampaignManager.js +43 -0
- package/src/NamiCustomerManager.d.ts +39 -0
- package/src/NamiCustomerManager.js +43 -0
- package/src/NamiEntitlementManager.d.ts +24 -0
- package/src/NamiEntitlementManager.js +23 -0
- package/src/NamiMLManager.d.ts +5 -0
- package/src/NamiMLManager.js +7 -0
- package/src/NamiPaywallManager.d.ts +57 -0
- package/src/NamiPaywallManager.js +28 -0
- package/src/NamiPurchaseManager.d.ts +57 -0
- package/src/NamiPurchaseManager.js +37 -0
- package/src/types.ts +36 -0
- package/android/src/main/java/com/nami/reactlibrary/NamiAnalyticsEmitter.kt +0 -121
- package/ios/NamiAnalyticsEmitter.m +0 -146
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { EmitterSubscription } from "react-native";
|
|
2
|
+
import { NamiSKU } from "./types";
|
|
3
|
+
|
|
4
|
+
export const NamiPaywallManager: {
|
|
5
|
+
buySkuComplete: (purchaseSuccess: PurchaseSuccess) => void;
|
|
6
|
+
dismiss: (animated: boolean, callback: () => void) => void;
|
|
7
|
+
displayedViewController: () => void;
|
|
8
|
+
renderCustomUiHandler: () => any;
|
|
9
|
+
registerBuySkuHandler: (
|
|
10
|
+
callback: (sku: NamiSKU) => void
|
|
11
|
+
) => EmitterSubscription["remove"];
|
|
12
|
+
registerCloseHandler: (
|
|
13
|
+
blockDismiss: boolean,
|
|
14
|
+
callback: (resultObject: { blockingPaywallClosed: boolean }) => void
|
|
15
|
+
) => EmitterSubscription["remove"];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type PurchaseSuccess = {
|
|
19
|
+
product: PurchaseSuccessProduct;
|
|
20
|
+
transactionID: string;
|
|
21
|
+
originalTransactionID: string;
|
|
22
|
+
originalPurchaseDate: number;
|
|
23
|
+
purchaseDate: number;
|
|
24
|
+
expiresDate?: number;
|
|
25
|
+
price: string;
|
|
26
|
+
currencyCode: string;
|
|
27
|
+
locale: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type PurchaseSuccessProduct = {
|
|
31
|
+
id: string;
|
|
32
|
+
platformID: string;
|
|
33
|
+
skuId: string;
|
|
34
|
+
languageCode: string;
|
|
35
|
+
name: string;
|
|
36
|
+
featured: boolean;
|
|
37
|
+
storeId: string;
|
|
38
|
+
type: number;
|
|
39
|
+
isFeatured: boolean;
|
|
40
|
+
namiID: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export enum NamiPaywallAction {
|
|
44
|
+
BUY_SKU = "BUY_SKU",
|
|
45
|
+
SELECT_SKU = "SELECT_SKU",
|
|
46
|
+
RESTORE_PURCHASES = "RESTORE_PURCHASES",
|
|
47
|
+
SIGN_IN = "SIGN_IN",
|
|
48
|
+
CLOSE_PAYWALL = "CLOSE_PAYWALL",
|
|
49
|
+
SHOW_PAYWALL = "SHOW_PAYWALL",
|
|
50
|
+
PURCHASE_SELECTED_SKU = "PURCHASE_SELECTED_SKU",
|
|
51
|
+
PURCHASE_SUCCESS = "PURCHASE_SUCCESS",
|
|
52
|
+
PURCHASE_FAILED = "PURCHASE_FAILED",
|
|
53
|
+
PURCHASE_CANCELLED = "PURCHASE_CANCELLED",
|
|
54
|
+
PURCHASE_PENDING = "PURCHASE_PENDING",
|
|
55
|
+
PURCHASE_UNKNOWN = "PURCHASE_UNKNOWN",
|
|
56
|
+
PURCHASE_DEFERRED = "PURCHASE_DEFERRED",
|
|
57
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { NativeModules, NativeEventEmitter } from "react-native";
|
|
2
|
+
|
|
3
|
+
const { NamiPaywallManagerBridge, RNNamiPaywallManager } = NativeModules;
|
|
4
|
+
|
|
5
|
+
export const NamiPaywallManager = {
|
|
6
|
+
paywallEmitter: new NativeEventEmitter(RNNamiPaywallManager),
|
|
7
|
+
...RNNamiPaywallManager,
|
|
8
|
+
...NamiPaywallManagerBridge,
|
|
9
|
+
registerBuySkuHandler(callback) {
|
|
10
|
+
var subscription = this.paywallEmitter.addListener(
|
|
11
|
+
"RegisterBuySKU",
|
|
12
|
+
callback
|
|
13
|
+
);
|
|
14
|
+
RNNamiPaywallManager.registerBuySkuHandler();
|
|
15
|
+
return subscription.remove;
|
|
16
|
+
},
|
|
17
|
+
registerCloseHandler(blockDismiss, callback) {
|
|
18
|
+
var subscription;
|
|
19
|
+
subscription = this.paywallEmitter.addListener(
|
|
20
|
+
"BlockingPaywallClosed",
|
|
21
|
+
() => {
|
|
22
|
+
subscription.remove();
|
|
23
|
+
callback();
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
RNNamiPaywallManager.registerCloseHandler(blockDismiss);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { EmitterSubscription } from "react-native";
|
|
2
|
+
import { NamiSKU } from "./types";
|
|
3
|
+
import { NamiEntitlement } from "./NamiEntitlementManager";
|
|
4
|
+
|
|
5
|
+
export const NamiPurchaseManager: {
|
|
6
|
+
allPurchases: () => NamiPurchase[];
|
|
7
|
+
anySkuPurchased: (skuIds: string[]) => boolean;
|
|
8
|
+
consumePurchasedSku: (skuId: string) => void;
|
|
9
|
+
clearBypassStorePurchases: () => void;
|
|
10
|
+
presentCodeRedemptionSheet: () => void;
|
|
11
|
+
restorePurchases: () => void;
|
|
12
|
+
skuPurchased: (skuId: string) => boolean;
|
|
13
|
+
registerPurchasesChangedHandler: (
|
|
14
|
+
callback: (
|
|
15
|
+
purchaseState: NamiPurchasesState,
|
|
16
|
+
purchases: NamiPurchase[],
|
|
17
|
+
error: string
|
|
18
|
+
) => void
|
|
19
|
+
) => EmitterSubscription["remove"];
|
|
20
|
+
registerRestorePurchasesHandler: (
|
|
21
|
+
callback: (
|
|
22
|
+
state: NamiRestorePurchasesState,
|
|
23
|
+
newPurchases: NamiPurchase[],
|
|
24
|
+
oldPurchases: NamiPurchase[]
|
|
25
|
+
) => void
|
|
26
|
+
) => EmitterSubscription["remove"];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type NamiPurchase = {
|
|
30
|
+
sku?: NamiSKU;
|
|
31
|
+
skuId: string;
|
|
32
|
+
transactionIdentifier?: string;
|
|
33
|
+
expires?: Date;
|
|
34
|
+
purchaseInitiatedTimestamp: Date;
|
|
35
|
+
purchaseSource?: "CAMPAIGN" | "MARKETPLACE" | "UNKNOWN";
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export enum NamiPurchaseState {
|
|
39
|
+
PURCHASED = "PURCHASED",
|
|
40
|
+
FAILED = "FAILED",
|
|
41
|
+
CANCELLED = "CANCELLEDd",
|
|
42
|
+
PENDING = "PENDING",
|
|
43
|
+
UNKNOWN = "UNKNOWN",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type NamiRestorePurchasesState = "started" | "finished" | "error";
|
|
47
|
+
|
|
48
|
+
export type NamiPurchasesState =
|
|
49
|
+
| "pending"
|
|
50
|
+
| "purchased"
|
|
51
|
+
| "consumed"
|
|
52
|
+
| "resubscribed"
|
|
53
|
+
| "unsubscribed"
|
|
54
|
+
| "deferred"
|
|
55
|
+
| "failed"
|
|
56
|
+
| "cancelled"
|
|
57
|
+
| "unknown";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { NativeModules, NativeEventEmitter, Platform } from "react-native";
|
|
2
|
+
|
|
3
|
+
const { NamiPurchaseManagerBridge, RNNamiPurchaseManager } = NativeModules;
|
|
4
|
+
|
|
5
|
+
export const NamiPurchaseManager = {
|
|
6
|
+
emitter: new NativeEventEmitter(RNNamiPurchaseManager),
|
|
7
|
+
...NamiPurchaseManagerBridge,
|
|
8
|
+
...RNNamiPurchaseManager,
|
|
9
|
+
registerPurchasesChangedHandler(callback) {
|
|
10
|
+
const subscription = this.emitter.addListener(
|
|
11
|
+
"PurchasesChanged",
|
|
12
|
+
(body) => {
|
|
13
|
+
var purchases = body.purchases;
|
|
14
|
+
var purchaseState = body.purchaseState.toLowerCase();
|
|
15
|
+
var error = body.error;
|
|
16
|
+
callback(purchaseState, purchases, error);
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
RNNamiPurchaseManager.registerPurchasesChangedHandler();
|
|
20
|
+
return subscription.remove;
|
|
21
|
+
},
|
|
22
|
+
registerRestorePurchasesHandler(callback) {
|
|
23
|
+
if (Platform.OS === "ios") {
|
|
24
|
+
const subscription = this.emitter.addListener(
|
|
25
|
+
"RestorePurchasesStateChanged",
|
|
26
|
+
(body) => {
|
|
27
|
+
var state = body.state.toLowerCase();
|
|
28
|
+
var newPurchases = body.newPurchases;
|
|
29
|
+
var oldPurchases = body.oldPurchases;
|
|
30
|
+
callback(state, newPurchases, oldPurchases);
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
RNNamiPurchaseManager.registerRestorePurchasesHandler();
|
|
34
|
+
return subscription.remove;
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type NamiSKU = {
|
|
2
|
+
name: string;
|
|
3
|
+
skuId: string;
|
|
4
|
+
product?: SKProduct;
|
|
5
|
+
type: NamiSKUType;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export enum NamiPurchaseState {
|
|
9
|
+
PENDING = "pending",
|
|
10
|
+
PURCHASED = "purchased",
|
|
11
|
+
CONSUMED = "consumed",
|
|
12
|
+
RESUBSCRIBED = "resubscribed",
|
|
13
|
+
UNSUBSCRIBED = "unsubscribed",
|
|
14
|
+
DEFERRED = "deferred",
|
|
15
|
+
FAILED = "failed",
|
|
16
|
+
CANCELLED = "cancelled",
|
|
17
|
+
UNKNOWN = "unknown",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export enum NamiRestorePurchasesState {
|
|
21
|
+
STARTED = "started",
|
|
22
|
+
FINISHED = "finished",
|
|
23
|
+
ERROR = "error",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type NamiSKUType = "unknown" | "one_time_purchase" | "subscription";
|
|
27
|
+
|
|
28
|
+
export type SKProduct = {
|
|
29
|
+
localizedDescription: string;
|
|
30
|
+
localizedMultipliedPrice: string;
|
|
31
|
+
localizedPrice: string;
|
|
32
|
+
localizedTitle: string;
|
|
33
|
+
price: string;
|
|
34
|
+
priceCurrency: string;
|
|
35
|
+
priceLanguage: string;
|
|
36
|
+
};
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
package com.nami.reactlibrary
|
|
2
|
-
|
|
3
|
-
import com.facebook.react.bridge.ReactApplicationContext
|
|
4
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
5
|
-
|
|
6
|
-
class NamiAnalyticsEmitter(reactContext: ReactApplicationContext) :
|
|
7
|
-
ReactContextBaseJavaModule(reactContext) {
|
|
8
|
-
// fun NamiEmitter(reactContext: ReactApplicationContext?) {
|
|
9
|
-
// Log.e("ReactNative", "In Emitter Initialize(reactContext)")
|
|
10
|
-
// NamiPaywallManager.registerApplicationPaywallProvider { context, paywallData, products, developerPaywallId ->
|
|
11
|
-
//
|
|
12
|
-
// Log.e("ReactNativeAndroidDridge", "products from regsiterApplicationPaywallProvider callback are " + products)
|
|
13
|
-
//
|
|
14
|
-
// val productList: List<NamiSKU> = products ?: ArrayList<NamiSKU>()
|
|
15
|
-
// emitPaywallRaise(context, paywallData, productList, developerPaywallId)
|
|
16
|
-
// }
|
|
17
|
-
// NamiPaywallManager.registerApplicationSignInProvider { context, paywallData, developerPaywallId ->
|
|
18
|
-
// currentActivity?.let {
|
|
19
|
-
// emitSignInActivated(WeakReference(it), paywallData, developerPaywallId)
|
|
20
|
-
// }
|
|
21
|
-
// }
|
|
22
|
-
// }
|
|
23
|
-
|
|
24
|
-
override fun onCatalystInstanceDestroy() {
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
override fun getName(): String {
|
|
28
|
-
return "NamiAnaltyicsEmitter"
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
override fun canOverrideExistingModule(): Boolean {
|
|
32
|
-
return false
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
override fun initialize() {
|
|
36
|
-
|
|
37
|
-
// [NamiAnalyticsSupport registerAnalyticsHandlerWithHandler: ^(NamiAnalyticsActionType actionType , NSDictionary<NSString *,id> * _Nonnull anaytlicsDict) {
|
|
38
|
-
// [self sendAnalyticsEventForAction:actionType anayticsItems:anaytlicsDict];
|
|
39
|
-
// }];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// public fun emitSignInActivated(activity: java.lang.ref.WeakReference<android.app.Activity>, paywallData: NamiPaywall, paywallDeveloperID: String?) {
|
|
43
|
-
//// if (hasNamiEmitterListeners) {
|
|
44
|
-
//// // Pass along paywall ID and paywall metadata for use in sign-in provider.
|
|
45
|
-
//// [self sendEventWithName:@"SignInActivate" body:@{ @"developerPaywallID": developerPaywallID,
|
|
46
|
-
//// @"paywallMetadata": paywallMetadata.namiPaywallInfoDict, }];
|
|
47
|
-
//// }
|
|
48
|
-
// val map = Arguments.createMap()
|
|
49
|
-
// map.putString("developerPaywallID", paywallDeveloperID)
|
|
50
|
-
// map.putString("paywallMetadata", "Need TO Map NamiPaywall Object")
|
|
51
|
-
// try {
|
|
52
|
-
// reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
53
|
-
// .emit("SignInActivate", map)
|
|
54
|
-
// } catch (e: Exception) {
|
|
55
|
-
// Log.e("ReactNative", "Caught Exception: " + e.message)
|
|
56
|
-
// }
|
|
57
|
-
// }
|
|
58
|
-
|
|
59
|
-
// Future work to convert this ObjC code:
|
|
60
|
-
//
|
|
61
|
-
// - (NSDictionary *) productDictIfProductPresentInAnalyticsItems:(NSDictionary *)anayticsItems forKey:(NSString *)key {
|
|
62
|
-
// NamiSKU *product = (NamiSKU *)anayticsItems[key];
|
|
63
|
-
// if (product != NULL && [product isKindOfClass:[NamiSKU class]] ) {
|
|
64
|
-
// return [NamiBridgeUtil skuToSKUDict:product];
|
|
65
|
-
// } else {
|
|
66
|
-
// return NULL;
|
|
67
|
-
// }
|
|
68
|
-
// }
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
// - (NSDictionary <NSString *, id> *) sanitizeAnalyticsItems:(NSDictionary *)anayticsItems {
|
|
73
|
-
// NSMutableDictionary<NSString *, id> *sanitizedDictionary = [NSMutableDictionary dictionaryWithDictionary:anayticsItems];
|
|
74
|
-
//
|
|
75
|
-
// id rawProducts = anayticsItems[@"paywallProducts"];
|
|
76
|
-
// if ([rawProducts isKindOfClass:[NSArray class]]) {
|
|
77
|
-
// NSMutableArray<NSDictionary *> *productsSanitized = [NSMutableArray new];
|
|
78
|
-
// for (NamiSKU *product in (NSArray *)rawProducts) {
|
|
79
|
-
// [productsSanitized addObject:[NamiBridgeUtil skuToSKUDict:product]];
|
|
80
|
-
// }
|
|
81
|
-
// sanitizedDictionary[@"paywallProducts"] = productsSanitized;
|
|
82
|
-
// }
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
// NSDate *purchseTimestamp = (NSDate *)(anayticsItems[@"purchasedProductPurchaseTimestamp"]);
|
|
86
|
-
// if (purchseTimestamp != NULL && [purchseTimestamp isKindOfClass:[NSDate class]])
|
|
87
|
-
// {
|
|
88
|
-
// sanitizedDictionary[@"purchasedProductPurchaseTimestamp"] = [NamiBridgeUtil javascriptDateFromNSDate:purchseTimestamp];
|
|
89
|
-
// }
|
|
90
|
-
//
|
|
91
|
-
// NSDictionary *purchasedProductDict = [self productDictIfProductPresentInAnalyticsItems:anayticsItems forKey:@"purchasedProduct"];
|
|
92
|
-
// if ( purchasedProductDict != NULL ) {
|
|
93
|
-
// sanitizedDictionary[@"purchasedProduct"] = purchasedProductDict;
|
|
94
|
-
// sanitizedDictionary[@"purchasedProductPrice"] = purchasedProductDict[@"price"];
|
|
95
|
-
// sanitizedDictionary[@"purchasedProductLocale"] = purchasedProductDict[@"priceLocale"];
|
|
96
|
-
// }
|
|
97
|
-
//
|
|
98
|
-
// NSNumber *activityType = anayticsItems[@"purchaseActivityType"];
|
|
99
|
-
// if (activityType != NULL && [activityType isKindOfClass:[NSNumber class]] ) {
|
|
100
|
-
// switch (activityType.intValue) {
|
|
101
|
-
// case 0: //newPurchase
|
|
102
|
-
// sanitizedDictionary[@"purchaseActivityType_ActivityType"] = @"newPurchase";
|
|
103
|
-
// break;
|
|
104
|
-
// case 1: // cancelled
|
|
105
|
-
// sanitizedDictionary[@"purchaseActivityType_ActivityType"] = @"cancelled";
|
|
106
|
-
// break;
|
|
107
|
-
// case 2: // resubscribe
|
|
108
|
-
// sanitizedDictionary[@"purchaseActivityType_ActivityType"] = @"resubscribe";
|
|
109
|
-
// break;
|
|
110
|
-
// case 3: // restored
|
|
111
|
-
// sanitizedDictionary[@"purchaseActivityType_ActivityType"] = @"restored";
|
|
112
|
-
// break;
|
|
113
|
-
// default:
|
|
114
|
-
// break;
|
|
115
|
-
// }
|
|
116
|
-
// }
|
|
117
|
-
//
|
|
118
|
-
// return sanitizedDictionary;
|
|
119
|
-
// }
|
|
120
|
-
|
|
121
|
-
}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// NamiAnalyticsEmitter.m
|
|
3
|
-
// RNNami
|
|
4
|
-
//
|
|
5
|
-
// Created by Kendall Gelner on 1/9/20.
|
|
6
|
-
// Copyright © 2020 Nami ML Inc. All rights reserved.
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
#import <Foundation/Foundation.h>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
#import <Nami/Nami.h>
|
|
13
|
-
|
|
14
|
-
#import <React/RCTBridgeModule.h>
|
|
15
|
-
#import <React/RCTEventEmitter.h>
|
|
16
|
-
|
|
17
|
-
#import "React/RCTViewManager.h"
|
|
18
|
-
#import <UIKit/UIKit.h>
|
|
19
|
-
|
|
20
|
-
#import "NamiBridgeUtil.h"
|
|
21
|
-
|
|
22
|
-
@interface RCT_EXTERN_MODULE(NamiAnalyticsEmitter, RCTEventEmitter)
|
|
23
|
-
@end
|
|
24
|
-
|
|
25
|
-
@implementation NamiAnalyticsEmitter : RCTEventEmitter
|
|
26
|
-
|
|
27
|
-
- (instancetype)init
|
|
28
|
-
{
|
|
29
|
-
self = [super init];
|
|
30
|
-
if (self) {
|
|
31
|
-
hasNamiAanlyticsEmitterListeners = NO;
|
|
32
|
-
|
|
33
|
-
[NamiAnalyticsSupport registerAnalyticsHandlerWithHandler: ^(NamiAnalyticsActionType actionType , NSDictionary<NSString *,id> * _Nonnull anaytlicsDict) {
|
|
34
|
-
[self sendAnalyticsEventForAction:actionType anayticsItems:anaytlicsDict];
|
|
35
|
-
}];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return self;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
+ (BOOL)requiresMainQueueSetup {
|
|
42
|
-
return YES;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
- (NSArray<NSString *> *)supportedEvents {
|
|
46
|
-
return @[@"NamiAnalyticsSent" ];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
- (NSDictionary<NSString *, NSObject *> *)constantsToExport {
|
|
50
|
-
return @{};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
bool hasNamiAanlyticsEmitterListeners;
|
|
54
|
-
|
|
55
|
-
// Will be called when this module's first listener is added.
|
|
56
|
-
-(void)startObserving {
|
|
57
|
-
hasNamiAanlyticsEmitterListeners = YES;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Will be called when this module's last listener is removed, or on dealloc.
|
|
61
|
-
-(void)stopObserving {
|
|
62
|
-
hasNamiAanlyticsEmitterListeners = NO;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
- (void)sendAnalyticsEventForAction:(NamiAnalyticsActionType)action
|
|
66
|
-
anayticsItems:(NSDictionary *)anayticsItems {
|
|
67
|
-
if (hasNamiAanlyticsEmitterListeners) {
|
|
68
|
-
NSDictionary *sendAnalyitcsDict = [self sanitizeAnalyticsItems:anayticsItems];
|
|
69
|
-
|
|
70
|
-
NSString *actionName = @"UNKNOWN";
|
|
71
|
-
switch (action) {
|
|
72
|
-
case NamiAnalyticsActionTypePaywallRaise:
|
|
73
|
-
actionName = @"paywall_raise";
|
|
74
|
-
break;
|
|
75
|
-
case NamiAnalyticsActionTypePurchaseActivity:
|
|
76
|
-
actionName = @"purchase_activity";
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
[self sendEventWithName:@"NamiAnalyticsSent" body:@{@"actionType" : actionName, @"analyticsItems": sendAnalyitcsDict}];
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
- (NSDictionary *) skuDictIfSKUPresentInAnalyticsItems:(NSDictionary *)anayticsItems forKey:(NSString *)key {
|
|
86
|
-
NamiSKU *product = (NamiSKU *)anayticsItems[key];
|
|
87
|
-
if (product != NULL && [product isKindOfClass:[NamiSKU class]] ) {
|
|
88
|
-
return [NamiBridgeUtil skuToSKUDict:product];
|
|
89
|
-
} else {
|
|
90
|
-
return NULL;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
- (NSDictionary <NSString *, id> *) sanitizeAnalyticsItems:(NSDictionary *)anayticsItems {
|
|
97
|
-
NSMutableDictionary<NSString *, id> *sanitizedDictionary = [NSMutableDictionary dictionaryWithDictionary:anayticsItems];
|
|
98
|
-
|
|
99
|
-
id rawProducts = anayticsItems[@"paywallSKUs"];
|
|
100
|
-
if ([rawProducts isKindOfClass:[NSArray class]]) {
|
|
101
|
-
NSMutableArray<NSDictionary *> *productsSanitized = [NSMutableArray new];
|
|
102
|
-
for (NamiSKU *product in (NSArray *)rawProducts) {
|
|
103
|
-
[productsSanitized addObject:[NamiBridgeUtil skuToSKUDict:product]];
|
|
104
|
-
}
|
|
105
|
-
sanitizedDictionary[@"paywallSKUs"] = productsSanitized;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
NSDate *purchaseTimestamp = (NSDate *)(anayticsItems[@"purchasedSKUPurchaseTimestamp"]);
|
|
110
|
-
if (purchaseTimestamp != NULL && [purchaseTimestamp isKindOfClass:[NSDate class]])
|
|
111
|
-
{
|
|
112
|
-
sanitizedDictionary[@"purchaseTimestamp"] = [NamiBridgeUtil javascriptDateFromNSDate:purchaseTimestamp];
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
NSDictionary *purchasedProductDict = [self skuDictIfSKUPresentInAnalyticsItems:anayticsItems forKey:@"purchasedSKU"];
|
|
116
|
-
if ( purchasedProductDict != NULL ) {
|
|
117
|
-
sanitizedDictionary[@"purchasedSKU"] = purchasedProductDict;
|
|
118
|
-
sanitizedDictionary[@"purchasedSKUPrice"] = purchasedProductDict[@"price"];
|
|
119
|
-
sanitizedDictionary[@"purchasedSKULocale"] = purchasedProductDict[@"priceLocale"];
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
NSNumber *activityType = anayticsItems[@"purchaseActivityType"];
|
|
123
|
-
if (activityType != NULL && [activityType isKindOfClass:[NSNumber class]] ) {
|
|
124
|
-
switch (activityType.intValue) {
|
|
125
|
-
case 0: //newPurchase
|
|
126
|
-
sanitizedDictionary[@"purchaseActivityType_ActivityType"] = @"newPurchase";
|
|
127
|
-
break;
|
|
128
|
-
case 1: // cancelled
|
|
129
|
-
sanitizedDictionary[@"purchaseActivityType_ActivityType"] = @"cancelled";
|
|
130
|
-
break;
|
|
131
|
-
case 2: // resubscribe
|
|
132
|
-
sanitizedDictionary[@"purchaseActivityType_ActivityType"] = @"resubscribe";
|
|
133
|
-
break;
|
|
134
|
-
case 3: // restored
|
|
135
|
-
sanitizedDictionary[@"purchaseActivityType_ActivityType"] = @"restored";
|
|
136
|
-
break;
|
|
137
|
-
default:
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return sanitizedDictionary;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
@end
|