diff --git a/Glassfy.podspec b/Glassfy.podspec index b705f94..1238927 100644 --- a/Glassfy.podspec +++ b/Glassfy.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Glassfy" - s.version = "1.3.4" + s.version = "1.4.0-beta.0" 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 56004ca..b0a1f41 100644 --- a/Glassfy.xcodeproj/project.pbxproj +++ b/Glassfy.xcodeproj/project.pbxproj @@ -64,8 +64,6 @@ 817A1D00258CF7EE00D1BA10 /* GYStoreRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 817A1CFE258CF7EE00D1BA10 /* GYStoreRequest.m */; }; 817C95692678F79200DB4945 /* GYAPISkuResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 817C95682678F78400DB4945 /* GYAPISkuResponse.h */; settings = {ATTRIBUTES = (Private, ); }; }; 817C956B2678F7D300DB4945 /* GYAPISkuResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 817C956A2678F7D300DB4945 /* GYAPISkuResponse.m */; }; - 818880B52717153A00128A10 /* GYAPIPaywallResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 818880B32717153A00128A10 /* GYAPIPaywallResponse.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 818880B62717153A00128A10 /* GYAPIPaywallResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 818880B42717153A00128A10 /* GYAPIPaywallResponse.m */; }; 818880BA27171D7A00128A10 /* GYPaywallViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 818880B827171D7A00128A10 /* GYPaywallViewController.m */; }; 818880BC27171DA900128A10 /* GYPaywallViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 818880BB27171DA900128A10 /* GYPaywallViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 818880BE27171E1F00128A10 /* GYPaywallViewController+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 818880BD27171E1F00128A10 /* GYPaywallViewController+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -100,10 +98,16 @@ 81D8D49A258B7193006BFE51 /* Glassfy.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8168309F258B6D9C00565968 /* Glassfy.framework */; }; 81E1DC3225933FC7003B5EBD /* SKPayment+GYEncode.h in Headers */ = {isa = PBXBuildFile; fileRef = 81E1DC3025933FC7003B5EBD /* SKPayment+GYEncode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 81E1DC3325933FC7003B5EBD /* SKPayment+GYEncode.m in Sources */ = {isa = PBXBuildFile; fileRef = 81E1DC3125933FC7003B5EBD /* SKPayment+GYEncode.m */; }; + 81E2BCD32869A58D0022AAEB /* GYPaywall.m in Sources */ = {isa = PBXBuildFile; fileRef = 81E2BCD12869A58D0022AAEB /* GYPaywall.m */; }; + 81E2BCD62869AB070022AAEB /* GYAPIPaywallResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 81E2BCD42869AB070022AAEB /* GYAPIPaywallResponse.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 81E2BCD72869AB070022AAEB /* GYAPIPaywallResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 81E2BCD52869AB070022AAEB /* GYAPIPaywallResponse.m */; }; + 81E2BCD92869AB890022AAEB /* GYPaywall.h in Headers */ = {isa = PBXBuildFile; fileRef = 81E2BCD82869AB890022AAEB /* GYPaywall.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 81E2BCDB2869ABCB0022AAEB /* GYPaywall+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 81E2BCDA2869ABBD0022AAEB /* GYPaywall+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 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, ); }; }; + 81FE06302907D64400FA5C16 /* GYInternalType.h in Headers */ = {isa = PBXBuildFile; fileRef = 81FE062F2907D63600FA5C16 /* GYInternalType.h */; settings = {ATTRIBUTES = (Private, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -173,8 +177,6 @@ 817A1CFE258CF7EE00D1BA10 /* GYStoreRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GYStoreRequest.m; sourceTree = ""; }; 817C95682678F78400DB4945 /* GYAPISkuResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GYAPISkuResponse.h; sourceTree = ""; }; 817C956A2678F7D300DB4945 /* GYAPISkuResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GYAPISkuResponse.m; sourceTree = ""; }; - 818880B32717153A00128A10 /* GYAPIPaywallResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GYAPIPaywallResponse.h; sourceTree = ""; }; - 818880B42717153A00128A10 /* GYAPIPaywallResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GYAPIPaywallResponse.m; sourceTree = ""; }; 818880B827171D7A00128A10 /* GYPaywallViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GYPaywallViewController.m; sourceTree = ""; }; 818880BB27171DA900128A10 /* GYPaywallViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GYPaywallViewController.h; path = Public/GYPaywallViewController.h; sourceTree = ""; }; 818880BD27171E1F00128A10 /* GYPaywallViewController+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GYPaywallViewController+Private.h"; sourceTree = ""; }; @@ -213,11 +215,17 @@ 81D8D499258B7193006BFE51 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 81E1DC3025933FC7003B5EBD /* SKPayment+GYEncode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SKPayment+GYEncode.h"; sourceTree = ""; }; 81E1DC3125933FC7003B5EBD /* SKPayment+GYEncode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SKPayment+GYEncode.m"; sourceTree = ""; }; + 81E2BCD12869A58D0022AAEB /* GYPaywall.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GYPaywall.m; sourceTree = ""; }; + 81E2BCD42869AB070022AAEB /* GYAPIPaywallResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GYAPIPaywallResponse.h; sourceTree = ""; }; + 81E2BCD52869AB070022AAEB /* GYAPIPaywallResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GYAPIPaywallResponse.m; sourceTree = ""; }; + 81E2BCD82869AB890022AAEB /* GYPaywall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GYPaywall.h; path = Public/GYPaywall.h; sourceTree = ""; }; + 81E2BCDA2869ABBD0022AAEB /* GYPaywall+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GYPaywall+Private.h"; sourceTree = ""; }; 81EFB54225A772D900706FCB /* GYAPIPermissionsResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GYAPIPermissionsResponse.h; sourceTree = ""; }; 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 = ""; }; + 81FE062F2907D63600FA5C16 /* GYInternalType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GYInternalType.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -252,8 +260,8 @@ 81EFB54325A772D900706FCB /* GYAPIPermissionsResponse.m */, 81C684632602633500223D3E /* GYAPISignatureResponse.h */, 81C684642602633500223D3E /* GYAPISignatureResponse.m */, - 818880B32717153A00128A10 /* GYAPIPaywallResponse.h */, - 818880B42717153A00128A10 /* GYAPIPaywallResponse.m */, + 81E2BCD42869AB070022AAEB /* GYAPIPaywallResponse.h */, + 81E2BCD52869AB070022AAEB /* GYAPIPaywallResponse.m */, 816EF28B26611C5900513FB1 /* GYAPIPropertiesResponse.h */, 816EF28C26611C5900513FB1 /* GYAPIPropertiesResponse.m */, 817C95682678F78400DB4945 /* GYAPISkuResponse.h */, @@ -328,6 +336,8 @@ 81EFB54925A772F200706FCB /* GYPermission.m */, 8191E86A26690C850077BDD7 /* GYUserProperties.h */, 816EF2882661161200513FB1 /* GYUserProperties.m */, + 81E2BCD82869AB890022AAEB /* GYPaywall.h */, + 81E2BCD12869A58D0022AAEB /* GYPaywall.m */, 818880BB27171DA900128A10 /* GYPaywallViewController.h */, 818880B827171D7A00128A10 /* GYPaywallViewController.m */, 81C9AF5D2805BB82004A36A1 /* GYStoresInfo.h */, @@ -357,6 +367,7 @@ 817A1CF4258CF63600D1BA10 /* GYAPIManager.m */, 817A1CFD258CF7EE00D1BA10 /* GYStoreRequest.h */, 817A1CFE258CF7EE00D1BA10 /* GYStoreRequest.m */, + 81FE062F2907D63600FA5C16 /* GYInternalType.h */, 818880BD27171E1F00128A10 /* GYPaywallViewController+Private.h */, 811F322D2631CC6C00777020 /* Glassfy+Private.h */, 81A7064425ACADB200169564 /* GYSku+Private.h */, @@ -370,6 +381,7 @@ 816EF28F26611CF100513FB1 /* GYUserProperties+Private.h */, 81C9AF672805D2F3004A36A1 /* GYStoresInfo+Private.h */, 81C9AF542805BA8A004A36A1 /* GYStoreInfo+Private.h */, + 81E2BCDA2869ABBD0022AAEB /* GYPaywall+Private.h */, 8166503F28DB689200E5B985 /* GYAccountableSku+Private.h */, ); name = Core; @@ -435,10 +447,11 @@ 818880BC27171DA900128A10 /* GYPaywallViewController.h in Headers */, 8138BA9B25924C8F005CB44E /* SKProductDiscount+GYEncode.h in Headers */, 81C684652602633500223D3E /* GYAPISignatureResponse.h in Headers */, + 81FE06302907D64400FA5C16 /* GYInternalType.h in Headers */, 811F31B726317ECD00777020 /* GYPermission+Private.h in Headers */, 81C9AF682805D2F3004A36A1 /* GYStoresInfo+Private.h in Headers */, 811F31A826317EBB00777020 /* GYOfferings+Private.h in Headers */, - 818880B52717153A00128A10 /* GYAPIPaywallResponse.h in Headers */, + 81E2BCDB2869ABCB0022AAEB /* GYPaywall+Private.h in Headers */, 81B49B552729A31C000BDDA1 /* GYFormatter.h in Headers */, 811F31BC26317ED300777020 /* GYTransaction+Private.h in Headers */, 816EF29026611CF700513FB1 /* GYUserProperties+Private.h in Headers */, @@ -450,6 +463,7 @@ 8179459026565E32000EAA47 /* GYUtils.h in Headers */, 811F322E2631CC6C00777020 /* Glassfy+Private.h in Headers */, 81951CD626443F94003901F1 /* GYOffering.h in Headers */, + 81E2BCD92869AB890022AAEB /* GYPaywall.h in Headers */, 8166504228DB6B2700E5B985 /* GYAccountableSku.h in Headers */, 811F31C126317ED800777020 /* GYSku+Private.h in Headers */, 81EFB54425A772D900706FCB /* GYAPIPermissionsResponse.h in Headers */, @@ -458,6 +472,7 @@ 817C95692678F79200DB4945 /* GYAPISkuResponse.h in Headers */, 811DB3982809675D00021880 /* GYStoreInfo+Private.h in Headers */, 8104537725909F320015A728 /* GYAPIInitResponse.h in Headers */, + 81E2BCD62869AB070022AAEB /* GYAPIPaywallResponse.h in Headers */, 81C9AF522805B665004A36A1 /* GYAPIStoreInfoResponse.h in Headers */, 8166504028DB6AD100E5B985 /* GYAccountableSku+Private.h in Headers */, 8138BAA825924CDF005CB44E /* SKPaymentDiscount+GYEncode.h in Headers */, @@ -601,9 +616,9 @@ 817A1D00258CF7EE00D1BA10 /* GYStoreRequest.m in Sources */, 8166503E28DB671200E5B985 /* GYAccountableSku.m in Sources */, 818880BA27171D7A00128A10 /* GYPaywallViewController.m in Sources */, - 818880B62717153A00128A10 /* GYAPIPaywallResponse.m in Sources */, 817A1CF6258CF63600D1BA10 /* GYAPIManager.m in Sources */, 81EFB54525A772D900706FCB /* GYAPIPermissionsResponse.m in Sources */, + 81E2BCD72869AB070022AAEB /* GYAPIPaywallResponse.m in Sources */, 8138BAA925924CDF005CB44E /* SKPaymentDiscount+GYEncode.m in Sources */, 816EF28A2661161200513FB1 /* GYUserProperties.m in Sources */, 8138BAB325924D0A005CB44E /* SKProductSubscriptionPeriod+GYEncode.m in Sources */, @@ -611,6 +626,7 @@ 81B49B562729A31C000BDDA1 /* GYFormatter.m in Sources */, 816EF28E26611C5900513FB1 /* GYAPIPropertiesResponse.m in Sources */, 81EFB54B25A772F200706FCB /* GYPermission.m in Sources */, + 81E2BCD32869A58D0022AAEB /* GYPaywall.m in Sources */, 81010F2A2590C1AB00B07DE4 /* GYAPIOfferingsResponse.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -777,7 +793,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.3.4; + MARKETING_VERSION = 1.4.0-beta.0; PRODUCT_BUNDLE_IDENTIFIER = net.glassfy.sdk; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -805,7 +821,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.3.4; + MARKETING_VERSION = 1.4.0-beta.0; PRODUCT_BUNDLE_IDENTIFIER = net.glassfy.sdk; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/README.md b/README.md index 85157c8..f98e2ca 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.3.4'``` +```pod 'Glassfy', '~> 1.4.0-beta.0'``` Then, run the following command: diff --git a/Source/GYAPIManager.m b/Source/GYAPIManager.m index 47f077b..a6288ac 100644 --- a/Source/GYAPIManager.m +++ b/Source/GYAPIManager.m @@ -449,6 +449,7 @@ - (void)getPaywall:(NSString *)paywallId locale:(NSString *)locale completion:(G [self callApiWithRequest:req response:GYAPIPaywallResponse.class completion:block]; } + #pragma mark - private - (NSMutableURLRequest *_Nullable)authorizedRequestWithComponents:(NSURLComponents *)urlComponents diff --git a/Source/GYAPIPaywallResponse.h b/Source/GYAPIPaywallResponse.h index e87d1f3..5c0e0cc 100644 --- a/Source/GYAPIPaywallResponse.h +++ b/Source/GYAPIPaywallResponse.h @@ -2,17 +2,23 @@ // GYAPIPaywallResponse.h // Glassfy // -// Created by Luca Garbolino on 13/10/21. +// Created by Luca Garbolino on 27/06/22. // #import #import "GYAPIBaseResponse.h" +#import "GYInternalType.h" @class GYSku; NS_ASSUME_NONNULL_BEGIN -@interface GYAPIPaywallResponse: GYAPIBaseResponse -@property(nonatomic, strong) NSString *content; +@interface GYAPIPaywallResponse : GYAPIBaseResponse + +@property(nullable, nonatomic, strong) NSString *content; +@property(nullable, nonatomic, strong) NSString *contentUrl; + +@property(nullable, nonatomic, strong) NSString *version; +@property(nonatomic, assign) GYPaywallType type; @property(nullable, nonatomic, strong) NSString *locale; @property(nullable, nonatomic, strong) NSString *pwid; @property(nonatomic, strong) NSArray *skus; diff --git a/Source/GYAPIPaywallResponse.m b/Source/GYAPIPaywallResponse.m index dddeab5..bf6ab8c 100644 --- a/Source/GYAPIPaywallResponse.m +++ b/Source/GYAPIPaywallResponse.m @@ -2,15 +2,18 @@ // GYAPIPaywallResponse.m // Glassfy // -// Created by Luca Garbolino on 13/10/21. +// Created by Luca Garbolino on 27/06/22. // #import "GYAPIPaywallResponse.h" -#import "GYAPIBaseResponse.h" -#import "GYError.h" #import "GYSku+Private.h" +#import "GYError.h" + +#define PAYWALL_TYPE_HTML @"html" +#define PAYWALL_TYPE_NOCODE @"nocode" @implementation GYAPIPaywallResponse + - (instancetype _Nullable)initWithObject:(NSDictionary *)obj error:(NSError **)error { self = [super initWithObject:obj error:error]; @@ -21,6 +24,27 @@ - (instancetype _Nullable)initWithObject:(NSDictionary *)obj error:(NSError **)e if (self) { NSDictionary *paywall = obj[@"paywall"]; if ([paywall isKindOfClass:NSDictionary.class]) { + + NSString *version = paywall[@"version"]; + if ([version isKindOfClass:NSString.class]) { + self.version = version; + } + + GYPaywallType type = GYPaywallTypeNoCode; + NSString *typeStr = paywall[@"type"]; + if ([typeStr isKindOfClass:NSString.class]) { + if ([PAYWALL_TYPE_HTML isEqualToString:typeStr]) { + type = GYPaywallTypeHTML; + } else if ([PAYWALL_TYPE_NOCODE isEqualToString:typeStr]) { + type = GYPaywallTypeNoCode; + } + } + self.type = type; + + NSString *contentUrl = paywall[@"url"]; + if ([contentUrl isKindOfClass:NSString.class]) { + self.contentUrl = contentUrl; + } NSString *content = paywall[@"content"]; if ([content isKindOfClass:NSString.class]) { self.content = content; @@ -56,10 +80,14 @@ - (instancetype _Nullable)initWithObject:(NSDictionary *)obj error:(NSError **)e // verify - if (!self.content) { - *error = [GYError serverError:GYErrorCodeUnknow description:@"Unexpected data format"]; + if (!self.contentUrl && !self.content) { + if (error) { + *error = [GYError serverError:GYErrorCodeUnknow description:@"Unexpected data format"]; + } } } return self; + } + @end diff --git a/Source/GYInternalType.h b/Source/GYInternalType.h new file mode 100644 index 0000000..218876c --- /dev/null +++ b/Source/GYInternalType.h @@ -0,0 +1,27 @@ +// +// GYInternalType.h +// Glassfy +// +// Created by Luca Garbolino on 25/10/22. +// + +#ifndef GYInternalType_h +#define GYInternalType_h + +typedef NS_ENUM(NSUInteger, GYPaywallType) { + GYPaywallTypeNoCode, + GYPaywallTypeHTML +}; + +typedef NS_ENUM(NSUInteger, GYSubplatform) { + GYSubplatformUnknown = 0, + GYSubplatformiOS = 1, + GYSubplatformCatalyst = 2, + GYSubplatformTV = 3, + GYSubplatformWatch = 4, + GYSubplatformOSx = 5, + GYSubplatformDrive = 6, + GYSubplatformSimulator = 7 +}; + +#endif /* GYInternalType_h */ diff --git a/Source/GYManager.h b/Source/GYManager.h index c80067a..bd5edb4 100644 --- a/Source/GYManager.h +++ b/Source/GYManager.h @@ -36,13 +36,13 @@ NS_ASSUME_NONNULL_BEGIN - (void)setEmailUserProperty:(NSString *)email completion:(GYErrorCompletion)block; - (void)setDeviceToken:(NSString *)deviceToken completion:(GYErrorCompletion)block; - (void)setExtraUserProperty:(NSDictionary *)extra completion:(GYErrorCompletion)block; - - (void)getUserProperties:(GYUserPropertiesCompletion)block; - (void)connectPaddleLicenseKey:(NSString *)licenseKey force:(BOOL)force completion:(GYErrorCompletion)block; - (void)connectCustomSubscriber:(NSString *_Nullable)customId completion:(GYErrorCompletion)block; - (void)getPaywall:(NSString *)paywallId completion:(GYPaywallCompletion)block API_UNAVAILABLE(macos, watchos); +- (void)getPaywall:(NSString *)paywallid preload:(BOOL)preload completion:(GYPaywallCompletion)block API_UNAVAILABLE(macos, watchos); - (void)restorePurchasesWithCompletion:(GYPermissionsCompletion)block; diff --git a/Source/GYManager.m b/Source/GYManager.m index c79c307..ef87feb 100644 --- a/Source/GYManager.m +++ b/Source/GYManager.m @@ -25,6 +25,7 @@ #import "GYPaywallViewController+Private.h" #import "GYStoresInfo+Private.h" #import "Glassfy+Private.h" +#import "GYPaywall+Private.h" #import "GYSysInfo.h" @interface GYManager() @@ -349,32 +350,63 @@ - (void)getUserProperties:(GYUserPropertiesCompletion)block - (void)getPaywall:(NSString *)paywallId completion:(GYPaywallCompletion)block { + [self getPaywall:paywallId preload:YES completion:block]; +} + +- (void)getPaywall:(NSString *)paywallId preload:(BOOL)preload completion:(GYPaywallCompletion)block +{ +#if TARGET_OS_IPHONE NSString *lang = [[[NSBundle mainBundle] preferredLocalizations] firstObject]; [self.api getPaywall:paywallId locale:lang completion:^(GYAPIPaywallResponse *res, NSError *paywallErr) { - [self.store productWithSkus:res.skus completion:^(NSArray *products, NSError *storeErr) { - res.skus = [GYSku matchSkus:res.skus withProducts:products ?: @[]]; + GYPaywall *paywall; + + // Create the dispatch group + dispatch_group_t serviceGroup = dispatch_group_create(); + + // Define errors to be processed when everything is complete. + // One error per service + __block NSError *loadError = nil; + __block NSError *storeError = nil; + if (!paywallErr) { + paywall = [GYPaywall paywallWithResponse:res]; + if (preload) { + // Start loading from paywall contentURL + dispatch_group_enter(serviceGroup); + [paywall loadPaywallViewController:^(GYPaywallViewController *p, NSError *err) { + loadError = err; + dispatch_group_leave(serviceGroup); + }]; + } - typeof(block) __strong completion = block; - if (completion) { - dispatch_async(dispatch_get_main_queue(), ^{ -#if TARGET_OS_IPHONE - - NSError *err = paywallErr ?: storeErr; - GYPaywallViewController *vc = nil; - if (!err) { - vc = [GYPaywallViewController paywallWithResponse:res]; - } - - err ? completion(nil, err) : completion(vc, nil); -#else - completion(nil, GYError.notSupported); -#endif - }); + // Start sku request with appstore + dispatch_group_enter(serviceGroup); + [self.store productWithSkus:res.skus completion:^(NSArray *products, NSError *storeErr) { + storeError = storeErr; + if (!storeErr && (res.skus.count != products.count)) { + storeError = GYError.storeProductNotFound; + } + res.skus = [GYSku matchSkus:res.skus withProducts:products ?: @[]]; + dispatch_group_leave(serviceGroup); + }]; + } + + dispatch_group_notify(serviceGroup, dispatch_get_main_queue(), ^{ + NSError *overallError = paywallErr ?: (loadError ?: storeError); + if (overallError) { + block(nil, overallError); + return; } - }]; + block(paywall, nil); + }); }]; +#else + dispatch_async(dispatch_get_main_queue(), ^{ + block(nil, GYError.notSupported); + }); +#endif } + - (void)connectPaddleLicenseKey:(NSString *)licenseKey force:(BOOL)force completion:(GYErrorCompletion)block { [self.api postConnectPaddleLicenseKey:licenseKey force:force completion:^(GYAPIBaseResponse *res, NSError *err) { diff --git a/Source/GYPaywall+Private.h b/Source/GYPaywall+Private.h new file mode 100644 index 0000000..1993650 --- /dev/null +++ b/Source/GYPaywall+Private.h @@ -0,0 +1,32 @@ +// +// GYPaywall+Private.h +// Glassfy +// +// Created by Luca Garbolino on 27/06/22. +// + +#import "GYPaywall.h" +#import "GYInternalType.h" +@class GYAPIPaywallResponse; +@class GYSku; + +NS_ASSUME_NONNULL_BEGIN + +@interface GYPaywall (Private) + ++ (instancetype)paywallWithResponse:(GYAPIPaywallResponse *)res; + +@property(nullable, nonatomic, strong) NSURL *contentUrl; +@property(nullable, nonatomic, strong) NSString *version; +@property(nullable, nonatomic, strong) NSString *pwid; +@property(nullable, nonatomic, strong) NSLocale *locale; +@property(nullable, nonatomic, strong) NSArray *skus; +@property(nullable, nonatomic, strong) NSString *content; +@property(nonatomic, assign) GYPaywallType type; + +@property(nonatomic, assign) BOOL isLoading; +@property(nonatomic, assign) BOOL isLoaded; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Source/GYPaywall.m b/Source/GYPaywall.m new file mode 100644 index 0000000..ca8feb4 --- /dev/null +++ b/Source/GYPaywall.m @@ -0,0 +1,96 @@ +// +// GYPaywall.m +// Glassfy +// +// Created by Luca Garbolino on 27/06/22. +// + +#import "GYPaywall+Private.h" +#import "GYSku.h" +#import "Glassfy+Private.h" +#import "GYAPIPaywallResponse.h" +#import "GYPaywallViewController+Private.h" + +@interface GYPaywall() +@property(nonatomic, strong) NSURL *contentUrl; +@property(nonatomic, strong) NSString *version; +@property(nonatomic, strong) NSString *pwid; +@property(nonatomic, strong) NSLocale *locale; +@property(nonatomic, strong) NSArray *skus; +@property(nonatomic, strong) NSString *content; +@property(nonatomic, assign) GYPaywallType type; + +@property(nonatomic, assign) BOOL isLoading; +@property(nonatomic, assign) BOOL isLoaded; + +@end + +@implementation GYPaywall (Private) + ++ (instancetype)paywallWithResponse:(GYAPIPaywallResponse *)res +{ + GYPaywall *p = [self new]; + + p.content = res.content; + p.contentUrl = [NSURL URLWithString:res.contentUrl]; + + p.skus = res.skus; + p.pwid = res.pwid; + p.locale = [NSLocale localeWithLocaleIdentifier:res.locale ?: @"en-US"]; + + p.type = res.type; + p.version = res.version; + + return p; +} + +@end + +@implementation GYPaywall + +#if TARGET_OS_IPHONE +- (void)loadPaywallViewController:(void(^)(GYPaywallViewController *_Nullable, NSError *_Nullable))completion +{ + [self startLoading:^(NSError *err) { + GYPaywallViewController *vc = nil; + if (!err) { + vc = [GYPaywallViewController paywallViewController:self]; + } + + completion(vc, err); + }]; +} + +- (GYPaywallViewController *)paywallViewController +{ + return [GYPaywallViewController paywallViewController:self]; +} +#endif + +- (void)startLoading:(void(^_Nonnull)(NSError *))completion +{ + dispatch_async(Glassfy.shared.glqueue, ^{ + if (self.content || self.isLoaded || self.isLoading) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(nil); + }); + return; + } + + self.isLoading = YES; + + NSError *err = nil; + self.content = [NSString stringWithContentsOfURL:self.contentUrl encoding:NSUTF8StringEncoding error:&err]; + + self.isLoading = NO; + + if (!err) { + self.isLoaded = YES; + } + dispatch_async(dispatch_get_main_queue(), ^{ + completion(err); + }); + }); +} + +@end diff --git a/Source/GYPaywallViewController+Private.h b/Source/GYPaywallViewController+Private.h index 5ad9052..49a9de1 100644 --- a/Source/GYPaywallViewController+Private.h +++ b/Source/GYPaywallViewController+Private.h @@ -14,7 +14,9 @@ API_UNAVAILABLE_BEGIN(macos, watchos) NS_ASSUME_NONNULL_BEGIN @interface GYPaywallViewController (Private) -+ (instancetype)paywallWithResponse:(GYAPIPaywallResponse *)res; + ++ (instancetype)paywallViewController:(GYPaywall*)paywall; + @end NS_ASSUME_NONNULL_END diff --git a/Source/GYPaywallViewController.m b/Source/GYPaywallViewController.m index c6be658..bfe3e7e 100644 --- a/Source/GYPaywallViewController.m +++ b/Source/GYPaywallViewController.m @@ -14,14 +14,23 @@ #import "GYSku+Private.h" #import "SKProduct+GYEncode.h" #import "GYFormatter.h" +#import "GYPaywall+Private.h" +#import "GYSysInfo.h" #if TARGET_OS_IPHONE -@interface GYPaywallViewController () +#define kMessageHandlerName @"GYMessageHandler" + +@interface GYPaywallViewController() //, WKUIDelegate> @property(nonatomic, strong) NSString *content; +@property(nonatomic, strong, nullable) NSURL *url; @property(nonatomic, strong) NSString *pwid; @property(nonatomic, strong) NSLocale *locale; @property(nonatomic, strong) NSArray *skus; +@property(nonatomic, strong) NSString *version; +@property(nonatomic, assign) GYPaywallType paywallType; + +@property(nonatomic, strong) GYPaywall *paywall; @property(nonatomic, weak) UIView *activityView; @property(nonatomic, unsafe_unretained) WKWebView *webview; @@ -34,13 +43,34 @@ @interface GYPaywallViewController () *priceCorrections = [NSMutableArray array]; + for (GYSku *s in self.skus) { + SKProduct *p = s.product; + + NSMutableDictionary *msg = [NSMutableDictionary new]; + msg[@"TITLE"] = p.localizedTitle; + msg[@"DESCRIPTION"] = p.localizedDescription; + msg[@"ORIGINAL_PRICE"] = [self formatPrice:p.price locale:p.priceLocale]; + + float priceCorrection = 1.0f; + if (@available(iOS 11.2, *)) { + float k = 1.0f; + switch (p.subscriptionPeriod.unit) { + case (SKProductPeriodUnitDay): + msg[@"ORIGINAL_PERIOD"] = commonMsg[@"DAY"]; + k = 1.0f; + + break; + case (SKProductPeriodUnitWeek): + msg[@"ORIGINAL_PERIOD"] = commonMsg[@"WEEK"]; + k = 1.0f / 7.0f; + + break; + case (SKProductPeriodUnitMonth): + msg[@"ORIGINAL_PERIOD"] = commonMsg[@"MONTH"]; + k = 12.0f / 365.0f; + + break; + case (SKProductPeriodUnitYear): + msg[@"ORIGINAL_PERIOD"] = commonMsg[@"YEAR"]; + k = 1.0f / 365.0f; + + break; + } + priceCorrection = k; + + float priceDaily = p.price.floatValue * k / p.subscriptionPeriod.numberOfUnits; + float priceWeekly = priceDaily * 7.0f; + float priceYearly = priceDaily * 365.0f; + float priceMonthly = priceYearly / 12.0f; + + msg[@"ORIGINAL_DURATION"] = [GYFormatter formatPeriod:p.subscriptionPeriod.numberOfUnits unit:p.subscriptionPeriod.unit locale:self.locale]; + + msg[@"ORIGINAL_DAILY"] = [self formatPrice:@(priceDaily) locale:p.priceLocale]; + msg[@"ORIGINAL_WEEKLY"] = [self formatPrice:@(priceWeekly) locale:p.priceLocale]; + msg[@"ORIGINAL_MONTHLY"] = [self formatPrice:@(priceMonthly) locale:p.priceLocale]; + msg[@"ORIGINAL_YEARLY"] = [self formatPrice:@(priceYearly) locale:p.priceLocale]; + + if (p.introductoryPrice) { + float k = 1.0f; + switch (p.introductoryPrice.subscriptionPeriod.unit) { + case (SKProductPeriodUnitDay): + msg[@"INTRO_PERIOD"] = commonMsg[@"DAY"]; + k = 1.0f; + + break; + case (SKProductPeriodUnitWeek): + msg[@"INTRO_PERIOD"] = commonMsg[@"WEEK"]; + k = 1.0f / 7.0f; + + break; + case (SKProductPeriodUnitMonth): + msg[@"INTRO_PERIOD"] = commonMsg[@"MONTH"]; + k = 12.0f / 365.0f; + + break; + case (SKProductPeriodUnitYear): + msg[@"INTRO_PERIOD"] = commonMsg[@"YEAR"]; + k = 1.0f / 365.0f; + + break; + } + + float introDaily = p.introductoryPrice.price.floatValue * k / p.introductoryPrice.subscriptionPeriod.numberOfUnits; + float introWeekly = introDaily * 7.0f; + float introYearly = introDaily * 365.0f; + float introMonthly = introYearly / 12.0f; + float introDiscount = introDaily / priceDaily; + + msg[@"INTRO_PRICE"] = [self formatPrice:p.introductoryPrice.price locale:p.introductoryPrice.priceLocale]; + msg[@"INTRO_DURATION"] = [GYFormatter formatPeriod:p.introductoryPrice.subscriptionPeriod.numberOfUnits + unit:p.introductoryPrice.subscriptionPeriod.unit + locale:self.locale]; + + msg[@"INTRO_DAILY"] = [self formatPrice:@(introDaily) locale:p.introductoryPrice.priceLocale]; + msg[@"INTRO_WEEKLY"] = [self formatPrice:@(introWeekly) locale:p.introductoryPrice.priceLocale]; + msg[@"INTRO_MONTHLY"] = [self formatPrice:@(introMonthly) locale:p.introductoryPrice.priceLocale]; + msg[@"INTRO_YEARLY"] = [self formatPrice:@(introYearly) locale:p.introductoryPrice.priceLocale]; + + msg[@"INTRO_DISCOUNT"] = [GYFormatter formatPercentage:@(introDiscount) locale:self.locale]; + } + + if (s.promotionalId) { + NSPredicate *p = [NSPredicate predicateWithFormat:@"identifier = %@", s.promotionalId]; + if (@available(iOS 12.2, *)) { + SKProductDiscount *promo = [[s.product.discounts filteredArrayUsingPredicate:p] firstObject]; + + if (promo) { + float k = 1.0f; + switch (promo.subscriptionPeriod.unit) { + case (SKProductPeriodUnitDay): + msg[@"PROMO_PERIOD"] = commonMsg[@"DAY"]; + k = 1.0f; + + break; + case (SKProductPeriodUnitWeek): + msg[@"PROMO_PERIOD"] = commonMsg[@"WEEK"]; + k = 1.0f / 7.0f; + + break; + case (SKProductPeriodUnitMonth): + msg[@"PROMO_PERIOD"] = commonMsg[@"MONTH"]; + k = 12.0f / 365.0f; + + break; + case (SKProductPeriodUnitYear): + msg[@"PROMO_PERIOD"] = commonMsg[@"YEAR"]; + k = 1.0f / 365.0f; + + break; + } + + float promoDaily = promo.price.floatValue * k / promo.subscriptionPeriod.numberOfUnits; + float promoWeekly = promoDaily * 7.0f; + float promoYearly = promoDaily * 365.0f; + float promoMonthly = promoYearly / 12.0f; + float promoDiscount = promoDaily / priceDaily; + + msg[@"PROMO_PRICE"] = [self formatPrice:promo.price locale:promo.priceLocale]; + msg[@"PROMO_DURATION"] = [GYFormatter formatPeriod:promo.subscriptionPeriod.numberOfUnits + unit:promo.subscriptionPeriod.unit + locale:self.locale]; + + msg[@"PROMO_DAILY"] = [self formatPrice:@(promoDaily) locale:promo.priceLocale]; + msg[@"PROMO_WEEKLY"] = [self formatPrice:@(promoWeekly) locale:promo.priceLocale]; + msg[@"PROMO_MONTHLY"] = [self formatPrice:@(promoMonthly) locale:promo.priceLocale]; + msg[@"PROMO_YEARLY"] = [self formatPrice:@(promoYearly) locale:promo.priceLocale]; + + msg[@"PROMO_DISCOUNT"] = [GYFormatter formatPercentage:@(promoDiscount) locale:self.locale]; + } + } + } + } + [priceCorrections addObject:@(priceCorrection)]; + + if (s.promotionalEligibility == GYSkuEligibilityEligible && msg[@"PROMO_PRICE"]) { + msg[@"PERIOD"] = msg[@"PROMO_PERIOD"]; + msg[@"PRICE"] = msg[@"PROMO_PRICE"]; + msg[@"DURATION"] = msg[@"PROMO_DURATION"]; + msg[@"DAILY"] = msg[@"PROMO_DAILY"]; + msg[@"WEEKLY"] = msg[@"PROMO_WEEKLY"]; + msg[@"MONTHLY"] = msg[@"PROMO_MONTHLY"]; + msg[@"YEARLY"] = msg[@"PROMO_YEARLY"]; + msg[@"DISCOUNT"] = msg[@"PROMO_DISCOUNT"]; + } else if (s.introductoryEligibility == GYSkuEligibilityEligible && msg[@"INTRO_PRICE"]) { + msg[@"PERIOD"] = msg[@"INTRO_PERIOD"]; + msg[@"PRICE"] = msg[@"INTRO_PRICE"]; + msg[@"DURATION"] = msg[@"INTRO_DURATION"]; + msg[@"DAILY"] = msg[@"INTRO_DAILY"]; + msg[@"WEEKLY"] = msg[@"INTRO_WEEKLY"]; + msg[@"MONTHLY"] = msg[@"INTRO_MONTHLY"]; + msg[@"YEARLY"] = msg[@"INTRO_YEARLY"]; + msg[@"DISCOUNT"] = msg[@"INTRO_DISCOUNT"]; + } else { + msg[@"PERIOD"] = msg[@"ORIGINAL_PERIOD"]; + msg[@"PRICE"] = msg[@"ORIGINAL_PRICE"]; + msg[@"DURATION"] = msg[@"ORIGINAL_DURATION"]; + msg[@"DAILY"] = msg[@"ORIGINAL_DAILY"]; + msg[@"WEEKLY"] = msg[@"ORIGINAL_WEEKLY"]; + msg[@"MONTHLY"] = msg[@"ORIGINAL_MONTHLY"]; + msg[@"YEARLY"] = msg[@"ORIGINAL_YEARLY"]; + } + + NSMutableDictionary *skusDetail = [NSMutableDictionary new]; + skusDetail[@"product"] = [s.product encodedObject]; + skusDetail[@"msg"] = msg; + skusDetail[@"identifier"] = s.skuId; + skusDetail[@"offeringid"] = s.offeringId; + skusDetail[@"promotionalid"] = s.promotionalId; + skusDetail[@"introductoryeligibility"] = @(s.introductoryEligibility); + skusDetail[@"promotionaleligibility"] = @(s.promotionalEligibility); + skusDetail[@"extravars"] = s.extravars; + + skusDetails[s.skuId] = skusDetail; + } + + // Add discount towards other skus + for (int i = 0; i < self.skus.count; i++) { + GYSku *sku = self.skus[i]; + + int units = 1; + if (@available(iOS 11.2, *)) { + if (sku.product.subscriptionPeriod.numberOfUnits != 0) { + units = (int) sku.product.subscriptionPeriod.numberOfUnits; + } + } + float originalSkuPrice = sku.product.price.floatValue * priceCorrections[i].floatValue / units; + + for (int j = 0; j < self.skus.count; j++) { + GYSku *otherSku = self.skus[j]; + + units = 1; + if (@available(iOS 11.2, *)) { + if (otherSku.product.subscriptionPeriod.numberOfUnits != 0) { + units = (int) otherSku.product.subscriptionPeriod.numberOfUnits; + } + } + float originalOtherSkuPrice = otherSku.product.price.floatValue * priceCorrections[j].floatValue / units; + + float discount = 0.0f; + if (originalSkuPrice > 0 && originalOtherSkuPrice > 0) { + discount = 1.0f - originalSkuPrice / originalOtherSkuPrice; + } + + NSString *key = [NSString stringWithFormat:@"ORIGINAL_DISCOUNT_%d", j+1]; + skusDetails[sku.skuId][@"msg"][key] = [GYFormatter formatPercentage:@(discount) locale:self.locale]; + } + } + + NSString *uiStyle = @"light"; + if (@available(iOS 13.0, *)) { + if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) { + uiStyle = @"dark"; + } + } + + NSDictionary *settings = @{ + @"pwid": self.pwid, + @"locale": self.locale.languageCode, + @"uiStyle": uiStyle, + @"sdkVersion": Glassfy.sdkVersion, + @"appVersion": GYSysInfo.appVersion, + @"subplatform": @(GYSysInfo.subplatform), + @"store": @(GYStoreAppStore), + @"systemVersion": GYSysInfo.systemVersion, + @"sysInfo": GYSysInfo.sysInfo + }; + + return @{@"gy": @{@"skus": skusDetails, @"msg": commonMsg, @"settings": settings}}; +} + +- (NSDictionary *)noCodeSkuDetails { NSMutableDictionary *skusDetails = [NSMutableDictionary new]; NSMutableDictionary *commonMsg = [NSMutableDictionary new]; diff --git a/Source/GYSysInfo.h b/Source/GYSysInfo.h index 7c2b8f1..4c46165 100644 --- a/Source/GYSysInfo.h +++ b/Source/GYSysInfo.h @@ -6,11 +6,17 @@ // #import +#import "GYInternalType.h" NS_ASSUME_NONNULL_BEGIN @interface GYSysInfo : NSObject @property(class, nonatomic, strong, readonly) NSString *installationInfo; + +@property(class, nonatomic, assign, readonly) GYSubplatform subplatform; +@property(class, nonatomic, strong, readonly) NSString *appVersion; +@property(class, nonatomic, strong, readonly) NSString *systemVersion; +@property(class, nonatomic, strong, readonly, nullable) NSString *sysInfo; @property(class, nonatomic, strong, readonly, nullable) NSNotificationName applicationDidBecomeActiveNotification; @end diff --git a/Source/GYSysInfo.m b/Source/GYSysInfo.m index ee66f2c..690d2ce 100644 --- a/Source/GYSysInfo.m +++ b/Source/GYSysInfo.m @@ -16,17 +16,6 @@ @implementation GYSysInfo -typedef NS_ENUM(NSUInteger, GYSubplatform) { - GYSubplatformUnknown = 0, - GYSubplatformiOS = 1, - GYSubplatformCatalyst = 2, - GYSubplatformTV = 3, - GYSubplatformWatch = 4, - GYSubplatformOSx = 5, - GYSubplatformDrive = 6, - GYSubplatformSimulator = 7 -}; - + (NSString *)installationInfo { // store : sub-platform : os version : device type : sdkVersion : appVersion diff --git a/Source/GYUserProperties.m b/Source/GYUserProperties.m index 6b54d67..ead9f30 100644 --- a/Source/GYUserProperties.m +++ b/Source/GYUserProperties.m @@ -16,6 +16,7 @@ @interface GYUserProperties() @implementation GYUserProperties (Private) - (instancetype)initWithObject:(nonnull NSDictionary *)obj error:(NSError **)error { + self = [super init]; if (self) { NSString *email = obj[GYUserPropertyTypeEmail]; diff --git a/Source/Glassfy.m b/Source/Glassfy.m index 4517576..6b3b014 100644 --- a/Source/Glassfy.m +++ b/Source/Glassfy.m @@ -40,7 +40,7 @@ + (Glassfy *)shared + (NSString *)sdkVersion { - return @"1.3.4"; + return @"1.4.0-beta.0"; } + (void)initializeWithAPIKey:(NSString *)apiKey @@ -153,10 +153,17 @@ + (void)getUserProperties:(GYUserPropertiesCompletion)block }); } -+ (void)paywallWithId:(NSString *)paywallid completion:(GYPaywallCompletion)block ++ (void)paywallWithId:(NSString *)paywallId completion:(GYPaywallCompletion)block { dispatch_async(Glassfy.shared.glqueue, ^{ - [Glassfy.shared.manager getPaywall:paywallid completion:block]; + [Glassfy.shared.manager getPaywall:paywallId completion:block]; + }); +} + ++ (void)paywallWithId:(NSString *)paywallId preload:(BOOL)preload completion:(GYPaywallCompletion)block +{ + dispatch_async(Glassfy.shared.glqueue, ^{ + [Glassfy.shared.manager getPaywall:paywallId preload:preload completion:block]; }); } diff --git a/Source/Public/GYPaywall.h b/Source/Public/GYPaywall.h new file mode 100644 index 0000000..8ce50eb --- /dev/null +++ b/Source/Public/GYPaywall.h @@ -0,0 +1,28 @@ +// +// GYPaywall.h +// Glassfy +// +// Created by Luca Garbolino on 27/06/22. +// + +#import +#if __has_include() +#import +#else +#import "GYTypes.h" +#endif +NS_ASSUME_NONNULL_BEGIN + +#if TARGET_OS_IPHONE +@class GYPaywallViewController; +#endif + +NS_SWIFT_NAME(Glassfy.Paywall) +@interface GYPaywall : NSObject +#if TARGET_OS_IPHONE +- (void)loadPaywallViewController:(GYPaywallViewControllerCompletion)completion; +@property(nonatomic, readonly) GYPaywallViewController *paywallViewController; +#endif +@end + +NS_ASSUME_NONNULL_END diff --git a/Source/Public/GYTypes.h b/Source/Public/GYTypes.h index 25db11f..696afef 100644 --- a/Source/Public/GYTypes.h +++ b/Source/Public/GYTypes.h @@ -9,6 +9,8 @@ #define Types_h #import + +NS_ASSUME_NONNULL_BEGIN @class SKPaymentTransaction; @class GYTransaction; @class GYPermissions; @@ -17,10 +19,12 @@ @class GYStoresInfo; @class GYSku; @class GYSkuBase; +@class GYPaywall; +#if TARGET_OS_IPHONE @class GYPaywallViewController; -NS_ASSUME_NONNULL_BEGIN - +typedef void(^GYPaywallViewControllerCompletion)(GYPaywallViewController *_Nullable, NSError *_Nullable) NS_SWIFT_NAME(Glassfy.PaywallViewControllerCompletion); +#endif typedef void(^GYSkuBlock)(GYSku* _Nullable, NSError* _Nullable) NS_SWIFT_NAME(Glassfy.SkuBlock); typedef void(^GYSkuBaseCompletion)(GYSkuBase* _Nullable, NSError* _Nullable) NS_SWIFT_NAME(Glassfy.SkuBaseCompletion); typedef void(^GYPaymentTransactionBlock)(GYTransaction* _Nullable, NSError* _Nullable) NS_SWIFT_NAME(Glassfy.PaymentTransactionBlock); @@ -30,7 +34,7 @@ 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 void(^GYStoreCompletion)(GYStoresInfo* _Nullable, NSError* _Nullable) NS_SWIFT_NAME(Glassfy.StoreCompletion); -typedef void(^GYPaywallCompletion)(GYPaywallViewController* _Nullable, NSError* _Nullable) NS_SWIFT_NAME(Glassfy.PaywallCompletion); +typedef void(^GYPaywallCompletion)(GYPaywall* _Nullable, NSError* _Nullable) NS_SWIFT_NAME(Glassfy.PaywallCompletion); typedef void(^GYPaywallCloseBlock)(GYTransaction* _Nullable, NSError* _Nullable) NS_SWIFT_NAME(Glassfy.PaywallCloseBlock); typedef void(^GYPaywallLinkBlock)(NSURL*) NS_SWIFT_NAME(Glassfy.PaywallLinkBlock); typedef void(^GYPaywallPurchaseBlock)(GYSku*) NS_SWIFT_NAME(Glassfy.PaywallPurchaseBlock); diff --git a/Source/Public/Glassfy.h b/Source/Public/Glassfy.h index 6833ed7..ea71472 100644 --- a/Source/Public/Glassfy.h +++ b/Source/Public/Glassfy.h @@ -18,6 +18,7 @@ #import #import #import +#import #import #import @@ -35,6 +36,7 @@ #import "GYPermissions.h" #import "GYOfferings.h" #import "GYUserProperties.h" +#import "GYPaywall.h" #import "GYPaywallViewController.h" #import "GYTypes.h" @@ -208,6 +210,16 @@ Save extra user properties */ + (void)paywallWithId:(NSString *)paywallid completion:(GYPaywallCompletion)block API_UNAVAILABLE(macos, watchos) NS_SWIFT_NAME(paywall(id:completion:)); + +/** + Initialize a paywall object + + @param paywallid Paywall identifier + @param preload Preload paywall content + @param block Completion block + */ ++ (void)paywallWithId:(NSString *)paywallid preload:(BOOL)preload completion:(GYPaywallCompletion)block API_UNAVAILABLE(macos, watchos) NS_SWIFT_NAME(paywall(id:preload:completion:)); + /** Connect paddle license key