@purchasely/cordova-plugin-purchasely 2.3.2 → 4.2.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.
@@ -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
- - (void)startWithAPIKey:(CDVInvokedUrlCommand*)command {
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
- NSString *userId = [command argumentAtIndex:2];
17
- NSInteger logLevel = [[command argumentAtIndex:3] intValue];
18
- NSInteger runningMode = [[command argumentAtIndex:4] intValue];
19
- NSString *purchaselySdkVersion = [command argumentAtIndex:5];
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
- [Purchasely startWithAPIKey:apiKey appUserId:userId runningMode:runningMode eventDelegate:nil uiDelegate:nil paywallActionsInterceptor:nil logLevel:logLevel initialized:^(BOOL initialized, NSError * _Nullable error) {
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 {
@@ -46,6 +65,12 @@
46
65
  [Purchasely userLogout];
47
66
  }
48
67
 
68
+ - (void)setThemeMode:(CDVInvokedUrlCommand *)command {
69
+ NSInteger mode = [[command argumentAtIndex:0] intValue];
70
+
71
+ [Purchasely setThemeMode:(enum PLYThemeMode) mode];
72
+ }
73
+
49
74
  - (void)setAttribute:(CDVInvokedUrlCommand*)command {
50
75
  NSInteger attribute = [[command argumentAtIndex:0] intValue];
51
76
  NSString *value = [command argumentAtIndex:1];
@@ -58,9 +83,9 @@
58
83
  [self successFor:command resultString:anonymousId];
59
84
  }
60
85
 
61
- - (void)isReadyToPurchase:(CDVInvokedUrlCommand*)command {
86
+ - (void)readyToOpenDeeplink:(CDVInvokedUrlCommand*)command {
62
87
  BOOL isReadyToPurchase = [[command argumentAtIndex:0] boolValue];
63
- [Purchasely isReadyToPurchase: isReadyToPurchase];
88
+ [Purchasely readyToOpenDeeplink: isReadyToPurchase];
64
89
  }
65
90
 
66
91
  - (void)setDefaultPresentationResultHandler:(CDVInvokedUrlCommand*)command {
@@ -91,7 +116,7 @@
91
116
  [navCtrl.navigationBar setTintColor: [UIColor whiteColor]];
92
117
 
93
118
  self.presentedPresentationViewController = navCtrl;
94
-
119
+
95
120
  if (isFullscreen) {
96
121
  navCtrl.modalPresentationStyle = UIModalPresentationFullScreen;
97
122
  }
@@ -117,7 +142,7 @@
117
142
  [navCtrl.navigationBar setTintColor: [UIColor whiteColor]];
118
143
 
119
144
  self.presentedPresentationViewController = navCtrl;
120
-
145
+
121
146
  if (isFullscreen) {
122
147
  navCtrl.modalPresentationStyle = UIModalPresentationFullScreen;
123
148
  }
@@ -130,7 +155,7 @@
130
155
  NSString *presentationVendorId = [command argumentAtIndex:1];
131
156
  NSString *contentId = [command argumentAtIndex:2];
132
157
  BOOL isFullscreen = [[command argumentAtIndex:3] boolValue];
133
-
158
+
134
159
  UIViewController *ctrl = [Purchasely planControllerFor:planVendorId with:presentationVendorId contentId:contentId loaded:nil completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {
135
160
  NSDictionary *resultDict = [self resultDictionaryForPresentationController:result plan:plan];
136
161
  [self successFor:command resultDict:resultDict];
@@ -142,9 +167,9 @@
142
167
  [navCtrl.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
143
168
  [navCtrl.navigationBar setShadowImage: [UIImage new]];
144
169
  [navCtrl.navigationBar setTintColor: [UIColor whiteColor]];
145
-
170
+
146
171
  self.presentedPresentationViewController = navCtrl;
147
-
172
+
148
173
  if (isFullscreen) {
149
174
  navCtrl.modalPresentationStyle = UIModalPresentationFullScreen;
150
175
  }
@@ -157,7 +182,7 @@
157
182
  NSString *presentationVendorId = [command argumentAtIndex:1];
158
183
  NSString *contentId = [command argumentAtIndex:2];
159
184
  BOOL isFullscreen = [[command argumentAtIndex:3] boolValue];
160
-
185
+
161
186
  UIViewController *ctrl = [Purchasely productControllerFor:productVendorId with:presentationVendorId contentId:contentId loaded:nil completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {
162
187
  NSDictionary *resultDict = [self resultDictionaryForPresentationController:result plan:plan];
163
188
  [self successFor:command resultDict:resultDict];
@@ -169,9 +194,9 @@
169
194
  [navCtrl.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
170
195
  [navCtrl.navigationBar setShadowImage: [UIImage new]];
171
196
  [navCtrl.navigationBar setTintColor: [UIColor whiteColor]];
172
-
197
+
173
198
  self.presentedPresentationViewController = navCtrl;
174
-
199
+
175
200
  if (isFullscreen) {
176
201
  navCtrl.modalPresentationStyle = UIModalPresentationFullScreen;
177
202
  }
@@ -189,18 +214,50 @@
189
214
 
190
215
  - (void)purchaseWithPlanVendorId:(CDVInvokedUrlCommand*)command {
191
216
  NSString *planVendorId = [command argumentAtIndex:0];
192
-
217
+ NSString *offerId = [command argumentAtIndex:1];
218
+ NSString *contentId = [command argumentAtIndex:2];
219
+
193
220
  [Purchasely planWith:planVendorId
194
221
  success:^(PLYPlan * _Nonnull plan) {
195
- [Purchasely purchaseWithPlan:plan
196
- success:^{
197
- [self successFor:command resultDict: plan.asDictionary];
222
+
223
+ if (@available(iOS 12.2, macOS 12.0, tvOS 15.0, watchOS 8.0, *)) {
224
+
225
+ NSString *storeOfferId = nil;
226
+ for (PLYPromoOffer *promoOffer in plan.promoOffers) {
227
+ if ([promoOffer.vendorId isEqualToString:offerId]) {
228
+ storeOfferId = promoOffer.storeOfferId;
229
+ break;
230
+ }
231
+ }
232
+
233
+ if (storeOfferId) {
234
+ [Purchasely purchaseWithPromotionalOfferWithPlan:plan
235
+ contentId:contentId
236
+ storeOfferId:storeOfferId
237
+ success:^{
238
+ [self successFor:command resultDict: plan.asDictionary];
239
+ } failure:^(NSError * _Nonnull error) {
240
+ [self failureFor:command resultString: error.localizedDescription];
241
+ }];
242
+ } else {
243
+ [Purchasely purchaseWithPlan:plan
244
+ contentId:contentId
245
+ success:^{
246
+ [self successFor:command resultDict: plan.asDictionary];
247
+ } failure:^(NSError * _Nonnull error) {
248
+ [self failureFor:command resultString: error.localizedDescription];
249
+ }];
250
+ }
251
+ } else {
252
+ [Purchasely purchaseWithPlan:plan
253
+ contentId:contentId
254
+ success:^{
255
+ [self successFor:command resultDict: plan.asDictionary];
256
+ } failure:^(NSError * _Nonnull error) {
257
+ [self failureFor:command resultString: error.localizedDescription];
258
+ }];
198
259
  }
199
- failure:^(NSError * _Nonnull error) {
200
- [self failureFor:command resultString: error.localizedDescription];
201
- }];
202
- }
203
- failure:^(NSError * _Nullable error) {
260
+ } failure:^(NSError * _Nullable error) {
204
261
  [self failureFor:command resultString: error.localizedDescription];
205
262
  }];
206
263
  }
@@ -214,7 +271,7 @@
214
271
  }
215
272
 
216
273
  - (void)silentRestoreAllProducts:(CDVInvokedUrlCommand*)command {
217
- [Purchasely silentRestoreAllProductsWithSuccess:^{
274
+ [Purchasely synchronizeWithSuccess:^{
218
275
  [self successFor:command];
219
276
  } failure:^(NSError * _Nonnull error) {
220
277
  [self failureFor:command resultString:error.localizedDescription];
@@ -270,14 +327,15 @@
270
327
  }
271
328
 
272
329
  - (void)userSubscriptions:(CDVInvokedUrlCommand*)command {
273
- [Purchasely userSubscriptionsWithSuccess:^(NSArray<PLYSubscription *> * _Nullable subscriptions) {
330
+ [Purchasely userSubscriptions:false
331
+ success:^(NSArray<PLYSubscription *> * _Nullable subscriptions) {
274
332
  NSMutableArray *result = [NSMutableArray new];
275
333
  for (PLYSubscription *subscription in subscriptions) {
276
334
  [result addObject:subscription.asDictionary];
277
335
  }
278
336
  [self successFor:command resultArray:result];
279
337
  }
280
- failure:^(NSError * _Nonnull error) {
338
+ failure:^(NSError * _Nonnull error) {
281
339
  [self failureFor:command resultString:error.localizedDescription];
282
340
  }];
283
341
  }
@@ -292,27 +350,55 @@
292
350
  self.eventCommand = nil;
293
351
  }
294
352
 
295
- - (void)handle:(CDVInvokedUrlCommand*)command {
353
+ - (void)isDeeplinkHandled:(CDVInvokedUrlCommand*)command {
296
354
  NSString *deeplinkString = [command argumentAtIndex:0];
297
355
  NSURL *deeplink = [NSURL URLWithString:deeplinkString];
298
356
 
299
357
  if (deeplink != nil) {
300
- BOOL result = [Purchasely handleWithDeeplink:deeplink];
358
+ BOOL result = [Purchasely isDeeplinkHandledWithDeeplink:deeplink];
301
359
  [self successFor:command resultBool:result];
302
360
  } else {
303
361
  [self successFor:command resultBool:NO];
304
362
  }
305
363
  }
306
364
 
307
- - (void)close:(CDVInvokedUrlCommand*)command {
308
- }
309
-
310
365
  - (void)setLanguage:(CDVInvokedUrlCommand*)command {
311
366
  NSString *language = [command argumentAtIndex:0];
312
367
  NSLocale *locale = [NSLocale localeWithLocaleIdentifier:language];
313
368
  [Purchasely setLanguageFrom:locale];
314
369
  }
315
370
 
371
+ - (void)signPromotionalOffer:(CDVInvokedUrlCommand*)command {
372
+ NSString *storeProductId = [command argumentAtIndex:0];
373
+ NSString *storeOfferId = [command argumentAtIndex:1];
374
+
375
+ dispatch_async(dispatch_get_main_queue(), ^{
376
+ if (@available(iOS 12.2, *)) {
377
+ [Purchasely signPromotionalOfferWithStoreProductId:storeProductId storeOfferId:storeOfferId success:^(PLYOfferSignature * _Nonnull signature) {
378
+ NSDictionary* result = [self resultSignatureForSignPromoOffer:signature];
379
+ [self successFor:command resultBool:result];
380
+ } failure:^(NSError * _Nullable error) {
381
+ [self failureFor:command resultString:error.localizedDescription];
382
+ }];
383
+ } else {
384
+ [self failureFor:command resultString:@"This fonctionality is unavailable before ios 12.2"];
385
+ }
386
+ });
387
+ }
388
+
389
+ - (void)isEligibleForIntroOffer:(CDVInvokedUrlCommand*)command {
390
+ NSString *planVendorId = [command argumentAtIndex:0];
391
+
392
+ [Purchasely planWith:planVendorId
393
+ success:^(PLYPlan * _Nonnull plan) {
394
+ [plan isUserEligibleForIntroductoryOfferWithCompletion:^(BOOL isEligible) {
395
+ [self successFor:command resultBool:isEligible];
396
+ }];
397
+ } failure:^(NSError * _Nullable error) {
398
+ [self failureFor:command resultString:error.localizedDescription];
399
+ }];
400
+ }
401
+
316
402
  // Helpers
317
403
 
318
404
  - (NSDictionary<NSString *, NSObject *> *) resultDictionaryForPresentationController:(PLYProductViewControllerResult)result plan:(PLYPlan * _Nullable)plan {
@@ -389,7 +475,7 @@
389
475
  if (infos.abTestVariantId != nil) {
390
476
  [infosResult setObject:infos.abTestVariantId forKey:@"abTestVariantId"];
391
477
  }
392
-
478
+
393
479
  [actionInterceptorResult setObject:infosResult forKey:@"info"];
394
480
  }
395
481
  if (params != nil) {
@@ -406,9 +492,15 @@
406
492
  if (params.presentation != nil) {
407
493
  [paramsResult setObject:params.presentation forKey:@"presentation"];
408
494
  }
495
+ if (params.promoOffer != nil) {
496
+ NSMutableDictionary<NSString *, NSObject *> *promoOffer = [NSMutableDictionary new];
497
+ [promoOffer setObject:params.promoOffer.vendorId forKey:@"vendorId"];
498
+ [promoOffer setObject:params.promoOffer.storeOfferId forKey:@"storeOfferId"];
499
+ [paramsResult setObject:promoOffer forKey:@"offer"];
500
+ }
409
501
  [actionInterceptorResult setObject:paramsResult forKey:@"parameters"];
410
502
  }
411
-
503
+
412
504
  return actionInterceptorResult;
413
505
  }
414
506
 
@@ -432,20 +524,332 @@
432
524
  }
433
525
  }
434
526
 
435
- - (void)closePaywall:(CDVInvokedUrlCommand*)command {
527
+ - (void)closePresentation:(CDVInvokedUrlCommand*)command {
436
528
  if (self.presentedPresentationViewController != nil) {
437
529
  dispatch_async(dispatch_get_main_queue(), ^{
438
530
  [self.presentedPresentationViewController dismissViewControllerAnimated:true completion:^{
439
531
  self.presentedPresentationViewController = nil;
532
+ self.shouldReopenPaywall = NO;
440
533
  }];
441
534
  });
442
535
  }
443
536
  }
444
537
 
538
+ - (void)hidePresentation:(CDVInvokedUrlCommand*)command {
539
+ if (self.presentedPresentationViewController != nil) {
540
+ dispatch_async(dispatch_get_main_queue(), ^{
541
+ [self.presentedPresentationViewController dismissViewControllerAnimated:true completion:^{ }];
542
+ self.shouldReopenPaywall = YES;
543
+ });
544
+ }
545
+ }
546
+
547
+ - (void)showPresentation:(CDVInvokedUrlCommand*)command {
548
+ dispatch_async(dispatch_get_main_queue(), ^{
549
+ if (self.presentedPresentationViewController && self.shouldReopenPaywall) {
550
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
551
+ self.shouldReopenPaywall = NO;
552
+ [Purchasely showController:self.presentedPresentationViewController type:PLYUIControllerTypeProductPage];
553
+ });
554
+ }
555
+ });
556
+ }
557
+
445
558
  - (void)userDidConsumeSubscriptionContent:(CDVInvokedUrlCommand*)command {
446
559
  [Purchasely userDidConsumeSubscriptionContent];
447
560
  }
448
561
 
562
+ - (void)setUserAttributeWithString:(CDVInvokedUrlCommand*)command {
563
+ NSString *key = [command argumentAtIndex:0];
564
+ NSString *value = [command argumentAtIndex:1];
565
+ [Purchasely setUserAttributeWithStringValue:value forKey:key];
566
+ }
567
+
568
+ - (void)setUserAttributeWithBoolean:(CDVInvokedUrlCommand*)command {
569
+ NSString *key = [command argumentAtIndex:0];
570
+ BOOL value = [[command argumentAtIndex:1] boolValue];
571
+ [Purchasely setUserAttributeWithBoolValue:value forKey:key];
572
+ }
573
+
574
+ - (void)setUserAttributeWithInt:(CDVInvokedUrlCommand*)command {
575
+ NSString *key = [command argumentAtIndex:0];
576
+ NSInteger value = [[command argumentAtIndex:1] intValue];
577
+ [Purchasely setUserAttributeWithIntValue:value forKey:key];
578
+ }
579
+
580
+ - (void)setUserAttributeWithDouble:(CDVInvokedUrlCommand*)command {
581
+ NSString *key = [command argumentAtIndex:0];
582
+ double value = [[command argumentAtIndex:1] doubleValue];
583
+ [Purchasely setUserAttributeWithDoubleValue:value forKey:key];
584
+ }
585
+
586
+ - (void)setUserAttributeWithDate:(CDVInvokedUrlCommand*)command {
587
+ NSString *key = [command argumentAtIndex:0];
588
+ NSString *value = [command argumentAtIndex:1];
589
+
590
+ NSDateFormatter * dateFormatter = [NSDateFormatter new];
591
+ dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
592
+ [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
593
+ NSDate *date = [dateFormatter dateFromString:value];
594
+ if (date != nil) {
595
+ [Purchasely setUserAttributeWithDateValue:date forKey:key];
596
+ } else {
597
+ NSLog(@"[Purchasely] Cannot save date attribute %@", key);
598
+ }
599
+ }
600
+
601
+ - (void)userAttribute:(CDVInvokedUrlCommand*)command {
602
+ NSString *key = [command argumentAtIndex:0];
603
+
604
+ id _Nullable result = [self getUserAttributeValueForCordova:[Purchasely getUserAttributeFor:key]];
605
+ if (result != nil) {
606
+ [self successFor:command resultDict:result];
607
+ } else {
608
+ [self failureFor:command resultString:@"Cannot get user attribute"];
609
+ }
610
+ }
611
+
612
+ - (id _Nullable) getUserAttributeValueForCordova:(id _Nullable) value {
613
+ if ([value isKindOfClass:[NSDate class]]) {
614
+ NSDateFormatter * dateFormatter = [NSDateFormatter new];
615
+ dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
616
+ [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
617
+ NSString *dateStr = [dateFormatter stringFromDate:value];
618
+ return dateStr;
619
+ }
620
+
621
+ return value;
622
+ }
623
+
624
+ - (void)clearUserAttribute:(CDVInvokedUrlCommand*)command {
625
+ NSString *key = [command argumentAtIndex:0];
626
+ [Purchasely clearUserAttributeForKey:key];
627
+ }
628
+
629
+ - (void)clearUserAttributes:(CDVInvokedUrlCommand*)command {
630
+ [Purchasely clearUserAttributes];
631
+ }
632
+
633
+ - (void)fetchPresentation:(CDVInvokedUrlCommand*)command {
634
+ NSString *placementId = [command argumentAtIndex:0];
635
+ NSString *presentationId = [command argumentAtIndex:1];
636
+ NSString *contentId = [command argumentAtIndex:2];
637
+
638
+ dispatch_async(dispatch_get_main_queue(), ^{
639
+ if (placementId != nil) {
640
+ [Purchasely fetchPresentationFor:placementId contentId: contentId fetchCompletion:^(PLYPresentation * _Nullable presentation, NSError * _Nullable error) {
641
+ if (error != nil) {
642
+ [self failureFor:command resultString: error.localizedDescription];
643
+ } else if (presentation != nil) {
644
+ [self.presentationsLoaded addObject:presentation];
645
+ [self successFor:command resultDict:[self resultDictionaryForFetchPresentation:presentation]];
646
+ }
647
+ } completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {
648
+ if (self.purchaseResolve != nil){
649
+ [self successFor:self.purchaseResolve resultDict:[self resultDictionaryForPresentationController:result plan:plan]];
650
+ }
651
+ }];
652
+ } else {
653
+ [Purchasely fetchPresentationWith:presentationId contentId: contentId fetchCompletion:^(PLYPresentation * _Nullable presentation, NSError * _Nullable error) {
654
+ if (error != nil) {
655
+ [self failureFor:command resultString: error.localizedDescription];
656
+ } else if (presentation != nil) {
657
+ [self.presentationsLoaded addObject:presentation];
658
+ [self successFor:command resultDict:[self resultDictionaryForFetchPresentation:presentation]];
659
+ }
660
+ } completion:^(enum PLYProductViewControllerResult result, PLYPlan * _Nullable plan) {
661
+ if (self.purchaseResolve != nil) {
662
+ [self successFor:self.purchaseResolve resultDict:[self resultDictionaryForPresentationController:result plan:plan]];
663
+ }
664
+ }];
665
+ }
666
+ });
667
+ }
668
+
669
+ - (void)presentPresentation:(CDVInvokedUrlCommand *)command {
670
+ NSDictionary<NSString *, id> *presentationDictionary = [command argumentAtIndex:0];
671
+ BOOL isFullscreen = [[command argumentAtIndex:1] boolValue];
672
+ NSString *loadingBackgroundColor = [command argumentAtIndex:2];
673
+
674
+ if (presentationDictionary == nil) {
675
+ [self failureFor:command resultString: @"Presentation cannot be null"];
676
+ return;
677
+ }
678
+
679
+ self.purchaseResolve = command;
680
+
681
+ dispatch_async(dispatch_get_main_queue(), ^{
682
+
683
+ PLYPresentation *presentationLoaded = [self findPresentationLoadedFor:(NSString *)[presentationDictionary objectForKey:@"id"]];
684
+
685
+ if (presentationLoaded == nil || presentationLoaded.controller == nil) {
686
+ [self failureFor:command resultString: @"Presentation not loaded"];
687
+ return;
688
+ }
689
+
690
+ [self.presentationsLoaded removeObjectAtIndex:[self findIndexPresentationLoadedFor:(NSString *)[presentationDictionary objectForKey:@"id"]]];
691
+
692
+ if (presentationLoaded.controller != nil) {
693
+ if (loadingBackgroundColor != nil) {
694
+ UIColor *backColor = [UIColor ply_fromHex:loadingBackgroundColor];
695
+ if (backColor != nil) {
696
+ [presentationLoaded.controller.view setBackgroundColor:backColor];
697
+ }
698
+ }
699
+
700
+ if (isFullscreen) {
701
+ presentationLoaded.controller.modalPresentationStyle = UIModalPresentationFullScreen;
702
+ }
703
+
704
+ self.shouldReopenPaywall = NO;
705
+
706
+ [Purchasely closeDisplayedPresentation];
707
+ self.presentedPresentationViewController = presentationLoaded.controller;
708
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
709
+ [Purchasely showController:presentationLoaded.controller type: PLYUIControllerTypeProductPage];
710
+ });
711
+ }
712
+ });
713
+ }
714
+
715
+ - (PLYPresentation *) findPresentationLoadedFor:(NSString * _Nullable) presentationId {
716
+ for (PLYPresentation *presentationLoaded in self.presentationsLoaded) {
717
+ if ([presentationLoaded.id isEqualToString: presentationId]) {
718
+ return presentationLoaded;
719
+ }
720
+ }
721
+ return nil;
722
+ }
723
+
724
+ - (NSInteger) findIndexPresentationLoadedFor:(NSString * _Nullable) presentationId {
725
+ NSInteger index = 0;
726
+ for (PLYPresentation *presentationLoaded in self.presentationsLoaded) {
727
+ if ([presentationLoaded.id isEqualToString: presentationId]) {
728
+ return index;
729
+ }
730
+ index++;
731
+ }
732
+ return -1;
733
+ }
734
+
735
+ - (NSDictionary *)resultSignatureForSignPromoOffer:(PLYOfferSignature * _Nullable) signature {
736
+ NSMutableDictionary<NSString *, NSObject *> *dict = [NSMutableDictionary new];
737
+
738
+ [dict setObject:signature.planVendorId forKey:@"planVendorId"];
739
+ [dict setObject:signature.identifier forKey:@"identifier"];
740
+ [dict setObject:signature.signature forKey:@"signature"];
741
+ [dict setObject:signature.keyIdentifier forKey:@"keyIdentifier"];
742
+
743
+ NSString *nonceString = [signature.nonce UUIDString];
744
+ NSObject *nonce = (NSObject *)nonceString;
745
+ if (nonce != nil) {
746
+ [dict setObject:nonce forKey:@"nonce"];
747
+ }
748
+
749
+ NSNumber *timestamp = [NSNumber numberWithDouble:signature.timestamp];
750
+ if (timestamp != nil) {
751
+ [dict setObject:timestamp forKey:@"timestamp"];
752
+ }
753
+
754
+ return dict;
755
+ }
756
+
757
+ - (NSDictionary<NSString *, NSObject *> *) resultDictionaryForFetchPresentation:(PLYPresentation * _Nullable) presentation {
758
+ NSMutableDictionary<NSString *, NSObject *> *presentationResult = [NSMutableDictionary new];
759
+
760
+ // TODO: fill all parameters.
761
+ if (presentation != nil) {
762
+
763
+ if (presentation.id != nil) {
764
+ [presentationResult setObject:presentation.id forKey:@"id"];
765
+ }
766
+
767
+ if (presentation.placementId != nil) {
768
+ [presentationResult setObject:presentation.placementId forKey:@"placementId"];
769
+ }
770
+
771
+ if (presentation.audienceId != nil) {
772
+ [presentationResult setObject:presentation.audienceId forKey:@"audienceId"];
773
+ }
774
+
775
+ if (presentation.abTestId != nil) {
776
+ [presentationResult setObject:presentation.abTestId forKey:@"abTestId"];
777
+ }
778
+
779
+ if (presentation.abTestVariantId != nil) {
780
+ [presentationResult setObject:presentation.abTestVariantId forKey:@"abTestVariantId"];
781
+ }
782
+
783
+ if (presentation.language != nil) {
784
+ [presentationResult setObject:presentation.language forKey:@"language"];
785
+ }
786
+
787
+ if (presentation.plans != nil) {
788
+ NSMutableArray *plans = [NSMutableArray new];
789
+
790
+ for (PLYPresentationPlan *plan in presentation.plans) {
791
+ [plans addObject:plan.asDictionary];
792
+ }
793
+ [presentationResult setObject:plans forKey:@"plans"];
794
+ }
795
+
796
+ /*if (presentation.metadata != nil) {
797
+
798
+ NSDictionary<NSString *,id> *rawMetadata = [presentation.metadata getRawMetadata];
799
+ NSMutableDictionary<NSString *,id> *resultDict = [NSMutableDictionary dictionary];
800
+
801
+ dispatch_group_t group = dispatch_group_create();
802
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
803
+ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
804
+
805
+ for (NSString *key in rawMetadata) {
806
+ id value = rawMetadata[key];
807
+
808
+ if ([value isKindOfClass: [NSString class]]) {
809
+ dispatch_group_enter(group); // Enter the dispatch group before making the async call
810
+ [presentation.metadata getStringWith:key completion:^(NSString * _Nullable result) {
811
+ [resultDict setObject:result forKey:key];
812
+ dispatch_group_leave(group); // Leave the dispatch group after the async call is completed
813
+ }];
814
+ } else {
815
+ [resultDict setObject:value forKey:key];
816
+ }
817
+ }
818
+
819
+ dispatch_group_notify(group, queue, ^{
820
+ // Code to execute after all async calls are completed
821
+ [presentationResult setObject:resultDict forKey:@"metadata"];
822
+ dispatch_semaphore_signal(semaphore);
823
+ });
824
+
825
+ // Wait until all async calls are completed
826
+ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
827
+ }*/
828
+
829
+ int resultString;
830
+
831
+ switch (presentation.type) {
832
+ case PLYPresentationTypeNormal:
833
+ resultString = PLYPresentationTypeNormal;
834
+ break;
835
+ case PLYPresentationTypeClient:
836
+ resultString = PLYPresentationTypeClient;
837
+ break;
838
+ case PLYPresentationTypeFallback:
839
+ resultString = PLYPresentationTypeFallback;
840
+ break;
841
+ case PLYPresentationTypeDeactivated:
842
+ resultString = PLYPresentationTypeDeactivated;
843
+ break;
844
+ }
845
+
846
+ [presentationResult setObject:[NSNumber numberWithInt:resultString] forKey:@"type"];
847
+
848
+ }
849
+
850
+ return presentationResult;
851
+ }
852
+
449
853
  - (void)successFor:(CDVInvokedUrlCommand *)command {
450
854
  CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
451
855
  [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"];
@@ -0,0 +1,20 @@
1
+ //
2
+ // PLYPresentationPlan+Hybrid.h
3
+ // Pods
4
+ //
5
+ // Created by Florian Huet on 29/09/2023.
6
+ //
7
+
8
+ #import <Foundation/Foundation.h>
9
+ #import <Purchasely/Purchasely-Swift.h>
10
+ //@import Purchasely;
11
+
12
+ NS_ASSUME_NONNULL_BEGIN
13
+
14
+ @interface PLYPresentationPlan (Hybrid)
15
+
16
+ - (NSDictionary *)asDictionary;
17
+
18
+ @end
19
+
20
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,31 @@
1
+ //
2
+ // PLYPresentationPlan+Hybrid.m
3
+ // react-native-purchasely
4
+ //
5
+ // Created by Florian Huet on 29/09/2023.
6
+ //
7
+
8
+ #import "PLYPresentationPlan+Hybrid.h"
9
+ #import <Foundation/Foundation.h>
10
+
11
+ @implementation PLYPresentationPlan (Hybrid)
12
+
13
+ - (NSDictionary *)asDictionary {
14
+ NSMutableDictionary<NSString *, NSObject *> *dict = [NSMutableDictionary new];
15
+
16
+ if (self.offerId) {
17
+ [dict setObject:self.offerId forKey:@"offerId"];
18
+ }
19
+
20
+ if (self.storeProductId) {
21
+ [dict setObject:self.storeProductId forKey:@"storeProductId"];
22
+ }
23
+
24
+ if (self.planVendorId) {
25
+ [dict setObject:self.planVendorId forKey:@"planVendorId"];
26
+ }
27
+
28
+ return dict;
29
+ }
30
+
31
+ @end