diff --git a/Framework/Info.plist b/Framework/Info.plist index c548a727..b09c7d99 100644 --- a/Framework/Info.plist +++ b/Framework/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.8.6 + 5.9.0 CFBundleSignature ???? CFBundleVersion diff --git a/Qonversion.podspec b/Qonversion.podspec index 5197e2c2..de387663 100644 --- a/Qonversion.podspec +++ b/Qonversion.podspec @@ -3,7 +3,7 @@ Pod::Spec.new do |s| idfa_exclude_files = ['Sources/Qonversion/IDFA'] s.name = 'Qonversion' s.swift_version = '5.5' - s.version = '5.8.6' + s.version = '5.9.0' s.summary = 'qonversion.io' s.description = <<-DESC Deep Analytics for iOS Subscriptions diff --git a/Sources/Qonversion/Public/QONConfiguration.m b/Sources/Qonversion/Public/QONConfiguration.m index fc2c3613..9f71dce4 100644 --- a/Sources/Qonversion/Public/QONConfiguration.m +++ b/Sources/Qonversion/Public/QONConfiguration.m @@ -9,7 +9,7 @@ #import "QONConfiguration.h" #import "QNAPIConstants.h" -static NSString *const kSDKVersion = @"5.8.6"; +static NSString *const kSDKVersion = @"5.9.0"; @interface QONConfiguration () diff --git a/Sources/Qonversion/Public/Qonversion.h b/Sources/Qonversion/Public/Qonversion.h index 54c3872f..959fe78d 100644 --- a/Sources/Qonversion/Public/Qonversion.h +++ b/Sources/Qonversion/Public/Qonversion.h @@ -67,6 +67,14 @@ static NSString *const QonversionApiErrorDomain = @"com.qonversion.io.api"; */ - (void)identify:(NSString *)userID; +/** + Call this function to link a user to his unique ID in your system and share purchase data. + + @param userID - unique user ID in your system + @param completion - completion block that will be called when response is received + */ +- (void)identify:(NSString *)userID completion:(QONUserInfoCompletionHandler)completion; + /** Call this function to unlink a user from his unique ID in your system and his purchase data. */ diff --git a/Sources/Qonversion/Public/Qonversion.m b/Sources/Qonversion/Public/Qonversion.m index 3fffd13a..c1112d9f 100644 --- a/Sources/Qonversion/Public/Qonversion.m +++ b/Sources/Qonversion/Public/Qonversion.m @@ -114,27 +114,31 @@ - (void)syncHistoricalData { } - (void)identify:(NSString *)userID { - [[Qonversion sharedInstance].productCenterManager identify:userID]; + [self.productCenterManager identify:userID completion:nil]; +} + +- (void)identify:(NSString *)userID completion:(QONUserInfoCompletionHandler)completion { + [self.productCenterManager identify:userID completion:completion]; } - (void)logout { - [[Qonversion sharedInstance].productCenterManager logout]; + [self.productCenterManager logout]; } - (void)presentCodeRedemptionSheet { - [[Qonversion sharedInstance].productCenterManager presentCodeRedemptionSheet]; + [self.productCenterManager presentCodeRedemptionSheet]; } - (void)setEntitlementsUpdateListener:(id)delegate { - [[Qonversion sharedInstance].productCenterManager setPurchasesDelegate:delegate]; + [self.productCenterManager setPurchasesDelegate:delegate]; } - (void)setPromoPurchasesDelegate:(id)delegate { - [[Qonversion sharedInstance].productCenterManager setPromoPurchasesDelegate:delegate]; + [self.productCenterManager setPromoPurchasesDelegate:delegate]; } - (void)attribution:(NSDictionary *)data fromProvider:(QONAttributionProvider)provider { - [[Qonversion sharedInstance].attributionManager addAttributionData:data fromProvider:provider]; + [self.attributionManager addAttributionData:data fromProvider:provider]; } - (void)setUserProperty:(QONUserPropertyKey)key value:(NSString *)value { @@ -152,87 +156,87 @@ - (void)setUserProperty:(QONUserPropertyKey)key value:(NSString *)value { } - (void)setCustomUserProperty:(NSString *)property value:(NSString *)value { - [[Qonversion sharedInstance].propertiesManager setUserProperty:property value:value]; + [self.propertiesManager setUserProperty:property value:value]; } - (void)userProperties:(QONUserPropertiesCompletionHandler)completion { - [[Qonversion sharedInstance].propertiesManager getUserProperties:completion]; + [self.propertiesManager getUserProperties:completion]; } - (void)checkEntitlements:(QONEntitlementsCompletionHandler)completion { - [[Qonversion sharedInstance].productCenterManager checkEntitlements:completion]; + [self.productCenterManager checkEntitlements:completion]; } - (void)purchaseProduct:(QONProduct *)product completion:(QONPurchaseCompletionHandler)completion { - [[Qonversion sharedInstance].productCenterManager purchaseProduct:product completion:completion]; + [self.productCenterManager purchaseProduct:product completion:completion]; } - (void)purchase:(NSString *)productID completion:(QONPurchaseCompletionHandler)completion { - [[Qonversion sharedInstance].productCenterManager purchase:productID completion:completion]; + [self.productCenterManager purchase:productID completion:completion]; } - (void)restore:(QNRestoreCompletionHandler)completion { - [[Qonversion sharedInstance].productCenterManager restore:completion]; + [self.productCenterManager restore:completion]; } - (void)products:(QONProductsCompletionHandler)completion { - return [[Qonversion sharedInstance].productCenterManager products:completion]; + return [self.productCenterManager products:completion]; } - (void)checkTrialIntroEligibility:(NSArray *)productIds completion:(QONEligibilityCompletionHandler)completion { - [[Qonversion sharedInstance].productCenterManager checkTrialIntroEligibilityForProductIds:productIds completion:completion]; + [self.productCenterManager checkTrialIntroEligibilityForProductIds:productIds completion:completion]; } - (void)offerings:(QONOfferingsCompletionHandler)completion { - return [[Qonversion sharedInstance].productCenterManager offerings:completion]; + return [self.productCenterManager offerings:completion]; } - (void)collectAppleSearchAdsAttribution { - [[Qonversion sharedInstance].attributionManager addAppleSearchAttributionData]; + [self.attributionManager addAppleSearchAttributionData]; } - (void)userInfo:(QONUserInfoCompletionHandler)completion { - [[[Qonversion sharedInstance] productCenterManager] userInfo:completion]; + [[self productCenterManager] userInfo:completion]; } - (void)remoteConfig:(QONRemoteConfigCompletionHandler)completion { - [[[Qonversion sharedInstance] remoteConfigManager] obtainRemoteConfigWithContextKey:nil completion:completion]; + [[self remoteConfigManager] obtainRemoteConfigWithContextKey:nil completion:completion]; } - (void)remoteConfig:(NSString *)contextKey completion:(QONRemoteConfigCompletionHandler)completion { - [[[Qonversion sharedInstance] remoteConfigManager] obtainRemoteConfigWithContextKey:contextKey completion:completion]; + [[self remoteConfigManager] obtainRemoteConfigWithContextKey:contextKey completion:completion]; } - (void)remoteConfigList:(NSArray *)contextKeys includeEmptyContextKey:(BOOL)includeEmptyContextKey completion:(QONRemoteConfigListCompletionHandler)completion { - [[[Qonversion sharedInstance] remoteConfigManager] obtainRemoteConfigListWithContextKeys:contextKeys includeEmptyContextKey:includeEmptyContextKey completion:completion]; + [[self remoteConfigManager] obtainRemoteConfigListWithContextKeys:contextKeys includeEmptyContextKey:includeEmptyContextKey completion:completion]; } - (void)remoteConfigList:(QONRemoteConfigListCompletionHandler)completion { - [[[Qonversion sharedInstance] remoteConfigManager] obtainRemoteConfigList:completion]; + [[self remoteConfigManager] obtainRemoteConfigList:completion]; } - (void)attachUserToExperiment:(NSString *)experimentId groupId:(NSString *)groupId completion:(QONExperimentAttachCompletionHandler)completion { - [[[Qonversion sharedInstance] remoteConfigManager] attachUserToExperiment:experimentId groupId:groupId completion:completion]; + [[self remoteConfigManager] attachUserToExperiment:experimentId groupId:groupId completion:completion]; } - (void)detachUserFromExperiment:(NSString *)experimentId completion:(QONExperimentAttachCompletionHandler)completion { - [[[Qonversion sharedInstance] remoteConfigManager] detachUserFromExperiment:experimentId completion:completion]; + [[self remoteConfigManager] detachUserFromExperiment:experimentId completion:completion]; } - (void)attachUserToRemoteConfiguration:(NSString *)remoteConfigurationId completion:(QONRemoteConfigurationAttachCompletionHandler)completion { - [[[Qonversion sharedInstance] remoteConfigManager] attachUserToRemoteConfiguration:remoteConfigurationId completion:completion]; + [[self remoteConfigManager] attachUserToRemoteConfiguration:remoteConfigurationId completion:completion]; } - (void)detachUserFromRemoteConfiguration:(NSString *)remoteConfigurationId completion:(QONRemoteConfigurationAttachCompletionHandler)completion { - [[[Qonversion sharedInstance] remoteConfigManager] detachUserFromRemoteConfiguration:remoteConfigurationId completion:completion]; + [[self remoteConfigManager] detachUserFromRemoteConfiguration:remoteConfigurationId completion:completion]; } - (void)handlePurchases:(NSArray *)purchasesInfo { - [[Qonversion sharedInstance] handlePurchases:purchasesInfo completion:nil]; + [self handlePurchases:purchasesInfo completion:nil]; } - (void)handlePurchases:(NSArray *)purchasesInfo completion:(nullable QONDefaultCompletionHandler)completion { - [[[Qonversion sharedInstance] productCenterManager] handlePurchases:purchasesInfo completion:completion]; + [[self productCenterManager] handlePurchases:purchasesInfo completion:completion]; } // MARK: - Private @@ -264,7 +268,7 @@ - (instancetype)initWithCustomUserDefaults:(NSUserDefaults *)userDefaults { - (void)collectAdvertisingId { NSString *idfa = [QNDevice current].advertiserID; - [[Qonversion sharedInstance] setUserProperty:QONUserPropertyKeyAdvertisingID value:idfa]; + [self setUserProperty:QONUserPropertyKeyAdvertisingID value:idfa]; } @end diff --git a/Sources/Qonversion/Qonversion/Main/QNProductCenterManager/QNProductCenterManager.h b/Sources/Qonversion/Qonversion/Main/QNProductCenterManager/QNProductCenterManager.h index 310d7bf3..d9743450 100644 --- a/Sources/Qonversion/Qonversion/Main/QNProductCenterManager/QNProductCenterManager.h +++ b/Sources/Qonversion/Qonversion/Main/QNProductCenterManager/QNProductCenterManager.h @@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithUserInfoService:(id)userInfoService identityManager:(id)identityManager localStorage:(id)localStorage; - (BOOL)isUserStable; -- (void)identify:(NSString *)userID; +- (void)identify:(NSString *)userID completion:(nullable QONUserInfoCompletionHandler)completion; - (void)logout; - (void)setPurchasesDelegate:(id)delegate; - (void)setPromoPurchasesDelegate:(id)delegate; diff --git a/Sources/Qonversion/Qonversion/Main/QNProductCenterManager/QNProductCenterManager.m b/Sources/Qonversion/Qonversion/Main/QNProductCenterManager/QNProductCenterManager.m index 1d58787a..e97bb882 100644 --- a/Sources/Qonversion/Qonversion/Main/QNProductCenterManager/QNProductCenterManager.m +++ b/Sources/Qonversion/Qonversion/Main/QNProductCenterManager/QNProductCenterManager.m @@ -40,7 +40,7 @@ @interface QNProductCenterManager() @property (nonatomic, copy) NSArray *restoredTransactions; -@property (nonatomic, strong) NSMutableDictionary *purchasingBlocks; +@property (nonatomic, strong) NSMutableDictionary *purchasingBlocks; @property (nonatomic, strong) NSMutableArray *restorePurchasesBlocks; @property (nonatomic, strong) NSMutableArray *entitlementsBlocks; @property (nonatomic, strong) NSMutableArray *productsBlocks; @@ -62,6 +62,7 @@ @interface QNProductCenterManager() @property (nonatomic, assign) BOOL identityInProgress; @property (nonatomic, assign) BOOL unhandledLogoutAvailable; @property (nonatomic, copy) NSString *pendingIdentityUserID; +@property (nonatomic, strong) NSMutableDictionary *> *pendingIdentityBlocks; @end @@ -97,6 +98,7 @@ - (instancetype)initWithUserInfoService:(id)userInfo _productsBlocks = [NSMutableArray new]; _offeringsBlocks = [NSMutableArray new]; _userInfoBlocks = [NSMutableArray new]; + _pendingIdentityBlocks = [NSMutableDictionary new]; } return self; @@ -198,15 +200,19 @@ - (void)launchWithCompletion:(nullable QONLaunchCompletionHandler)completion { }]; } -- (void)identify:(NSString *)userID { +- (void)identify:(NSString *)identityId completion:(nullable QONUserInfoCompletionHandler)completion { self.unhandledLogoutAvailable = NO; - NSString *currentIdentityID = [self.userInfoService obtainCustomIdentityUserID]; - if ([currentIdentityID isEqualToString:userID]) { + NSString *currentIdentityId = [self.userInfoService obtainCustomIdentityUserID]; + if ([currentIdentityId isEqualToString:identityId]) { + if (completion) { + [self userInfo:completion]; + } return; } - self.pendingIdentityUserID = userID; + [self addIdentityCompletion:identityId completion:completion]; + self.pendingIdentityUserID = identityId; if (!self.launchingFinished || self.restoreInProgress) { return; } @@ -221,39 +227,47 @@ - (void)identify:(NSString *)userID { [weakSelf executeEntitlementsBlocksWithError:error]; [weakSelf.remoteConfigManager userChangingRequestFailedWithError:error]; } else { - [weakSelf processIdentity:userID]; + [weakSelf processIdentity:identityId]; } }]; } else { - [self processIdentity:userID]; + [self processIdentity:identityId]; } } -- (void)processIdentity:(NSString *)userID { +- (void)processIdentity:(NSString *)identityId { NSString *currentUserID = [self.userInfoService obtainUserID]; __block __weak QNProductCenterManager *weakSelf = self; - [self.identityManager identify:userID completion:^(NSString *result, NSError * _Nullable error) { + [self.identityManager identify:identityId completion:^(NSString *result, NSError * _Nullable error) { weakSelf.identityInProgress = NO; if (error) { [weakSelf executeEntitlementsBlocksWithError:error]; [weakSelf.remoteConfigManager userChangingRequestFailedWithError:error]; + [weakSelf fireIdentityError:error identityId:identityId]; return; } weakSelf.pendingIdentityUserID = nil; - [weakSelf.userInfoService storeCustomIdentityUserID:userID]; + [weakSelf.userInfoService storeCustomIdentityUserID:identityId]; if ([currentUserID isEqualToString:result]) { [weakSelf handlePendingRequests:nil]; + [weakSelf fireIdentitySuccess:identityId]; } else { [[QNAPIClient shared] setUserID:result]; [weakSelf.remoteConfigManager userHasBeenChanged]; - + [weakSelf resetActualPermissionsCache]; - [weakSelf launchWithCompletion:nil]; + [weakSelf launchWithCompletion:^(QONLaunchResult * _Nonnull result, NSError * _Nullable error) { + if (error) { + [weakSelf fireIdentityError:error identityId:identityId]; + } else { + [weakSelf fireIdentitySuccess:identityId]; + } + }]; } }]; } @@ -288,7 +302,7 @@ - (void)userInfo:(QONUserInfoCompletionHandler)completion { } [self actualizeUserInfo]; - completion(self.user, self.launchError); + run_block_on_main(completion, self.user, self.launchError); } - (void)presentCodeRedemptionSheet { @@ -1189,7 +1203,7 @@ - (void)handlePendingRequests:(NSError *)lastError { } if (self.pendingIdentityUserID) { - [self identify:self.pendingIdentityUserID]; + [self identify:self.pendingIdentityUserID completion:nil]; } else if (self.unhandledLogoutAvailable) { [self handleLogout]; } else { @@ -1198,4 +1212,43 @@ - (void)handlePendingRequests:(NSError *)lastError { } } +- (void)addIdentityCompletion:(NSString *)identityId completion:(nullable QONUserInfoCompletionHandler)completion { + if (!completion) { + return; + } + + NSMutableArray *completions = self.pendingIdentityBlocks[identityId]; + if (!completions) { + completions = [NSMutableArray new]; + self.pendingIdentityBlocks[identityId] = completions; + } + [completions addObject:completion]; +} + +- (void)fireIdentitySuccess:(NSString *)identityId { + NSMutableArray *completions = self.pendingIdentityBlocks[identityId]; + if (!completions) { + return; + } + self.pendingIdentityBlocks[identityId] = nil; + + [self userInfo:^(QONUser * _Nullable user, NSError * _Nullable error) { + for (QONUserInfoCompletionHandler completion in completions) { + run_block_on_main(completion, user, error); + } + }]; +} + +- (void)fireIdentityError:(NSError * _Nullable)error identityId:(NSString *)identityId { + NSMutableArray *completions = self.pendingIdentityBlocks[identityId]; + if (!completions) { + return; + } + self.pendingIdentityBlocks[identityId] = nil; + for (QONUserInfoCompletionHandler completion in completions) { + run_block_on_main(completion, nil, error); + } +} + + @end diff --git a/fastlane/report.xml b/fastlane/report.xml index b315de27..3a8f4d99 100644 --- a/fastlane/report.xml +++ b/fastlane/report.xml @@ -5,12 +5,12 @@ - + - +