@purchasely/cordova-plugin-purchasely 2.3.1 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/example/android.sh +8 -0
- package/example/config.xml +1 -1
- package/example/ios.sh +16 -0
- package/example/package-lock.json +410 -482
- package/example/package.json +5 -4
- package/example/www/index.html +12 -0
- package/example/www/js/index.js +113 -9
- package/package.json +9 -1
- package/plugin.xml +16 -5
- package/purchasely.iml +11 -0
- package/src/android/PLYProductActivity.kt +171 -0
- package/src/android/PLYSubscriptionsActivity.java +1 -1
- package/src/android/PurchaselyPlugin.kt +916 -0
- package/src/android/activity_ply_product_activity.xml +2 -2
- package/src/android/activity_ply_subscriptions_activity.xml +6 -0
- package/src/ios/CDVPurchasely.h +23 -6
- package/src/ios/CDVPurchasely.m +432 -35
- package/src/ios/Hybrid/PLYPlan+Hybrid.m +0 -1
- package/src/ios/Hybrid/PLYPresentationPlan+Hybrid.h +20 -0
- package/src/ios/Hybrid/PLYPresentationPlan+Hybrid.m +31 -0
- package/src/ios/Hybrid/Purchasely_Hybrid.h +1 -0
- package/src/ios/Hybrid/UIColor+PLYHelper.h +19 -0
- package/src/ios/Hybrid/UIColor+PLYHelper.m +66 -0
- package/www/Purchasely.js +90 -28
- package/src/android/PLYProductActivity.java +0 -87
- package/src/android/PurchaselyPlugin.java +0 -739
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
-
<
|
|
2
|
+
<FrameLayout
|
|
3
3
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
4
|
-
android:id="@+id/
|
|
4
|
+
android:id="@+id/container"
|
|
5
5
|
android:layout_width="match_parent"
|
|
6
6
|
android:layout_height="match_parent" />
|
package/src/ios/CDVPurchasely.h
CHANGED
|
@@ -11,21 +11,26 @@
|
|
|
11
11
|
@interface CDVPurchasely<PLYEventDelegate> : CDVPlugin {
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
@property (nonatomic,
|
|
14
|
+
@property (nonatomic, retain) UIViewController* presentedPresentationViewController;
|
|
15
15
|
|
|
16
16
|
@property CDVInvokedUrlCommand* purchasedCommand;
|
|
17
17
|
@property CDVInvokedUrlCommand* eventCommand;
|
|
18
18
|
|
|
19
|
+
@property (nonatomic) NSMutableArray<PLYPresentation *> *presentationsLoaded;
|
|
20
|
+
@property (nonatomic, assign) Boolean shouldReopenPaywall;
|
|
21
|
+
|
|
22
|
+
@property (nonatomic) CDVInvokedUrlCommand* purchaseResolve;
|
|
23
|
+
|
|
19
24
|
@property CDVInvokedUrlCommand* paywallActionInterceptorCommand;
|
|
20
25
|
@property void (^onProcessActionHandler)(BOOL proceed);
|
|
21
26
|
|
|
22
|
-
- (void)
|
|
27
|
+
- (void)start:(CDVInvokedUrlCommand*)command;
|
|
23
28
|
- (void)setLogLevel:(CDVInvokedUrlCommand*)command;
|
|
24
29
|
- (void)userLogin:(CDVInvokedUrlCommand*)command;
|
|
25
30
|
- (void)userLogout:(CDVInvokedUrlCommand*)command;
|
|
26
31
|
- (void)setAttribute:(CDVInvokedUrlCommand*)command;
|
|
27
32
|
- (void)getAnonymousUserId:(CDVInvokedUrlCommand*)command;
|
|
28
|
-
- (void)
|
|
33
|
+
- (void)readyToOpenDeeplink:(CDVInvokedUrlCommand*)command;
|
|
29
34
|
- (void)setDefaultPresentationResultHandler:(CDVInvokedUrlCommand*)command;
|
|
30
35
|
- (void)presentPresentationWithIdentifier:(CDVInvokedUrlCommand*)command;
|
|
31
36
|
- (void)presentPresentationForPlacement:(CDVInvokedUrlCommand*)command;
|
|
@@ -42,11 +47,23 @@
|
|
|
42
47
|
- (void)userSubscriptions:(CDVInvokedUrlCommand*)command;
|
|
43
48
|
- (void)addEventsListener:(CDVInvokedUrlCommand*)command;
|
|
44
49
|
- (void)removeEventsListener:(CDVInvokedUrlCommand*)command;
|
|
45
|
-
- (void)
|
|
46
|
-
- (void)close:(CDVInvokedUrlCommand*)command;
|
|
50
|
+
- (void)isDeeplinkHandled:(CDVInvokedUrlCommand*)command;
|
|
47
51
|
- (void)setPaywallActionInterceptor:(CDVInvokedUrlCommand*)command;
|
|
48
52
|
- (void)onProcessAction:(CDVInvokedUrlCommand*)command;
|
|
49
|
-
- (void)
|
|
53
|
+
- (void)closePresentation:(CDVInvokedUrlCommand*)command;
|
|
54
|
+
- (void)hidePresentation:(CDVInvokedUrlCommand*)command;
|
|
55
|
+
- (void)showPresentation:(CDVInvokedUrlCommand*)command;
|
|
50
56
|
- (void)userDidConsumeSubscriptionContent:(CDVInvokedUrlCommand*)command;
|
|
57
|
+
- (void)setUserAttributeWithString:(CDVInvokedUrlCommand*)command;
|
|
58
|
+
- (void)setUserAttributeWithBoolean:(CDVInvokedUrlCommand*)command;
|
|
59
|
+
- (void)setUserAttributeWithInt:(CDVInvokedUrlCommand*)command;
|
|
60
|
+
- (void)setUserAttributeWithDate:(CDVInvokedUrlCommand*)command;
|
|
61
|
+
- (void)userAttribute:(CDVInvokedUrlCommand*)command;
|
|
62
|
+
- (void)clearUserAttribute:(CDVInvokedUrlCommand*)command;
|
|
63
|
+
- (void)clearUserAttributes:(CDVInvokedUrlCommand*)command;
|
|
64
|
+
- (void)fetchPresentation:(CDVInvokedUrlCommand*)command;
|
|
65
|
+
- (void)presentPresentation:(CDVInvokedUrlCommand*)command;
|
|
66
|
+
- (void)signPromotionalOffer:(CDVInvokedUrlCommand*)command;
|
|
67
|
+
- (void)isEligibleForIntroOffer:(CDVInvokedUrlCommand*)command;
|
|
51
68
|
|
|
52
69
|
@end
|
package/src/ios/CDVPurchasely.m
CHANGED
|
@@ -8,20 +8,39 @@
|
|
|
8
8
|
#import "CDVPurchasely.h"
|
|
9
9
|
#import "Purchasely_Hybrid.h"
|
|
10
10
|
#import "CDVPurchasely+Events.h"
|
|
11
|
+
#import "UIColor+PLYHelper.h"
|
|
11
12
|
|
|
12
13
|
@implementation CDVPurchasely
|
|
13
14
|
|
|
14
|
-
- (
|
|
15
|
+
- (instancetype)init {
|
|
16
|
+
self = [super init];
|
|
17
|
+
|
|
18
|
+
self.presentationsLoaded = [NSMutableArray new];
|
|
19
|
+
self.shouldReopenPaywall = NO;
|
|
20
|
+
|
|
21
|
+
return self;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
- (void)start:(CDVInvokedUrlCommand*)command {
|
|
15
25
|
NSString *apiKey = [command argumentAtIndex:0];
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
NSInteger
|
|
19
|
-
|
|
26
|
+
BOOL storeKit1 = [[command argumentAtIndex:2] boolValue];
|
|
27
|
+
NSString *userId = [command argumentAtIndex:3];
|
|
28
|
+
NSInteger logLevel = [[command argumentAtIndex:4] intValue];
|
|
29
|
+
NSInteger runningMode = [[command argumentAtIndex:5] intValue];
|
|
30
|
+
NSString *purchaselySdkVersion = [command argumentAtIndex:6];
|
|
20
31
|
|
|
21
32
|
[Purchasely setSdkBridgeVersion:purchaselySdkVersion];
|
|
22
|
-
|
|
33
|
+
|
|
23
34
|
[Purchasely setAppTechnology:PLYAppTechnologyCordova];
|
|
24
|
-
|
|
35
|
+
|
|
36
|
+
[Purchasely startWithAPIKey:apiKey
|
|
37
|
+
appUserId:userId
|
|
38
|
+
runningMode:runningMode
|
|
39
|
+
paywallActionsInterceptor:nil
|
|
40
|
+
storekitSettings: storeKit1 ? [StorekitSettings storeKit1] : [StorekitSettings storeKit2]
|
|
41
|
+
logLevel:logLevel
|
|
42
|
+
initialized:^(BOOL initialized, NSError * _Nullable error) {
|
|
43
|
+
|
|
25
44
|
if (error != nil) {
|
|
26
45
|
[self failureFor:command resultString: error.localizedDescription];
|
|
27
46
|
} else {
|
|
@@ -58,9 +77,9 @@
|
|
|
58
77
|
[self successFor:command resultString:anonymousId];
|
|
59
78
|
}
|
|
60
79
|
|
|
61
|
-
- (void)
|
|
80
|
+
- (void)readyToOpenDeeplink:(CDVInvokedUrlCommand*)command {
|
|
62
81
|
BOOL isReadyToPurchase = [[command argumentAtIndex:0] boolValue];
|
|
63
|
-
[Purchasely
|
|
82
|
+
[Purchasely readyToOpenDeeplink: isReadyToPurchase];
|
|
64
83
|
}
|
|
65
84
|
|
|
66
85
|
- (void)setDefaultPresentationResultHandler:(CDVInvokedUrlCommand*)command {
|
|
@@ -91,7 +110,7 @@
|
|
|
91
110
|
[navCtrl.navigationBar setTintColor: [UIColor whiteColor]];
|
|
92
111
|
|
|
93
112
|
self.presentedPresentationViewController = navCtrl;
|
|
94
|
-
|
|
113
|
+
|
|
95
114
|
if (isFullscreen) {
|
|
96
115
|
navCtrl.modalPresentationStyle = UIModalPresentationFullScreen;
|
|
97
116
|
}
|
|
@@ -117,7 +136,7 @@
|
|
|
117
136
|
[navCtrl.navigationBar setTintColor: [UIColor whiteColor]];
|
|
118
137
|
|
|
119
138
|
self.presentedPresentationViewController = navCtrl;
|
|
120
|
-
|
|
139
|
+
|
|
121
140
|
if (isFullscreen) {
|
|
122
141
|
navCtrl.modalPresentationStyle = UIModalPresentationFullScreen;
|
|
123
142
|
}
|
|
@@ -130,7 +149,7 @@
|
|
|
130
149
|
NSString *presentationVendorId = [command argumentAtIndex:1];
|
|
131
150
|
NSString *contentId = [command argumentAtIndex:2];
|
|
132
151
|
BOOL isFullscreen = [[command argumentAtIndex:3] boolValue];
|
|
133
|
-
|
|
152
|
+
|
|
134
153
|
UIViewController *ctrl = [Purchasely planControllerFor:planVendorId with:presentationVendorId contentId:contentId loaded:nil completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {
|
|
135
154
|
NSDictionary *resultDict = [self resultDictionaryForPresentationController:result plan:plan];
|
|
136
155
|
[self successFor:command resultDict:resultDict];
|
|
@@ -142,9 +161,9 @@
|
|
|
142
161
|
[navCtrl.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
|
|
143
162
|
[navCtrl.navigationBar setShadowImage: [UIImage new]];
|
|
144
163
|
[navCtrl.navigationBar setTintColor: [UIColor whiteColor]];
|
|
145
|
-
|
|
164
|
+
|
|
146
165
|
self.presentedPresentationViewController = navCtrl;
|
|
147
|
-
|
|
166
|
+
|
|
148
167
|
if (isFullscreen) {
|
|
149
168
|
navCtrl.modalPresentationStyle = UIModalPresentationFullScreen;
|
|
150
169
|
}
|
|
@@ -157,7 +176,7 @@
|
|
|
157
176
|
NSString *presentationVendorId = [command argumentAtIndex:1];
|
|
158
177
|
NSString *contentId = [command argumentAtIndex:2];
|
|
159
178
|
BOOL isFullscreen = [[command argumentAtIndex:3] boolValue];
|
|
160
|
-
|
|
179
|
+
|
|
161
180
|
UIViewController *ctrl = [Purchasely productControllerFor:productVendorId with:presentationVendorId contentId:contentId loaded:nil completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {
|
|
162
181
|
NSDictionary *resultDict = [self resultDictionaryForPresentationController:result plan:plan];
|
|
163
182
|
[self successFor:command resultDict:resultDict];
|
|
@@ -169,9 +188,9 @@
|
|
|
169
188
|
[navCtrl.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
|
|
170
189
|
[navCtrl.navigationBar setShadowImage: [UIImage new]];
|
|
171
190
|
[navCtrl.navigationBar setTintColor: [UIColor whiteColor]];
|
|
172
|
-
|
|
191
|
+
|
|
173
192
|
self.presentedPresentationViewController = navCtrl;
|
|
174
|
-
|
|
193
|
+
|
|
175
194
|
if (isFullscreen) {
|
|
176
195
|
navCtrl.modalPresentationStyle = UIModalPresentationFullScreen;
|
|
177
196
|
}
|
|
@@ -189,18 +208,50 @@
|
|
|
189
208
|
|
|
190
209
|
- (void)purchaseWithPlanVendorId:(CDVInvokedUrlCommand*)command {
|
|
191
210
|
NSString *planVendorId = [command argumentAtIndex:0];
|
|
192
|
-
|
|
211
|
+
NSString *offerId = [command argumentAtIndex:1];
|
|
212
|
+
NSString *contentId = [command argumentAtIndex:2];
|
|
213
|
+
|
|
193
214
|
[Purchasely planWith:planVendorId
|
|
194
215
|
success:^(PLYPlan * _Nonnull plan) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
216
|
+
|
|
217
|
+
if (@available(iOS 12.2, macOS 12.0, tvOS 15.0, watchOS 8.0, *)) {
|
|
218
|
+
|
|
219
|
+
NSString *storeOfferId = nil;
|
|
220
|
+
for (PLYPromoOffer *promoOffer in plan.promoOffers) {
|
|
221
|
+
if ([promoOffer.vendorId isEqualToString:offerId]) {
|
|
222
|
+
storeOfferId = promoOffer.storeOfferId;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (storeOfferId) {
|
|
228
|
+
[Purchasely purchaseWithPromotionalOfferWithPlan:plan
|
|
229
|
+
contentId:contentId
|
|
230
|
+
storeOfferId:storeOfferId
|
|
231
|
+
success:^{
|
|
232
|
+
[self successFor:command resultDict: plan.asDictionary];
|
|
233
|
+
} failure:^(NSError * _Nonnull error) {
|
|
234
|
+
[self failureFor:command resultString: error.localizedDescription];
|
|
235
|
+
}];
|
|
236
|
+
} else {
|
|
237
|
+
[Purchasely purchaseWithPlan:plan
|
|
238
|
+
contentId:contentId
|
|
239
|
+
success:^{
|
|
240
|
+
[self successFor:command resultDict: plan.asDictionary];
|
|
241
|
+
} failure:^(NSError * _Nonnull error) {
|
|
242
|
+
[self failureFor:command resultString: error.localizedDescription];
|
|
243
|
+
}];
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
[Purchasely purchaseWithPlan:plan
|
|
247
|
+
contentId:contentId
|
|
248
|
+
success:^{
|
|
249
|
+
[self successFor:command resultDict: plan.asDictionary];
|
|
250
|
+
} failure:^(NSError * _Nonnull error) {
|
|
251
|
+
[self failureFor:command resultString: error.localizedDescription];
|
|
252
|
+
}];
|
|
198
253
|
}
|
|
199
|
-
|
|
200
|
-
[self failureFor:command resultString: error.localizedDescription];
|
|
201
|
-
}];
|
|
202
|
-
}
|
|
203
|
-
failure:^(NSError * _Nullable error) {
|
|
254
|
+
} failure:^(NSError * _Nullable error) {
|
|
204
255
|
[self failureFor:command resultString: error.localizedDescription];
|
|
205
256
|
}];
|
|
206
257
|
}
|
|
@@ -214,7 +265,7 @@
|
|
|
214
265
|
}
|
|
215
266
|
|
|
216
267
|
- (void)silentRestoreAllProducts:(CDVInvokedUrlCommand*)command {
|
|
217
|
-
[Purchasely
|
|
268
|
+
[Purchasely synchronizeWithSuccess:^{
|
|
218
269
|
[self successFor:command];
|
|
219
270
|
} failure:^(NSError * _Nonnull error) {
|
|
220
271
|
[self failureFor:command resultString:error.localizedDescription];
|
|
@@ -292,27 +343,55 @@
|
|
|
292
343
|
self.eventCommand = nil;
|
|
293
344
|
}
|
|
294
345
|
|
|
295
|
-
- (void)
|
|
346
|
+
- (void)isDeeplinkHandled:(CDVInvokedUrlCommand*)command {
|
|
296
347
|
NSString *deeplinkString = [command argumentAtIndex:0];
|
|
297
348
|
NSURL *deeplink = [NSURL URLWithString:deeplinkString];
|
|
298
349
|
|
|
299
350
|
if (deeplink != nil) {
|
|
300
|
-
BOOL result = [Purchasely
|
|
351
|
+
BOOL result = [Purchasely isDeeplinkHandledWithDeeplink:deeplink];
|
|
301
352
|
[self successFor:command resultBool:result];
|
|
302
353
|
} else {
|
|
303
354
|
[self successFor:command resultBool:NO];
|
|
304
355
|
}
|
|
305
356
|
}
|
|
306
357
|
|
|
307
|
-
- (void)close:(CDVInvokedUrlCommand*)command {
|
|
308
|
-
}
|
|
309
|
-
|
|
310
358
|
- (void)setLanguage:(CDVInvokedUrlCommand*)command {
|
|
311
359
|
NSString *language = [command argumentAtIndex:0];
|
|
312
360
|
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:language];
|
|
313
361
|
[Purchasely setLanguageFrom:locale];
|
|
314
362
|
}
|
|
315
363
|
|
|
364
|
+
- (void)signPromotionalOffer:(CDVInvokedUrlCommand*)command {
|
|
365
|
+
NSString *storeProductId = [command argumentAtIndex:0];
|
|
366
|
+
NSString *storeOfferId = [command argumentAtIndex:1];
|
|
367
|
+
|
|
368
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
369
|
+
if (@available(iOS 12.2, *)) {
|
|
370
|
+
[Purchasely signPromotionalOfferWithStoreProductId:storeProductId storeOfferId:storeOfferId success:^(PLYOfferSignature * _Nonnull signature) {
|
|
371
|
+
NSDictionary* result = [self resultSignatureForSignPromoOffer:signature];
|
|
372
|
+
[self successFor:command resultBool:result];
|
|
373
|
+
} failure:^(NSError * _Nullable error) {
|
|
374
|
+
[self failureFor:command resultString:error.localizedDescription];
|
|
375
|
+
}];
|
|
376
|
+
} else {
|
|
377
|
+
[self failureFor:command resultString:@"This fonctionality is unavailable before ios 12.2"];
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
- (void)isEligibleForIntroOffer:(CDVInvokedUrlCommand*)command {
|
|
383
|
+
NSString *planVendorId = [command argumentAtIndex:0];
|
|
384
|
+
|
|
385
|
+
[Purchasely planWith:planVendorId
|
|
386
|
+
success:^(PLYPlan * _Nonnull plan) {
|
|
387
|
+
[plan isUserEligibleForIntroductoryOfferWithCompletion:^(BOOL isEligible) {
|
|
388
|
+
[self successFor:command resultBool:isEligible];
|
|
389
|
+
}];
|
|
390
|
+
} failure:^(NSError * _Nullable error) {
|
|
391
|
+
[self failureFor:command resultString:error.localizedDescription];
|
|
392
|
+
}];
|
|
393
|
+
}
|
|
394
|
+
|
|
316
395
|
// Helpers
|
|
317
396
|
|
|
318
397
|
- (NSDictionary<NSString *, NSObject *> *) resultDictionaryForPresentationController:(PLYProductViewControllerResult)result plan:(PLYPlan * _Nullable)plan {
|
|
@@ -389,7 +468,7 @@
|
|
|
389
468
|
if (infos.abTestVariantId != nil) {
|
|
390
469
|
[infosResult setObject:infos.abTestVariantId forKey:@"abTestVariantId"];
|
|
391
470
|
}
|
|
392
|
-
|
|
471
|
+
|
|
393
472
|
[actionInterceptorResult setObject:infosResult forKey:@"info"];
|
|
394
473
|
}
|
|
395
474
|
if (params != nil) {
|
|
@@ -406,9 +485,15 @@
|
|
|
406
485
|
if (params.presentation != nil) {
|
|
407
486
|
[paramsResult setObject:params.presentation forKey:@"presentation"];
|
|
408
487
|
}
|
|
488
|
+
if (params.promoOffer != nil) {
|
|
489
|
+
NSMutableDictionary<NSString *, NSObject *> *promoOffer = [NSMutableDictionary new];
|
|
490
|
+
[promoOffer setObject:params.promoOffer.vendorId forKey:@"vendorId"];
|
|
491
|
+
[promoOffer setObject:params.promoOffer.storeOfferId forKey:@"storeOfferId"];
|
|
492
|
+
[paramsResult setObject:promoOffer forKey:@"offer"];
|
|
493
|
+
}
|
|
409
494
|
[actionInterceptorResult setObject:paramsResult forKey:@"parameters"];
|
|
410
495
|
}
|
|
411
|
-
|
|
496
|
+
|
|
412
497
|
return actionInterceptorResult;
|
|
413
498
|
}
|
|
414
499
|
|
|
@@ -432,20 +517,332 @@
|
|
|
432
517
|
}
|
|
433
518
|
}
|
|
434
519
|
|
|
435
|
-
- (void)
|
|
520
|
+
- (void)closePresentation:(CDVInvokedUrlCommand*)command {
|
|
436
521
|
if (self.presentedPresentationViewController != nil) {
|
|
437
522
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
438
523
|
[self.presentedPresentationViewController dismissViewControllerAnimated:true completion:^{
|
|
439
524
|
self.presentedPresentationViewController = nil;
|
|
525
|
+
self.shouldReopenPaywall = NO;
|
|
440
526
|
}];
|
|
441
527
|
});
|
|
442
528
|
}
|
|
443
529
|
}
|
|
444
530
|
|
|
531
|
+
- (void)hidePresentation:(CDVInvokedUrlCommand*)command {
|
|
532
|
+
if (self.presentedPresentationViewController != nil) {
|
|
533
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
534
|
+
[self.presentedPresentationViewController dismissViewControllerAnimated:true completion:^{ }];
|
|
535
|
+
self.shouldReopenPaywall = YES;
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
- (void)showPresentation:(CDVInvokedUrlCommand*)command {
|
|
541
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
542
|
+
if (self.presentedPresentationViewController && self.shouldReopenPaywall) {
|
|
543
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
|
544
|
+
self.shouldReopenPaywall = NO;
|
|
545
|
+
[Purchasely showController:self.presentedPresentationViewController type:PLYUIControllerTypeProductPage];
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
445
551
|
- (void)userDidConsumeSubscriptionContent:(CDVInvokedUrlCommand*)command {
|
|
446
552
|
[Purchasely userDidConsumeSubscriptionContent];
|
|
447
553
|
}
|
|
448
554
|
|
|
555
|
+
- (void)setUserAttributeWithString:(CDVInvokedUrlCommand*)command {
|
|
556
|
+
NSString *key = [command argumentAtIndex:0];
|
|
557
|
+
NSString *value = [command argumentAtIndex:1];
|
|
558
|
+
[Purchasely setUserAttributeWithStringValue:value forKey:key];
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
- (void)setUserAttributeWithBoolean:(CDVInvokedUrlCommand*)command {
|
|
562
|
+
NSString *key = [command argumentAtIndex:0];
|
|
563
|
+
BOOL value = [[command argumentAtIndex:1] boolValue];
|
|
564
|
+
[Purchasely setUserAttributeWithBoolValue:value forKey:key];
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
- (void)setUserAttributeWithInt:(CDVInvokedUrlCommand*)command {
|
|
568
|
+
NSString *key = [command argumentAtIndex:0];
|
|
569
|
+
NSInteger value = [[command argumentAtIndex:1] intValue];
|
|
570
|
+
[Purchasely setUserAttributeWithIntValue:value forKey:key];
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
- (void)setUserAttributeWithDouble:(CDVInvokedUrlCommand*)command {
|
|
574
|
+
NSString *key = [command argumentAtIndex:0];
|
|
575
|
+
double value = [[command argumentAtIndex:1] doubleValue];
|
|
576
|
+
[Purchasely setUserAttributeWithDoubleValue:value forKey:key];
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
- (void)setUserAttributeWithDate:(CDVInvokedUrlCommand*)command {
|
|
580
|
+
NSString *key = [command argumentAtIndex:0];
|
|
581
|
+
NSString *value = [command argumentAtIndex:1];
|
|
582
|
+
|
|
583
|
+
NSDateFormatter * dateFormatter = [NSDateFormatter new];
|
|
584
|
+
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
|
|
585
|
+
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
|
|
586
|
+
NSDate *date = [dateFormatter dateFromString:value];
|
|
587
|
+
if (date != nil) {
|
|
588
|
+
[Purchasely setUserAttributeWithDateValue:date forKey:key];
|
|
589
|
+
} else {
|
|
590
|
+
NSLog(@"[Purchasely] Cannot save date attribute %@", key);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
- (void)userAttribute:(CDVInvokedUrlCommand*)command {
|
|
595
|
+
NSString *key = [command argumentAtIndex:0];
|
|
596
|
+
|
|
597
|
+
id _Nullable result = [self getUserAttributeValueForCordova:[Purchasely getUserAttributeFor:key]];
|
|
598
|
+
if (result != nil) {
|
|
599
|
+
[self successFor:command resultDict:result];
|
|
600
|
+
} else {
|
|
601
|
+
[self failureFor:command resultString:@"Cannot get user attribute"];
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
- (id _Nullable) getUserAttributeValueForCordova:(id _Nullable) value {
|
|
606
|
+
if ([value isKindOfClass:[NSDate class]]) {
|
|
607
|
+
NSDateFormatter * dateFormatter = [NSDateFormatter new];
|
|
608
|
+
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
|
|
609
|
+
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
|
|
610
|
+
NSString *dateStr = [dateFormatter stringFromDate:value];
|
|
611
|
+
return dateStr;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
return value;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
- (void)clearUserAttribute:(CDVInvokedUrlCommand*)command {
|
|
618
|
+
NSString *key = [command argumentAtIndex:0];
|
|
619
|
+
[Purchasely clearUserAttributeForKey:key];
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
- (void)clearUserAttributes:(CDVInvokedUrlCommand*)command {
|
|
623
|
+
[Purchasely clearUserAttributes];
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
- (void)fetchPresentation:(CDVInvokedUrlCommand*)command {
|
|
627
|
+
NSString *placementId = [command argumentAtIndex:0];
|
|
628
|
+
NSString *presentationId = [command argumentAtIndex:1];
|
|
629
|
+
NSString *contentId = [command argumentAtIndex:2];
|
|
630
|
+
|
|
631
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
632
|
+
if (placementId != nil) {
|
|
633
|
+
[Purchasely fetchPresentationFor:placementId contentId: contentId fetchCompletion:^(PLYPresentation * _Nullable presentation, NSError * _Nullable error) {
|
|
634
|
+
if (error != nil) {
|
|
635
|
+
[self failureFor:command resultString: error.localizedDescription];
|
|
636
|
+
} else if (presentation != nil) {
|
|
637
|
+
[self.presentationsLoaded addObject:presentation];
|
|
638
|
+
[self successFor:command resultDict:[self resultDictionaryForFetchPresentation:presentation]];
|
|
639
|
+
}
|
|
640
|
+
} completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {
|
|
641
|
+
if (self.purchaseResolve != nil){
|
|
642
|
+
[self successFor:self.purchaseResolve resultDict:[self resultDictionaryForPresentationController:result plan:plan]];
|
|
643
|
+
}
|
|
644
|
+
}];
|
|
645
|
+
} else {
|
|
646
|
+
[Purchasely fetchPresentationWith:presentationId contentId: contentId fetchCompletion:^(PLYPresentation * _Nullable presentation, NSError * _Nullable error) {
|
|
647
|
+
if (error != nil) {
|
|
648
|
+
[self failureFor:command resultString: error.localizedDescription];
|
|
649
|
+
} else if (presentation != nil) {
|
|
650
|
+
[self.presentationsLoaded addObject:presentation];
|
|
651
|
+
[self successFor:command resultDict:[self resultDictionaryForFetchPresentation:presentation]];
|
|
652
|
+
}
|
|
653
|
+
} completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {
|
|
654
|
+
if (self.purchaseResolve != nil) {
|
|
655
|
+
[self successFor:self.purchaseResolve resultDict:[self resultDictionaryForPresentationController:result plan:plan]];
|
|
656
|
+
}
|
|
657
|
+
}];
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
- (void)presentPresentation:(CDVInvokedUrlCommand *)command {
|
|
663
|
+
NSDictionary<NSString *, id> *presentationDictionary = [command argumentAtIndex:0];
|
|
664
|
+
BOOL isFullscreen = [[command argumentAtIndex:1] boolValue];
|
|
665
|
+
NSString *loadingBackgroundColor = [command argumentAtIndex:2];
|
|
666
|
+
|
|
667
|
+
if (presentationDictionary == nil) {
|
|
668
|
+
[self failureFor:command resultString: @"Presentation cannot be null"];
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
self.purchaseResolve = command;
|
|
673
|
+
|
|
674
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
675
|
+
|
|
676
|
+
PLYPresentation *presentationLoaded = [self findPresentationLoadedFor:(NSString *)[presentationDictionary objectForKey:@"id"]];
|
|
677
|
+
|
|
678
|
+
if (presentationLoaded == nil || presentationLoaded.controller == nil) {
|
|
679
|
+
[self failureFor:command resultString: @"Presentation not loaded"];
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
[self.presentationsLoaded removeObjectAtIndex:[self findIndexPresentationLoadedFor:(NSString *)[presentationDictionary objectForKey:@"id"]]];
|
|
684
|
+
|
|
685
|
+
if (presentationLoaded.controller != nil) {
|
|
686
|
+
if (loadingBackgroundColor != nil) {
|
|
687
|
+
UIColor *backColor = [UIColor ply_fromHex:loadingBackgroundColor];
|
|
688
|
+
if (backColor != nil) {
|
|
689
|
+
[presentationLoaded.controller.view setBackgroundColor:backColor];
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
if (isFullscreen) {
|
|
694
|
+
presentationLoaded.controller.modalPresentationStyle = UIModalPresentationFullScreen;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
self.shouldReopenPaywall = NO;
|
|
698
|
+
|
|
699
|
+
[Purchasely closeDisplayedPresentation];
|
|
700
|
+
self.presentedPresentationViewController = presentationLoaded.controller;
|
|
701
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
|
702
|
+
[Purchasely showController:presentationLoaded.controller type: PLYUIControllerTypeProductPage];
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
- (PLYPresentation *) findPresentationLoadedFor:(NSString * _Nullable) presentationId {
|
|
709
|
+
for (PLYPresentation *presentationLoaded in self.presentationsLoaded) {
|
|
710
|
+
if ([presentationLoaded.id isEqualToString: presentationId]) {
|
|
711
|
+
return presentationLoaded;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return nil;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
- (NSInteger) findIndexPresentationLoadedFor:(NSString * _Nullable) presentationId {
|
|
718
|
+
NSInteger index = 0;
|
|
719
|
+
for (PLYPresentation *presentationLoaded in self.presentationsLoaded) {
|
|
720
|
+
if ([presentationLoaded.id isEqualToString: presentationId]) {
|
|
721
|
+
return index;
|
|
722
|
+
}
|
|
723
|
+
index++;
|
|
724
|
+
}
|
|
725
|
+
return -1;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
- (NSDictionary *)resultSignatureForSignPromoOffer:(PLYOfferSignature * _Nullable) signature {
|
|
729
|
+
NSMutableDictionary<NSString *, NSObject *> *dict = [NSMutableDictionary new];
|
|
730
|
+
|
|
731
|
+
[dict setObject:signature.planVendorId forKey:@"planVendorId"];
|
|
732
|
+
[dict setObject:signature.identifier forKey:@"identifier"];
|
|
733
|
+
[dict setObject:signature.signature forKey:@"signature"];
|
|
734
|
+
[dict setObject:signature.keyIdentifier forKey:@"keyIdentifier"];
|
|
735
|
+
|
|
736
|
+
NSString *nonceString = [signature.nonce UUIDString];
|
|
737
|
+
NSObject *nonce = (NSObject *)nonceString;
|
|
738
|
+
if (nonce != nil) {
|
|
739
|
+
[dict setObject:nonce forKey:@"nonce"];
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
NSNumber *timestamp = [NSNumber numberWithDouble:signature.timestamp];
|
|
743
|
+
if (timestamp != nil) {
|
|
744
|
+
[dict setObject:timestamp forKey:@"timestamp"];
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
return dict;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
- (NSDictionary<NSString *, NSObject *> *) resultDictionaryForFetchPresentation:(PLYPresentation * _Nullable) presentation {
|
|
751
|
+
NSMutableDictionary<NSString *, NSObject *> *presentationResult = [NSMutableDictionary new];
|
|
752
|
+
|
|
753
|
+
// TODO: fill all parameters.
|
|
754
|
+
if (presentation != nil) {
|
|
755
|
+
|
|
756
|
+
if (presentation.id != nil) {
|
|
757
|
+
[presentationResult setObject:presentation.id forKey:@"id"];
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
if (presentation.placementId != nil) {
|
|
761
|
+
[presentationResult setObject:presentation.placementId forKey:@"placementId"];
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
if (presentation.audienceId != nil) {
|
|
765
|
+
[presentationResult setObject:presentation.audienceId forKey:@"audienceId"];
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
if (presentation.abTestId != nil) {
|
|
769
|
+
[presentationResult setObject:presentation.abTestId forKey:@"abTestId"];
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (presentation.abTestVariantId != nil) {
|
|
773
|
+
[presentationResult setObject:presentation.abTestVariantId forKey:@"abTestVariantId"];
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
if (presentation.language != nil) {
|
|
777
|
+
[presentationResult setObject:presentation.language forKey:@"language"];
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
if (presentation.plans != nil) {
|
|
781
|
+
NSMutableArray *plans = [NSMutableArray new];
|
|
782
|
+
|
|
783
|
+
for (PLYPresentationPlan *plan in presentation.plans) {
|
|
784
|
+
[plans addObject:plan.asDictionary];
|
|
785
|
+
}
|
|
786
|
+
[presentationResult setObject:plans forKey:@"plans"];
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/*if (presentation.metadata != nil) {
|
|
790
|
+
|
|
791
|
+
NSDictionary<NSString *,id> *rawMetadata = [presentation.metadata getRawMetadata];
|
|
792
|
+
NSMutableDictionary<NSString *,id> *resultDict = [NSMutableDictionary dictionary];
|
|
793
|
+
|
|
794
|
+
dispatch_group_t group = dispatch_group_create();
|
|
795
|
+
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
|
796
|
+
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
|
797
|
+
|
|
798
|
+
for (NSString *key in rawMetadata) {
|
|
799
|
+
id value = rawMetadata[key];
|
|
800
|
+
|
|
801
|
+
if ([value isKindOfClass: [NSString class]]) {
|
|
802
|
+
dispatch_group_enter(group); // Enter the dispatch group before making the async call
|
|
803
|
+
[presentation.metadata getStringWith:key completion:^(NSString * _Nullable result) {
|
|
804
|
+
[resultDict setObject:result forKey:key];
|
|
805
|
+
dispatch_group_leave(group); // Leave the dispatch group after the async call is completed
|
|
806
|
+
}];
|
|
807
|
+
} else {
|
|
808
|
+
[resultDict setObject:value forKey:key];
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
dispatch_group_notify(group, queue, ^{
|
|
813
|
+
// Code to execute after all async calls are completed
|
|
814
|
+
[presentationResult setObject:resultDict forKey:@"metadata"];
|
|
815
|
+
dispatch_semaphore_signal(semaphore);
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
// Wait until all async calls are completed
|
|
819
|
+
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
|
820
|
+
}*/
|
|
821
|
+
|
|
822
|
+
int resultString;
|
|
823
|
+
|
|
824
|
+
switch (presentation.type) {
|
|
825
|
+
case PLYPresentationTypeNormal:
|
|
826
|
+
resultString = PLYPresentationTypeNormal;
|
|
827
|
+
break;
|
|
828
|
+
case PLYPresentationTypeClient:
|
|
829
|
+
resultString = PLYPresentationTypeClient;
|
|
830
|
+
break;
|
|
831
|
+
case PLYPresentationTypeFallback:
|
|
832
|
+
resultString = PLYPresentationTypeFallback;
|
|
833
|
+
break;
|
|
834
|
+
case PLYPresentationTypeDeactivated:
|
|
835
|
+
resultString = PLYPresentationTypeDeactivated;
|
|
836
|
+
break;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
[presentationResult setObject:[NSNumber numberWithInt:resultString] forKey:@"type"];
|
|
840
|
+
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
return presentationResult;
|
|
844
|
+
}
|
|
845
|
+
|
|
449
846
|
- (void)successFor:(CDVInvokedUrlCommand *)command {
|
|
450
847
|
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
|
451
848
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
[dict setObject:self.vendorId forKey:@"vendorId"];
|
|
16
16
|
[dict setObject:@(self.hasIntroductoryPrice) forKey:@"hasIntroductoryPrice"];
|
|
17
17
|
[dict setObject:@([self type]) forKey:@"type"];
|
|
18
|
-
[dict setObject:@([self isEligibleForIntroOffer]) forKey:@"isEligibleForIntroOffer"];
|
|
19
18
|
|
|
20
19
|
if (self.hasIntroductoryPrice && [[self introAmount] intValue] == 0) {
|
|
21
20
|
[dict setObject:@(YES) forKey:@"hasFreeTrial"];
|