From 6f96643cd058d895ee6d70cb1c3c26a4525cd6cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20To=CC=88r?= <3296904+yusuftor@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:54:11 +0100 Subject: [PATCH] Added `setLocaleIdentifier(_:)` and `getLocaleIdentifier()`. --- CHANGELOG.md | 11 +- .../bridges/SuperwallBridge.kt | 11 + example/ios/Runner/Products.storekit | 69 ++- ios/Classes/Bridges/SuperwallBridge.swift | 421 ++++++++++-------- lib/src/public/Superwall.dart | 20 +- pubspec.yaml | 2 +- 6 files changed, 328 insertions(+), 206 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a87667c..663528b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,16 @@ The changelog for `Superwall`. Also see the [releases](https://github.com/superwall/Superwall-Flutter/releases) on GitHub. +## 1.3.4 + +### Enhancements + +- Adds `setLocaleIdentifier(_:)` and `getLocaleIdentifier()`. + ## 1.3.3 -- Upgrades Android SDK to 1.3.1 [View Android SDK release notes](https://github.com/superwall-me/Superwall-Android/releases/tag/1.3.1) - - This fixes the issue when using Superwall with some SDK's would cause a crash (i.e. Smartlook SDK) +- Upgrades Android SDK to 1.3.1 [View Android SDK release notes](https://github.com/superwall-me/Superwall-Android/releases/tag/1.3.1) +- This fixes the issue when using Superwall with some SDK's would cause a crash (i.e. Smartlook SDK) ## 1.3.2 @@ -16,6 +22,7 @@ The changelog for `Superwall`. Also see the [releases](https://github.com/superw ## 1.3.1 ### Enhancements + - Upgrades Android SDK to 1.3.0 [View Android SDK release notes](https://github.com/superwall-me/Superwall-Android/releases/tag/1.3.0) - Upgrades Android SDK to 3.10.1 [View Android SDK release notes](https://github.com/superwall-me/Superwall-iOS/releases/tag/3.10.1) - Adds `confirmAllAssignments` method to `Superwall` which confirms assignments for all placements and returns an array of all confirmed experiment assignments. Note that the assignments may be different when a placement is registered due to changes in user, placement, or device parameters used in audience filters. diff --git a/android/src/main/kotlin/com/superwall/superwallkit_flutter/bridges/SuperwallBridge.kt b/android/src/main/kotlin/com/superwall/superwallkit_flutter/bridges/SuperwallBridge.kt index bf74c36..17020ca 100644 --- a/android/src/main/kotlin/com/superwall/superwallkit_flutter/bridges/SuperwallBridge.kt +++ b/android/src/main/kotlin/com/superwall/superwallkit_flutter/bridges/SuperwallBridge.kt @@ -82,6 +82,17 @@ class SuperwallBridge( } } + "getLocaleIdentifier" -> { + val identifier = Superwall.instance.localeIdentifier + result.success(identifier) + } + + "setLocaleIdentifier" -> { + val localeIdentifier = call.argument("localeIdentifier") + Superwall.instance.localeIdentifier = localeIdentifier + result.success(null) + } + "getUserId" -> { // Implement logic to get the current user's id val userId = Superwall.instance.userId diff --git a/example/ios/Runner/Products.storekit b/example/ios/Runner/Products.storekit index b5e7b93..c98c64f 100644 --- a/example/ios/Runner/Products.storekit +++ b/example/ios/Runner/Products.storekit @@ -1,4 +1,14 @@ { + "appPolicies" : { + "eula" : "", + "policies" : [ + { + "locale" : "en_US", + "policyText" : "", + "policyURL" : "" + } + ] + }, "identifier" : "AD417988", "nonRenewingSubscriptions" : [ @@ -89,7 +99,10 @@ "recurringSubscriptionPeriod" : "P1M", "referenceName" : "com.ui_tests.monthly", "subscriptionGroupID" : "4F31BE19", - "type" : "RecurringSubscription" + "type" : "RecurringSubscription", + "winbackOffers" : [ + + ] }, { "adHocOffers" : [ @@ -114,7 +127,10 @@ "recurringSubscriptionPeriod" : "P1Y", "referenceName" : "com.ui_tests.annual", "subscriptionGroupID" : "4F31BE19", - "type" : "RecurringSubscription" + "type" : "RecurringSubscription", + "winbackOffers" : [ + + ] }, { "adHocOffers" : [ @@ -139,7 +155,10 @@ "recurringSubscriptionPeriod" : "P1Y", "referenceName" : "com.ui_tests.custom_annual", "subscriptionGroupID" : "4F31BE19", - "type" : "RecurringSubscription" + "type" : "RecurringSubscription", + "winbackOffers" : [ + + ] }, { "adHocOffers" : [ @@ -164,7 +183,10 @@ "recurringSubscriptionPeriod" : "P1M", "referenceName" : "com.ui_tests.custom_monthly", "subscriptionGroupID" : "4F31BE19", - "type" : "RecurringSubscription" + "type" : "RecurringSubscription", + "winbackOffers" : [ + + ] }, { "adHocOffers" : [ @@ -193,13 +215,48 @@ "recurringSubscriptionPeriod" : "P1Y", "referenceName" : "com.ui_tests.free_trial_annual", "subscriptionGroupID" : "4F31BE19", - "type" : "RecurringSubscription" + "type" : "RecurringSubscription", + "winbackOffers" : [ + + ] + }, + { + "adHocOffers" : [ + + ], + "codeOffers" : [ + + ], + "displayPrice" : "89.99", + "familyShareable" : false, + "groupNumber" : 1, + "internalID" : "F92019EE", + "introductoryOffer" : { + "internalID" : "C3BBE17D", + "paymentMode" : "free", + "subscriptionPeriod" : "P1W" + }, + "localizations" : [ + { + "description" : "with a free 7 day trial", + "displayName" : "Yearly Subscription", + "locale" : "en_US" + } + ], + "productID" : "sk.superwall.annual.89.99_7", + "recurringSubscriptionPeriod" : "P1Y", + "referenceName" : "sw_8999_yr", + "subscriptionGroupID" : "4F31BE19", + "type" : "RecurringSubscription", + "winbackOffers" : [ + + ] } ] } ], "version" : { - "major" : 3, + "major" : 4, "minor" : 0 } } diff --git a/ios/Classes/Bridges/SuperwallBridge.swift b/ios/Classes/Bridges/SuperwallBridge.swift index 21cd62d..0f86e0b 100644 --- a/ios/Classes/Bridges/SuperwallBridge.swift +++ b/ios/Classes/Bridges/SuperwallBridge.swift @@ -6,220 +6,249 @@ public class SuperwallBridge: BridgeInstance { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { - case "setDelegate": - guard let delegateProxyBridge: SuperwallDelegate = call.bridgeInstance(for: "delegateProxyBridgeId") else { - result(call.badArgs) - return + case "setDelegate": + guard + let delegateProxyBridge: SuperwallDelegate = call.bridgeInstance( + for: "delegateProxyBridgeId") + else { + result(call.badArgs) + return + } + + Superwall.shared.delegate = delegateProxyBridge + + result(nil) + + case "getLogLevel": + // Implement logic to get log level + let json = Superwall.shared.logLevel.toJson() + result(json) + + case "setLogLevel": + guard + let logLevelValue: String = call.argument(for: "logLevel"), + let logLevel = LogLevel.fromJson(logLevelValue) + else { + result(call.badArgs) + return + } + + Superwall.shared.logLevel = logLevel + + result(nil) + + case "getUserAttributes": + // Implement logic to get user attributes + result(Superwall.shared.userAttributes) + + case "setUserAttributes": + guard let userAttributes: [String: Any?] = call.argument(for: "userAttributes") else { + result(call.badArgs) + return + } + + Superwall.shared.setUserAttributes(userAttributes) + + result(nil) + + case "getUserId": + // Implement logic to get the current user's id + result(Superwall.shared.userId) + + case "getIsLoggedIn": + // Implement logic to check if the user is logged in to Superwall + result(Superwall.shared.isLoggedIn) + + case "getIsInitialized": + // Implement logic to check if Superwall is initialized + result(Superwall.isInitialized) + + case "getPresentedViewController": + // TODO: Implement logic to get the presented paywall view controller + result(FlutterMethodNotImplemented) + + case "getLatestPaywallInfoBridgeId": + // Implement logic to get the latest PaywallInfo object + let paywallInfo = Superwall.shared.latestPaywallInfo + result(paywallInfo?.createBridgeId()) + + case "getSubscriptionStatusBridgeId": + // Implement logic to get the subscription status of the user + let subscriptionStatusBridgeId = Superwall.shared.subscriptionStatus.createBridgeId() + result(subscriptionStatusBridgeId) + + case "setSubscriptionStatus": + // Implement logic to set the subscription status of the user + guard + let subscriptionStatusBridge: SubscriptionStatusBridge = call.bridgeInstance( + for: "subscriptionStatusBridgeId") + else { + result(call.badArgs) + return + } + + Superwall.shared.subscriptionStatus = subscriptionStatusBridge.status + result(nil) + + case "getConfigurationStatusBridgeId": + // Implement logic to check the configuration status of Superwall + let configurationStatusBridgeId = Superwall.shared.configurationStatus.createBridgeId() + result(configurationStatusBridgeId) + + case "getIsConfigured": + // Implement logic to check if Superwall has finished configuring + result(Superwall.shared.isConfigured) + + case "setIsConfigured": + // Implement logic to set the configured state of Superwall + if let configured: Bool = call.argument(for: "configured") { + Superwall.shared.isConfigured = configured + } + result(nil) + + case "getLocaleIdentifier": + // Implement logic to check if Superwall has finished configuring + result(Superwall.shared.localeIdentifier) + + case "setLocaleIdentifier": + guard let identifier: String? = call.argument(for: "localeIdentifier") else { + result(call.badArgs) + return + } + + Superwall.shared.localeIdentifier = identifier + + result(nil) + + case "getIsPaywallPresented": + // Implement logic to check if a paywall is currently being presented + result(Superwall.shared.isPaywallPresented) + + case "preloadAllPaywalls": + // Implement logic to preload all paywalls + Superwall.shared.preloadAllPaywalls() + result(nil) + + case "preloadPaywallsForEvents": + // Implement logic to preload paywalls for specific event names + if let eventNames: [String] = call.argument(for: "eventNames") { + Superwall.shared.preloadPaywalls(forEvents: Set(eventNames)) + } + result(nil) + + case "handleDeepLink": + // Implement logic to handle deep links for paywall previews + if let urlString: String = call.argument(for: "url"), let url = URL(string: urlString) { + let handled = Superwall.shared.handleDeepLink(url) + result(handled) + } else { + result(call.badArgs) + } + + case "togglePaywallSpinner": + // Implement logic to toggle the paywall loading spinner + if let isHidden: Bool = call.argument(for: "isHidden") { + Superwall.shared.togglePaywallSpinner(isHidden: isHidden) + } + result(nil) + + case "reset": + // Implement logic to reset the user ID, on-device paywall assignments, and stored data + Superwall.shared.reset() + result(nil) + + case "configure": + // Implement logic to configure the Superwall instance + guard let apiKey: String = call.argument(for: "apiKey") else { + result(call.badArgs) + return + } + let purchaseControllerProxyBridge: PurchaseControllerProxyBridge? = call.bridgeInstance( + for: "purchaseControllerProxyBridgeId") + + let options: SuperwallOptions? = { + guard let optionsValue: [String: Any] = call.argument(for: "options") else { + return nil } - Superwall.shared.delegate = delegateProxyBridge - + let options = SuperwallOptions.fromJson(optionsValue) + return options + }() + + Superwall.configure( + apiKey: apiKey, purchaseController: purchaseControllerProxyBridge, options: options + ) { + let completionBlockProxyBridge: CompletionBlockProxyBridge? = call.bridgeInstance( + for: "completionBlockProxyBridgeId") + completionBlockProxyBridge?.callCompletionBlock() + } + + // Set the platform wrapper + let sdkVersion = call.argument(for: "sdkVersion") ?? "" + Superwall.shared.setPlatformWrapper("Flutter", version: sdkVersion) + + // Returning nil instead of the result from configure because we want to use the Dart + // instance of Superwall, not a native variant + result(nil) + + case "dismiss": + Task { + await Superwall.shared.dismiss() result(nil) + } + + case "registerEvent": + guard let event: String = call.argument(for: "event") else { + result(call.badArgs) + return + } - case "getLogLevel": - // Implement logic to get log level - let json = Superwall.shared.logLevel.toJson() - result(json) + let params: [String: Any]? = call.argument(for: "params") - case "setLogLevel": + let handler: PaywallPresentationHandler? = { guard - let logLevelValue: String = call.argument(for: "logLevel"), - let logLevel = LogLevel.fromJson(logLevelValue) + let handlerProxyBridge: PaywallPresentationHandlerProxyBridge = call.bridgeInstance( + for: "handlerProxyBridgeId") else { - result(call.badArgs) - return - } - - Superwall.shared.logLevel = logLevel - - result(nil) - - case "getUserAttributes": - // Implement logic to get user attributes - result(Superwall.shared.userAttributes) - - case "setUserAttributes": - guard let userAttributes: [String: Any?] = call.argument(for: "userAttributes") else { - result(call.badArgs) - return - } - - Superwall.shared.setUserAttributes(userAttributes) - - result(nil) - - case "getUserId": - // Implement logic to get the current user's id - result(Superwall.shared.userId) - - case "getIsLoggedIn": - // Implement logic to check if the user is logged in to Superwall - result(Superwall.shared.isLoggedIn) - - case "getIsInitialized": - // Implement logic to check if Superwall is initialized - result(Superwall.isInitialized) - - case "getPresentedViewController": - // TODO: Implement logic to get the presented paywall view controller - result(FlutterMethodNotImplemented) - - case "getLatestPaywallInfoBridgeId": - // Implement logic to get the latest PaywallInfo object - let paywallInfo = Superwall.shared.latestPaywallInfo - result(paywallInfo?.createBridgeId()) - - case "getSubscriptionStatusBridgeId": - // Implement logic to get the subscription status of the user - let subscriptionStatusBridgeId = Superwall.shared.subscriptionStatus.createBridgeId() - result(subscriptionStatusBridgeId) - - case "setSubscriptionStatus": - // Implement logic to set the subscription status of the user - guard let subscriptionStatusBridge: SubscriptionStatusBridge = call.bridgeInstance(for: "subscriptionStatusBridgeId") else { - result(call.badArgs) - return + return nil } - Superwall.shared.subscriptionStatus = subscriptionStatusBridge.status - result(nil) - - case "getConfigurationStatusBridgeId": - // Implement logic to check the configuration status of Superwall - let configurationStatusBridgeId = Superwall.shared.configurationStatus.createBridgeId() - result(configurationStatusBridgeId) + return handlerProxyBridge.handler + }() - case "getIsConfigured": - // Implement logic to check if Superwall has finished configuring - result(Superwall.shared.isConfigured) - - case "setIsConfigured": - // Implement logic to set the configured state of Superwall - if let configured: Bool = call.argument(for: "configured") { - Superwall.shared.isConfigured = configured + Superwall.shared.register(event: event, params: params, handler: handler) { + if let featureBlockProxyBridge: CompletionBlockProxyBridge = call.bridgeInstance( + for: "featureBlockProxyBridgeId") + { + featureBlockProxyBridge.callCompletionBlock() } - result(nil) + } - case "getIsPaywallPresented": - // Implement logic to check if a paywall is currently being presented - result(Superwall.shared.isPaywallPresented) + result(nil) - case "preloadAllPaywalls": - // Implement logic to preload all paywalls - Superwall.shared.preloadAllPaywalls() - result(nil) + case "identify": + guard let userId: String = call.argument(for: "userId") else { + result(call.badArgs) + return + } - case "preloadPaywallsForEvents": - // Implement logic to preload paywalls for specific event names - if let eventNames: [String] = call.argument(for: "eventNames") { - Superwall.shared.preloadPaywalls(forEvents: Set(eventNames)) + let options: IdentityOptions? = { + guard let identityOptionsJson: [String: Any] = call.argument(for: "identityOptions") else { + return nil } - result(nil) - case "handleDeepLink": - // Implement logic to handle deep links for paywall previews - if let urlString: String = call.argument(for: "url"), let url = URL(string: urlString) { - let handled = Superwall.shared.handleDeepLink(url) - result(handled) - } else { - result(call.badArgs) - } + return IdentityOptions.fromJson(identityOptionsJson) + }() - case "togglePaywallSpinner": - // Implement logic to toggle the paywall loading spinner - if let isHidden: Bool = call.argument(for: "isHidden") { - Superwall.shared.togglePaywallSpinner(isHidden: isHidden) - } - result(nil) - - case "reset": - // Implement logic to reset the user ID, on-device paywall assignments, and stored data - Superwall.shared.reset() - result(nil) - - case "configure": - // Implement logic to configure the Superwall instance - guard let apiKey: String = call.argument(for: "apiKey") else { - result(call.badArgs) - return - } - let purchaseControllerProxyBridge: PurchaseControllerProxyBridge? = call.bridgeInstance(for: "purchaseControllerProxyBridgeId") + Superwall.shared.identify(userId: userId, options: options) - let options: SuperwallOptions? = { - guard let optionsValue: [String: Any] = call.argument(for: "options") else { - return nil - } - - let options = SuperwallOptions.fromJson(optionsValue) - return options - }() - - Superwall.configure(apiKey: apiKey, purchaseController: purchaseControllerProxyBridge, options: options) { - let completionBlockProxyBridge: CompletionBlockProxyBridge? = call.bridgeInstance(for: "completionBlockProxyBridgeId") - completionBlockProxyBridge?.callCompletionBlock() - } - - // Set the platform wrapper - let sdkVersion = call.argument(for: "sdkVersion") ?? "" - Superwall.shared.setPlatformWrapper("Flutter", version: sdkVersion) - - // Returning nil instead of the result from configure because we want to use the Dart - // instance of Superwall, not a native variant - result(nil) - - case "dismiss": - Task { - await Superwall.shared.dismiss() - result(nil) - } - - case "registerEvent": - guard let event: String = call.argument(for: "event") else { - result(call.badArgs) - return - } - - let params: [String: Any]? = call.argument(for: "params") - - let handler: PaywallPresentationHandler? = { - guard let handlerProxyBridge: PaywallPresentationHandlerProxyBridge = call.bridgeInstance(for: "handlerProxyBridgeId") else { - return nil - } - - return handlerProxyBridge.handler - }() - - Superwall.shared.register(event: event, params: params, handler: handler) { - if let featureBlockProxyBridge: CompletionBlockProxyBridge = call.bridgeInstance(for: "featureBlockProxyBridgeId") { - featureBlockProxyBridge.callCompletionBlock() - } - } - - result(nil) - - case "identify": - guard let userId: String = call.argument(for: "userId") else { - result(call.badArgs) - return - } - - let options: IdentityOptions? = { - guard let identityOptionsJson: [String: Any] = call.argument(for: "identityOptions") else { - return nil - } - - return IdentityOptions.fromJson(identityOptionsJson) - }() - - Superwall.shared.identify(userId: userId, options: options) - - result(nil) - case "confirmAllAssignments": - Superwall.shared.confirmAllAssignments() { assignments in - result(assignments.map { $0.toJson() }) - } - default: - result(FlutterMethodNotImplemented) + result(nil) + case "confirmAllAssignments": + Superwall.shared.confirmAllAssignments { assignments in + result(assignments.map { $0.toJson() }) + } + default: + result(FlutterMethodNotImplemented) } } } diff --git a/lib/src/public/Superwall.dart b/lib/src/public/Superwall.dart index 5b47442..a9d6caa 100644 --- a/lib/src/public/Superwall.dart +++ b/lib/src/public/Superwall.dart @@ -110,6 +110,23 @@ class Superwall extends BridgeIdInstantiable { 'setUserAttributes', {'userAttributes': userAttributes}); } + // Asynchronous method to get userAttributes + Future getLocaleIdentifier() async { + await _waitForBridgeInstanceCreation(); + + final identifier = + await bridgeId.communicator.invokeBridgeMethod('getLocaleIdentifier'); + return identifier; + } + + // Asynchronous method to set userAttributes + Future setLocaleIdentifier(String? localeIdentifier) async { + await _waitForBridgeInstanceCreation(); + + await bridgeId.communicator.invokeBridgeMethod( + 'setLocaleIdentifier', {'localeIdentifier': localeIdentifier}); + } + // Asynchronous method to get the current user's id Future getUserId() async { await _waitForBridgeInstanceCreation(); @@ -252,7 +269,8 @@ class Superwall extends BridgeIdInstantiable { Future> confirmAllAssignments() async { await _waitForBridgeInstanceCreation(); - final result = await bridgeId.communicator.invokeBridgeMethod('confirmAllAssignments'); + final result = + await bridgeId.communicator.invokeBridgeMethod('confirmAllAssignments'); return List.from(result); } diff --git a/pubspec.yaml b/pubspec.yaml index 388f332..f9117c7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: superwallkit_flutter description: "Remotely configure every aspect of your paywall and double your revenue." -version: 1.3.3 +version: 1.3.4 homepage: "https://superwall.com" environment: