From d096957e46309f02799b1f9413204e226ff0d5c5 Mon Sep 17 00:00:00 2001 From: lgarbo <387293+lgarbo@users.noreply.github.com> Date: Wed, 23 Feb 2022 10:54:58 +0100 Subject: [PATCH] Release v1.1.8 --- Glassfy.podspec | 2 +- Glassfy.xcodeproj/project.pbxproj | 8 ++- README.md | 2 +- Source/GYAPIManager.h | 1 + Source/GYAPIManager.m | 15 +++++ Source/GYManager.h | 6 +- Source/GYManager.m | 99 ++++++++++++++++++++++++++---- Source/GYOffering+Private.h | 2 +- Source/GYOffering.m | 17 ++--- Source/GYOfferings.m | 4 +- Source/GYPermission.m | 11 +++- Source/GYPermissions.m | 4 +- Source/GYSku+Private.h | 2 +- Source/GYSku.m | 14 ++++- Source/GYTransaction.m | 15 ++++- Source/Glassfy.m | 28 ++++++++- Source/Public/GYOffering.h | 8 ++- Source/Public/GYOfferings.h | 2 +- Source/Public/GYPermission.h | 6 +- Source/Public/GYPermissions.h | 2 +- Source/Public/GYPurchaseDelegate.h | 28 +++++++++ Source/Public/GYSku.h | 6 +- Source/Public/GYTransaction.h | 11 +++- Source/Public/GYTypes.h | 8 +-- Source/Public/Glassfy.h | 25 +++++++- 25 files changed, 274 insertions(+), 52 deletions(-) create mode 100644 Source/Public/GYPurchaseDelegate.h diff --git a/Glassfy.podspec b/Glassfy.podspec index 7e40cf1..7843085 100644 --- a/Glassfy.podspec +++ b/Glassfy.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Glassfy" - s.version = "1.1.7" + s.version = "1.1.8" s.summary = "Subscription and in-app-purchase service." s.license = { :type => 'MIT', :file => 'LICENSE' } s.source = { :git => "https://github.com/glassfy/ios-sdk.git", :tag => s.version.to_s } diff --git a/Glassfy.xcodeproj/project.pbxproj b/Glassfy.xcodeproj/project.pbxproj index cf1db2e..d8e9a40 100644 --- a/Glassfy.xcodeproj/project.pbxproj +++ b/Glassfy.xcodeproj/project.pbxproj @@ -77,6 +77,7 @@ 81EFB54425A772D900706FCB /* GYAPIPermissionsResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EFB54225A772D900706FCB /* GYAPIPermissionsResponse.h */; settings = {ATTRIBUTES = (Private, ); }; }; 81EFB54525A772D900706FCB /* GYAPIPermissionsResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EFB54325A772D900706FCB /* GYAPIPermissionsResponse.m */; }; 81EFB54B25A772F200706FCB /* GYPermission.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EFB54925A772F200706FCB /* GYPermission.m */; }; + 81FCCE8627C3CE0A00DF3D1A /* GYPurchaseDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 81FCCE8527C3CE0A00DF3D1A /* GYPurchaseDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -164,6 +165,7 @@ 81EFB54325A772D900706FCB /* GYAPIPermissionsResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GYAPIPermissionsResponse.m; sourceTree = ""; }; 81EFB54925A772F200706FCB /* GYPermission.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GYPermission.m; sourceTree = ""; }; 81EFB55025A7736B00706FCB /* GYPermission+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GYPermission+Private.h"; sourceTree = ""; }; + 81FCCE8527C3CE0A00DF3D1A /* GYPurchaseDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GYPurchaseDelegate.h; path = Public/GYPurchaseDelegate.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -265,6 +267,7 @@ 8191E86A26690C850077BDD7 /* GYUserProperties.h */, 816EF2882661161200513FB1 /* GYUserProperties.m */, 81951CD226443F82003901F1 /* GYTypes.h */, + 81FCCE8527C3CE0A00DF3D1A /* GYPurchaseDelegate.h */, 816830B3258B6EA100565968 /* Core */, 8104537B25909F380015A728 /* Data */, 817A1CC7258CE9C700D1BA10 /* Utils */, @@ -344,6 +347,7 @@ 81010F292590C1AB00B07DE4 /* GYAPIOfferingsResponse.h in Headers */, 81951CD726443F94003901F1 /* GYOfferings.h in Headers */, 8138BAB225924D0A005CB44E /* SKProductSubscriptionPeriod+GYEncode.h in Headers */, + 81FCCE8627C3CE0A00DF3D1A /* GYPurchaseDelegate.h in Headers */, 817A1CF5258CF63600D1BA10 /* GYAPIManager.h in Headers */, 817A1CE7258CF46600D1BA10 /* GYCacheManager.h in Headers */, 81E1DC3225933FC7003B5EBD /* SKPayment+GYEncode.h in Headers */, @@ -668,7 +672,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.1.7; + MARKETING_VERSION = 1.1.8; PRODUCT_BUNDLE_IDENTIFIER = net.glassfy.sdk; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -695,7 +699,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.1.7; + MARKETING_VERSION = 1.1.8; PRODUCT_BUNDLE_IDENTIFIER = net.glassfy.sdk; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/README.md b/README.md index aace746..b16e4e0 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Our SDK can be easly integrated through Cocoapods or Swift Package Manager #### Integrate using Cocoapods Add the pod to your Podfile: -```pod 'Glassfy', '~> 1.1.7'``` +```pod 'Glassfy', '~> 1.1.8'``` Then, run the following command: diff --git a/Source/GYAPIManager.h b/Source/GYAPIManager.h index a9cf60f..78b082b 100644 --- a/Source/GYAPIManager.h +++ b/Source/GYAPIManager.h @@ -42,6 +42,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)getInitWithInfoWithCompletion:(GYGetInitCompletion _Nullable)block; - (void)getSku:(NSString *)skuid withCompletion:(GYGetSkuCompletion _Nullable)block; +- (void)getSkuWithProductId:(NSString *)productid promotionalId:(NSString *_Nullable)promoid withCompletion:(GYGetSkuCompletion _Nullable)block; - (void)getOfferingsWithCompletion:(GYGetOfferingsCompletion _Nullable)block; - (void)getPermissionsWithCompletion:(GYGetPermissionsCompletion _Nullable)block; diff --git a/Source/GYAPIManager.m b/Source/GYAPIManager.m index 07318aa..b4b7719 100644 --- a/Source/GYAPIManager.m +++ b/Source/GYAPIManager.m @@ -105,6 +105,21 @@ - (void)getSku:(NSString *)skuid withCompletion:(GYGetSkuCompletion)block [self callApiWithRequest:req response:GYAPISkuResponse.class completion:block]; } +- (void)getSkuWithProductId:(NSString *)productid promotionalId:(NSString *)promoid withCompletion:(GYGetSkuCompletion)block +{ + NSURLComponents *url = [self baseURLV0]; + url.path = [url.path stringByAppendingPathComponent:@"sku"]; + NSMutableArray *queryItems = [(url.queryItems ?: @[]) mutableCopy]; + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"productid" value:productid]]; + if (promoid && promoid.length > 0) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"promotionalid" value:promoid]]; + } + url.queryItems = queryItems; + + NSURLRequest *req = [self authorizedRequestWithComponents:url]; + [self callApiWithRequest:req response:GYAPISkuResponse.class completion:block]; +} + - (void)getOfferingsWithCompletion:(GYGetOfferingsCompletion)block { NSURLComponents *url = [self baseURLV0]; diff --git a/Source/GYManager.h b/Source/GYManager.h index 8282aeb..961d110 100644 --- a/Source/GYManager.h +++ b/Source/GYManager.h @@ -7,6 +7,7 @@ #import #import "GYTypes.h" +#import "GYPurchaseDelegate.h" @class GYSku; @@ -18,12 +19,15 @@ NS_ASSUME_NONNULL_BEGIN + (GYManager *)managerWithApiKey:(NSString *)apiKey watcherMode:(BOOL)watcherMode; +- (void)setPurchaseDelegate:(id)delegate; + - (void)loginUser:(NSString *_Nullable)userId withCompletion:(GYErrorCompletion _Nullable)block; - (void)logoutWithCompletion:(GYErrorCompletion _Nullable)block; - (void)permissionsWithCompletion:(GYPermissionsCompletion)block; - (void)offeringsWithCompletion:(GYOfferingsCompletion)block; -- (void)skuWithIdentifier:(NSString *)skuid completion:(GYSkuBlock)block; +- (void)skuWithId:(NSString *)skuid completion:(GYSkuBlock)block; +- (void)skuWithProductId:(NSString *)productid promotionalId:(NSString *_Nullable)promoid completion:(GYSkuBlock)block; - (void)purchaseSku:(GYSku *)sku completion:(GYPaymentTransactionBlock)block; - (void)purchaseSku:(GYSku *)sku withDiscount:(SKProductDiscount *_Nullable)discount completion:(GYPaymentTransactionBlock)block API_AVAILABLE(ios(12.2), macos(10.14.4), watchos(6.2)); diff --git a/Source/GYManager.m b/Source/GYManager.m index 5b09c51..e471cbb 100644 --- a/Source/GYManager.m +++ b/Source/GYManager.m @@ -32,6 +32,7 @@ @interface GYManager() @property(nonatomic, assign) BOOL watcherMode; @property(nonatomic, assign) BOOL initialized; +@property(nonatomic, weak) id purchasesDelegate; @property(nonatomic, strong) NSMapTable *purchaseCompletions; @end @@ -69,6 +70,11 @@ - (void)dealloc [NSNotificationCenter.defaultCenter removeObserver:self]; } +- (void)setPurchaseDelegate:(id)delegate +{ + _purchasesDelegate = delegate; +} + - (NSString *)apiKey { return self.api.apiKey; @@ -130,7 +136,7 @@ - (void)offeringsWithCompletion:(GYOfferingsCompletion)block }]; } -- (void)skuWithIdentifier:(NSString *)skuid completion:(GYSkuBlock)block +- (void)skuWithId:(NSString *)skuid completion:(GYSkuBlock)block { [self.api getSku:skuid withCompletion:^(GYAPISkuResponse *res, NSError *apiErr) { GYSku *sku = res.sku; @@ -162,6 +168,38 @@ - (void)skuWithIdentifier:(NSString *)skuid completion:(GYSkuBlock)block }]; } +- (void)skuWithProductId:(NSString *)productid promotionalId:(NSString *)promoid completion:(GYSkuBlock)block +{ + [self.api getSkuWithProductId:productid promotionalId:promoid withCompletion:^(GYAPISkuResponse *res, NSError *apiErr) { + GYSku *sku = res.sku; + [self.store productWithIdentifier:sku.productId completion:^(SKProduct *product, NSError *storeErr) { + sku.product = product; + + NSError *err = apiErr ?: storeErr; + if (!err) { + if (!product) { + err = GYError.storeProductNotFound; + } + else if (@available(iOS 12.2, macOS 10.14.4, watchOS 6.2, *)) { + if (sku.promotionalId && !sku.discount) { + err = GYError.storeProductNotFound; + } + } + else if (sku.promotionalId) { + err = GYError.storeProductNotFound; + } + } + + typeof(block) __strong completion = block; + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + err ? completion(nil, err) : completion(sku, nil); + }); + } + }]; + }]; +} + - (void)purchaseSku:(GYSku *)sku completion:(GYPaymentTransactionBlock)block { [self purchaseSku:sku withDiscountId:sku.promotionalId completion:block]; @@ -295,6 +333,37 @@ - (void)applicationDidBecomeActive:(NSNotification *)notification #pragma mark - SKPaymentTransactionObserver +- (BOOL)paymentQueue:(SKPaymentQueue *)queue shouldAddStorePayment:(SKPayment *)payment forProduct:(SKProduct *)product +{ + if ([self.purchasesDelegate respondsToSelector:@selector(handlePromotedProductId:withPromotionalId:purchaseHandler:)]) + { + NSString *promoid; + if (@available(iOS 12.2, *)) { + promoid = payment.paymentDiscount.identifier; + } + NSString *productid = product.productIdentifier; + + typeof(self) __weak weakSelf = self; + [self.purchasesDelegate handlePromotedProductId:productid + withPromotionalId:promoid + purchaseHandler:^(GYPaymentTransactionBlock completionHandler) + { + dispatch_async(Glassfy.shared.glqueue, ^{ + GYPaymentTransactionBlock completion = completionHandler ?: ^void(GYTransaction *tranansaction, NSError *err) { + GYLogInfo(@"Promotion completion handler"); + }; + + GYSku *sku = [GYSku skuWithProduct:product]; + [weakSelf.purchaseCompletions setObject:completion forKey:sku]; + + [SKPaymentQueue.defaultQueue addPayment:payment]; + }); + }]; + return NO; + } + return YES; +} + - (void)paymentQueue:(nonnull SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray *)transactions { typeof(self) __weak weakSelf = self; @@ -310,11 +379,11 @@ - (void)handleUpdatedTransactions:(nonnull NSArray *)tra GYTransaction *t = [GYTransaction transactionWithPaymentTransaction:transaction]; switch (transaction.transactionState) { case SKPaymentTransactionStatePurchased: - GYLog(@"TRANSACTION %@ PURCHASED", t.productIdentifier); + GYLog(@"TRANSACTION %@ PURCHASED", t.productId); [self handlePurchasedTransaction:t]; break; case SKPaymentTransactionStateRestored: // status from -[SKPaymentQueue restoreCompletedTransactions]; - GYLog(@"TRANSACTION %@ RESTORED", t.productIdentifier); + GYLog(@"TRANSACTION %@ RESTORED", t.productId); if (!restored) { [self handleRestoredTransaction:t]; restored = YES; @@ -324,15 +393,15 @@ - (void)handleUpdatedTransactions:(nonnull NSArray *)tra } break; case SKPaymentTransactionStateFailed: - GYLogErr(@"TRANSACTION %@ FAILED: %@", t.productIdentifier, t.paymentTransaction.error.debugDescription); + GYLogErr(@"TRANSACTION %@ FAILED: %@", t.productId, t.paymentTransaction.error.debugDescription); [self handleFailedTransaction:t]; break; case SKPaymentTransactionStateDeferred: - GYLog(@"TRANSACTION %@ DEFERRED", t.productIdentifier); + GYLog(@"TRANSACTION %@ DEFERRED", t.productId); [self handleDeferredTransaction:t]; break; case SKPaymentTransactionStatePurchasing: - GYLog(@"TRANSACTION %@ PURCHASING", t.productIdentifier); + GYLog(@"TRANSACTION %@ PURCHASING", t.productId); break; } } @@ -343,7 +412,7 @@ - (void)handlePurchasedTransaction:(GYTransaction *)t GYPaymentTransactionBlock completion; GYSku *sku; for (GYSku *s in self.purchaseCompletions.keyEnumerator) { - if ([s.productId isEqualToString:t.productIdentifier]) { + if ([s.productId isEqualToString:t.productId]) { sku = s; completion = [self.purchaseCompletions objectForKey:s]; [self.purchaseCompletions removeObjectForKey:s]; @@ -361,7 +430,7 @@ - (void)handlePurchasedTransaction:(GYTransaction *)t if (appStoreURL && [NSFileManager.defaultManager fileExistsAtPath:appStoreURL.path]) { typeof(self) __weak weakSelf = self; if (!sku) { - [self.store productWithIdentifier:t.productIdentifier completion:^(SKProduct *p, NSError *err) { + [self.store productWithIdentifier:t.productId completion:^(SKProduct *p, NSError *err) { if (p) { GYSku *s = [GYSku skuWithProduct:p]; [weakSelf.purchaseCompletions setObject:completion forKey:s]; @@ -377,6 +446,9 @@ - (void)handlePurchasedTransaction:(GYTransaction *)t t.receiptValidated = (err.code != GYErrorCodeAppleReceiptStatusError); dispatch_async(dispatch_get_main_queue(), ^{ completion(t, err); + if (!err && [weakSelf.purchasesDelegate respondsToSelector:@selector(didPurchaseProduct:)]) { + [weakSelf.purchasesDelegate didPurchaseProduct:t]; + } }); [weakSelf completeTransaction:t]; }]; @@ -394,6 +466,9 @@ - (void)handlePurchasedTransaction:(GYTransaction *)t t.receiptValidated = (err.code != GYErrorCodeAppleReceiptStatusError); dispatch_async(dispatch_get_main_queue(), ^{ completion(t, err); + if (!err && [weakSelf.purchasesDelegate respondsToSelector:@selector(didPurchaseProduct:)]) { + [weakSelf.purchasesDelegate didPurchaseProduct:t]; + } }); [weakSelf completeTransaction:t]; }]; @@ -418,7 +493,7 @@ - (void)handleFailedTransaction:(GYTransaction *)t GYPaymentTransactionBlock completion; for (GYSku *s in self.purchaseCompletions.keyEnumerator) { - if ([s.productId isEqualToString:t.productIdentifier]) { + if ([s.productId isEqualToString:t.productId]) { completion = [self.purchaseCompletions objectForKey:s]; [self.purchaseCompletions removeObjectForKey:s]; break; @@ -474,7 +549,7 @@ - (void)handleDeferredTransaction:(GYTransaction *)t { GYPaymentTransactionBlock completion; for (GYSku *s in self.purchaseCompletions.keyEnumerator) { - if ([s.productId isEqualToString:t.productIdentifier]) { + if ([s.productId isEqualToString:t.productId]) { completion = [self.purchaseCompletions objectForKey:s]; [self.purchaseCompletions removeObjectForKey:s]; break; @@ -489,10 +564,10 @@ - (void)handleDeferredTransaction:(GYTransaction *)t - (void)completeTransaction:(GYTransaction *)t { - GYLog(@"TRANSACTION %@ COMPLETED", t.productIdentifier); + GYLog(@"TRANSACTION %@ COMPLETED", t.productId); if (t.paymentTransaction && !self.watcherMode) { - GYLog(@"TRANSACTION %@ FINISH", t.productIdentifier); + GYLog(@"TRANSACTION %@ FINISH", t.productId); [[SKPaymentQueue defaultQueue] finishTransaction:t.paymentTransaction]; } } diff --git a/Source/GYOffering+Private.h b/Source/GYOffering+Private.h index 3bc63e4..f2e3f98 100644 --- a/Source/GYOffering+Private.h +++ b/Source/GYOffering+Private.h @@ -12,7 +12,7 @@ NS_ASSUME_NONNULL_BEGIN @interface GYOffering (Private) // @property(nonatomic, nullable, strong) NSString *name; -@property(nonatomic, strong) NSString *identifier; +@property(nonatomic, strong) NSString *offeringId; @property(nonatomic, strong) NSArray *skus; @end diff --git a/Source/GYOffering.m b/Source/GYOffering.m index 9ec3092..b58cb29 100644 --- a/Source/GYOffering.m +++ b/Source/GYOffering.m @@ -11,7 +11,7 @@ @interface GYOffering() //@property(nonatomic, nullable, strong) NSString *name; -@property(nonatomic, strong) NSString *identifier; +@property(nonatomic, strong) NSString *offeringId; @property(nonatomic, strong) NSArray *skus; @end @@ -23,10 +23,6 @@ - (instancetype)initWithObject:(nonnull NSDictionary *)obj error:(NSError **)err if ([obj[@"identifier"] isKindOfClass:NSString.class]) { identifier = obj[@"identifier"]; } -// NSString *name; -// if ([obj[@"name"] isKindOfClass:NSString.class]) { -// name = obj[@"name"]; -// } NSMutableArray *skus = [NSMutableArray array]; if ([obj[@"skus"] isKindOfClass:NSArray.class]) { @@ -54,8 +50,7 @@ - (instancetype)initWithObject:(nonnull NSDictionary *)obj error:(NSError **)err self = [super init]; if (self) { -// self.name = name; - self.identifier = identifier; + self.offeringId = identifier; self.skus = skus; } return self; @@ -65,4 +60,12 @@ - (instancetype)initWithObject:(nonnull NSDictionary *)obj error:(NSError **)err @implementation GYOffering + +#pragma mark - Deprecations + +- (NSString *)identifier +{ + return self.offeringId; +} + @end diff --git a/Source/GYOfferings.m b/Source/GYOfferings.m index 1d3dd5c..b455077 100644 --- a/Source/GYOfferings.m +++ b/Source/GYOfferings.m @@ -53,7 +53,7 @@ @implementation GYOfferings #pragma mark - Custom Keyed Subscripting method -- (GYOffering *)objectForKeyedSubscript:(NSString *)identifier +- (GYOffering *)objectForKeyedSubscript:(NSString *)offeringid { GYOffering *result = nil; if (!self.all || self.all.count == 0) { @@ -61,7 +61,7 @@ - (GYOffering *)objectForKeyedSubscript:(NSString *)identifier } for (GYOffering *o in self.all) { - if ([o.identifier isEqualToString:identifier]) { + if ([o.offeringId isEqualToString:offeringid]) { result = o; break; } diff --git a/Source/GYPermission.m b/Source/GYPermission.m index 5d25935..7fdcda7 100644 --- a/Source/GYPermission.m +++ b/Source/GYPermission.m @@ -8,7 +8,7 @@ #import "GYPermission.h" @interface GYPermission() -@property(nonatomic, readwrite, strong) NSString *permissionIdentifier; +@property(nonatomic, readwrite, strong) NSString *permissionId; @property(nonatomic, assign) GYEntitlement entitlement; @property(nonatomic, readwrite, strong) NSDate *expireDate; @property(nonatomic, readwrite, strong) NSSet *accountableSkus; @@ -22,7 +22,7 @@ + (instancetype)permissionWithIdentifier:(NSString *)identifier accountableSkus:(NSSet *)skuIds { GYPermission *permission = [[self alloc] init]; - permission.permissionIdentifier = identifier; + permission.permissionId = identifier; permission.entitlement = entitlement; permission.expireDate = date; permission.accountableSkus = skuIds; @@ -38,4 +38,11 @@ - (BOOL)isValid return self.entitlement > 0; } + +#pragma mark - Deprecations + +- (NSString *)permissionIdentifier { + return self.permissionId; +} + @end diff --git a/Source/GYPermissions.m b/Source/GYPermissions.m index 1e302bf..989af79 100644 --- a/Source/GYPermissions.m +++ b/Source/GYPermissions.m @@ -46,7 +46,7 @@ @implementation GYPermissions #pragma mark - Custom Keyed Subscripting method -- (nullable GYPermission *)objectForKeyedSubscript:(NSString *)identifier +- (nullable GYPermission *)objectForKeyedSubscript:(NSString *)permissionid { GYPermission *result = nil; if (!self.all || self.all.count == 0) { @@ -54,7 +54,7 @@ - (nullable GYPermission *)objectForKeyedSubscript:(NSString *)identifier } for (GYPermission *o in self.all) { - if ([o.permissionIdentifier isEqualToString:identifier]) { + if ([o.permissionId isEqualToString:permissionid]) { result = o; break; } diff --git a/Source/GYSku+Private.h b/Source/GYSku+Private.h index f36d18e..9de91bc 100644 --- a/Source/GYSku+Private.h +++ b/Source/GYSku+Private.h @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN @interface GYSku (Private) + (instancetype)skuWithProduct:(SKProduct *)product; -@property(nonatomic, strong) NSString *identifier; +@property(nonatomic, strong) NSString *skuId; @property(nonatomic, strong) NSString *productId; @property(nonatomic, nullable, strong) NSString *promotionalId; @property(nonatomic, nullable, strong) NSString *offeringId; diff --git a/Source/GYSku.m b/Source/GYSku.m index ab9174a..7bf3473 100644 --- a/Source/GYSku.m +++ b/Source/GYSku.m @@ -10,7 +10,7 @@ #import "SKProduct+GYEncode.h" @interface GYSku() -@property(nonatomic, strong) NSString *identifier; +@property(nonatomic, strong) NSString *skuId; @property(nonatomic, strong) NSString *productId; @property(nonatomic, nullable, strong) NSString *promotionalId; @property(nonatomic, nullable, strong) NSString *offeringId; @@ -74,7 +74,7 @@ - (instancetype)initWithObject:(nonnull NSDictionary *)obj error:(NSError **)err self = [super init]; if (self) { self.extravars = extravars; - self.identifier = identifier; + self.skuId = identifier; self.productId = productId; self.promotionalId = promotionalId; self.introductoryEligibility = introductoryEligibility; @@ -89,7 +89,7 @@ + (instancetype)skuWithProduct:(SKProduct *)product if (sku) { sku.product = product; sku.extravars = @{}; - sku.identifier = @""; + sku.skuId = @""; sku.productId = product.productIdentifier; sku.introductoryEligibility = GYSkuEligibilityUnknown; sku.promotionalEligibility = GYSkuEligibilityUnknown; @@ -117,4 +117,12 @@ - (SKProductDiscount *)discount return [self.product.discounts filteredArrayUsingPredicate:p].firstObject; } + +#pragma mark - Deprecations + +- (NSString *)identifier +{ + return self.skuId; +} + @end diff --git a/Source/GYTransaction.m b/Source/GYTransaction.m index 0779764..d1aee6a 100644 --- a/Source/GYTransaction.m +++ b/Source/GYTransaction.m @@ -32,9 +32,22 @@ + (instancetype)transactionWithPaymentTransaction:(SKPaymentTransaction*)t @implementation GYTransaction -- (NSString *)productIdentifier +- (NSString *)productId { return self.paymentTransaction.payment.productIdentifier; } +- (NSString *)promotionalId +{ + return self.paymentTransaction.payment.paymentDiscount.identifier; +} + + +#pragma mark - Deprecations + +- (NSString *)productIdentifier +{ + return self.productId; +} + @end diff --git a/Source/Glassfy.m b/Source/Glassfy.m index 687044a..fb6458e 100644 --- a/Source/Glassfy.m +++ b/Source/Glassfy.m @@ -40,7 +40,7 @@ + (Glassfy *)shared + (NSString *)sdkVersion { - return @"1.1.7"; + return @"1.1.8"; } + (void)initializeWithAPIKey:(NSString *)apiKey @@ -83,10 +83,17 @@ + (void)offeringsWithCompletion:(GYOfferingsCompletion)block }); } -+ (void)skuWithIdentifier:(NSString *)skuid completion:(GYSkuBlock)block ++ (void)skuWithId:(NSString *)skuid completion:(GYSkuBlock)block { dispatch_async(Glassfy.shared.glqueue, ^{ - [Glassfy.shared.manager skuWithIdentifier:skuid completion:block]; + [Glassfy.shared.manager skuWithId:skuid completion:block]; + }); +} + ++ (void)skuWithProductId:(NSString *)productid promotionalId:(NSString *)promoid completion:(GYSkuBlock)block +{ + dispatch_async(Glassfy.shared.glqueue, ^{ + [Glassfy.shared.manager skuWithProductId:productid promotionalId:promoid completion:block]; }); } @@ -146,4 +153,19 @@ + (void)setLogLevel:(GYLogLevel)level }); } ++ (void)setPurchaseDelegate:(id)delegate +{ + dispatch_async(Glassfy.shared.glqueue, ^{ + [Glassfy.shared.manager setPurchaseDelegate:delegate]; + }); +} + + +#pragma mark - Deprecations + ++ (void)skuWithIdentifier:(NSString *)skuid completion:(GYSkuBlock)block +{ + return [self skuWithId:skuid completion:block]; +} + @end diff --git a/Source/Public/GYOffering.h b/Source/Public/GYOffering.h index e599de5..aa57d32 100644 --- a/Source/Public/GYOffering.h +++ b/Source/Public/GYOffering.h @@ -12,9 +12,13 @@ NS_ASSUME_NONNULL_BEGIN NS_SWIFT_NAME(Glassfy.Offering) @interface GYOffering : NSObject -//@property(nullable, readonly, strong) NSString *name; -@property(readonly, strong) NSString *identifier; +@property(readonly, strong) NSString *offeringId; @property(readonly, strong) NSArray *skus; + + +/// Deprecations +@property(nonatomic, readonly) NSString *identifier __attribute__((deprecated("Renamed to offeringId"))); + @end NS_ASSUME_NONNULL_END diff --git a/Source/Public/GYOfferings.h b/Source/Public/GYOfferings.h index 9016fd2..31e3f57 100644 --- a/Source/Public/GYOfferings.h +++ b/Source/Public/GYOfferings.h @@ -15,7 +15,7 @@ NS_SWIFT_NAME(Glassfy.Offerings) @property(nonatomic, readonly) NSArray *all; // Custom Keyed Subscripting method -- (nullable GYOffering *)objectForKeyedSubscript:(NSString *)identifier; +- (nullable GYOffering *)objectForKeyedSubscript:(NSString *)offeringid; @end NS_ASSUME_NONNULL_END diff --git a/Source/Public/GYPermission.h b/Source/Public/GYPermission.h index 0f3260b..ca9aac9 100644 --- a/Source/Public/GYPermission.h +++ b/Source/Public/GYPermission.h @@ -16,11 +16,15 @@ NS_ASSUME_NONNULL_BEGIN NS_SWIFT_NAME(Glassfy.Permission) @interface GYPermission : NSObject -@property(nonatomic, readonly, strong) NSString *permissionIdentifier; +@property(nonatomic, readonly, strong) NSString *permissionId; @property(nonatomic, readonly, assign) GYEntitlement entitlement; @property(nonatomic, readonly, assign) BOOL isValid; @property(nonatomic, readonly, strong, nullable) NSDate *expireDate; @property(nonatomic, readonly, strong) NSSet *accountableSkus; + + +/// Deprecations +@property(nonatomic, readonly) NSString *permissionIdentifier __attribute__((deprecated("Renamed to permissionId"))); @end NS_ASSUME_NONNULL_END diff --git a/Source/Public/GYPermissions.h b/Source/Public/GYPermissions.h index afb0f21..a54e710 100644 --- a/Source/Public/GYPermissions.h +++ b/Source/Public/GYPermissions.h @@ -21,7 +21,7 @@ NS_SWIFT_NAME(Glassfy.Permissions) @property(nullable, nonatomic, readonly) NSString *installationId; // Custom Keyed Subscripting method -- (nullable GYPermission *)objectForKeyedSubscript:(NSString *)identifier; +- (nullable GYPermission *)objectForKeyedSubscript:(NSString *)permissionid; @end NS_ASSUME_NONNULL_END diff --git a/Source/Public/GYPurchaseDelegate.h b/Source/Public/GYPurchaseDelegate.h new file mode 100644 index 0000000..d73ebed --- /dev/null +++ b/Source/Public/GYPurchaseDelegate.h @@ -0,0 +1,28 @@ +// +// GYPurchaseDelegate.h +// Glassfy +// +// Created by Luca Garbolino on 21/02/22. +// + +#import +#if __has_include() +#import +#else +#import "GYTypes.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +NS_SWIFT_NAME(Glassfy.PurchaseDelegate) +@protocol GYPurchaseDelegate +@optional +- (void)handlePromotedProductId:(NSString *)productid + withPromotionalId:(NSString *_Nullable)promoid + purchaseHandler:(void (^)(GYPaymentTransactionBlock _Nullable))purchase NS_SWIFT_NAME(handlePromoted(productId:promotionalId:purchaseHandler:)); + +- (void)didPurchaseProduct:(GYTransaction *)transaction NS_SWIFT_NAME(didPurchaseProduct(transaction:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Source/Public/GYSku.h b/Source/Public/GYSku.h index aad77a6..fc89a2e 100644 --- a/Source/Public/GYSku.h +++ b/Source/Public/GYSku.h @@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN NS_SWIFT_NAME(Glassfy.Sku) @interface GYSku : NSObject -@property(nonatomic, readonly) NSString *identifier; +@property(nonatomic, readonly) NSString *skuId; @property(nonatomic, readonly) NSString *productId; @property(nonatomic, readonly) GYSkuEligibility introductoryEligibility; @property(nonatomic, readonly) GYSkuEligibility promotionalEligibility; @@ -26,6 +26,10 @@ NS_SWIFT_NAME(Glassfy.Sku) @property(nonatomic, readonly) SKProduct *product; @property(nonatomic, nullable, readonly) SKProductDiscount *discount API_AVAILABLE(ios(12.2), macos(10.14.4), watchos(6.2)); + + +/// Deprecations +@property(nonatomic, readonly) NSString *identifier __attribute__((deprecated("Renamed to skuId:"))); @end NS_ASSUME_NONNULL_END diff --git a/Source/Public/GYTransaction.h b/Source/Public/GYTransaction.h index 6e0fbad..12b5b26 100644 --- a/Source/Public/GYTransaction.h +++ b/Source/Public/GYTransaction.h @@ -13,10 +13,17 @@ NS_ASSUME_NONNULL_BEGIN NS_SWIFT_NAME(Glassfy.Transaction) @interface GYTransaction : NSObject -@property(nonatomic, readonly) SKPaymentTransaction *paymentTransaction; -@property(nonatomic, readonly) NSString *productIdentifier; @property(nonatomic, readonly) BOOL receiptValidated; @property(nonatomic, readonly) GYPermissions *permissions; + +@property(nonatomic, readonly) NSString *productId; +@property(nonatomic, readonly, nullable) NSString *promotionalId API_AVAILABLE(ios(12.2), macos(10.14.4), watchos(6.2)); + +@property(nonatomic, readonly) SKPaymentTransaction *paymentTransaction; + + +/// Deprecations +@property(nonatomic, readonly) NSString *productIdentifier __attribute__((deprecated("Renamed to productId:"))); @end NS_ASSUME_NONNULL_END diff --git a/Source/Public/GYTypes.h b/Source/Public/GYTypes.h index 7bf33f4..7a1f168 100644 --- a/Source/Public/GYTypes.h +++ b/Source/Public/GYTypes.h @@ -26,10 +26,10 @@ typedef void(^GYBooleanCompletion)(BOOL, NSError* _Nullable) NS_SWIFT_NAME(Glass typedef void(^GYErrorCompletion)(NSError* _Nullable) NS_SWIFT_NAME(Glassfy.ErrorCompletion); typedef void(^GYUserPropertiesCompletion)(GYUserProperties* _Nullable, NSError* _Nullable) NS_SWIFT_NAME(Glassfy.UserPropertiesCompletion); -typedef NS_ENUM(NSUInteger, GYSkuEligibility) { - GYSkuEligibilityEligible, - GYSkuEligibilityNonEligible, - GYSkuEligibilityUnknown +typedef NS_ENUM(NSInteger, GYSkuEligibility) { + GYSkuEligibilityEligible = 1, + GYSkuEligibilityNonEligible = -1, + GYSkuEligibilityUnknown = 0 } NS_SWIFT_NAME(Glassfy.SkuEligibility); typedef NS_ENUM(NSInteger, GYEntitlement) { diff --git a/Source/Public/Glassfy.h b/Source/Public/Glassfy.h index 1e28cdb..d0f9255 100644 --- a/Source/Public/Glassfy.h +++ b/Source/Public/Glassfy.h @@ -19,6 +19,7 @@ #import #import +#import #else #import "GYSku.h" #import "GYOffering.h" @@ -30,6 +31,7 @@ #import "GYTypes.h" #import "GYError.h" +#import "GYPurchaseDelegate.h" #endif @@ -108,7 +110,18 @@ NS_ASSUME_NONNULL_BEGIN @param skuid Sku's identifier @param block Completion block with result */ -+ (void)skuWithIdentifier:(NSString *)skuid completion:(GYSkuBlock)block NS_SWIFT_NAME(sku(identifier:completion:)); ++ (void)skuWithId:(NSString *)skuid completion:(GYSkuBlock)block NS_SWIFT_NAME(sku(id:completion:)); + +/** + Fetch Sku + + @note For more details, check the documentation https://docs.glassfy.io/dashboard/configure-products + + @param productid SKProduct product identifier + @param promoid Promotional Identifier + @param block Completion block with result + */ ++ (void)skuWithProductId:(NSString *)productid promotionalId:(NSString *_Nullable)promoid completion:(GYSkuBlock)block NS_SWIFT_NAME(sku(productId:promotionalId:completion:)); /** Make a purchase @@ -174,6 +187,16 @@ Save extra user properties */ + (void)getUserProperties:(GYUserPropertiesCompletion)block NS_SWIFT_NAME(userProperties(completion:)); +/** + Set purchase delegate + + @param delegate implementing GYPurchaseDelegate protocol + */ ++ (void)setPurchaseDelegate:(id _Nullable)delegate; + + +/// Deprecations ++ (void)skuWithIdentifier:(NSString *)skuid completion:(GYSkuBlock)block NS_SWIFT_NAME(sku(identifier:completion:)) __attribute__((deprecated("Renamed to +skuWithId:completion:"))); @end NS_ASSUME_NONNULL_END