diff --git a/CHANGELOG.md b/CHANGELOG.md index e098d53..4f90820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ The changelog for `Superwall`. Also see the [releases](https://github.com/superwall/react-native-superwall/releases) on GitHub. +## 1.3.3 + +### 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 iOS SDK to 3.10.1 [View iOS SDK release notes](https://github.com/superwall-me/Superwall-iOS/releases/tag/3.10.1) +- Adds `passIdentifiersToPlayStore` to `SuperwallOptions` which allows you to pass user identifiers to the Play Store purchases as account identifiers. This is useful for tracking user purchases in the Play Store console. +- 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. + +### Fixes + +- Fixes issue with the `Experiment` inside `PaywallInfo` being `null` in the `handleSuperwallEvent` delegate for iOS. + ## 1.3.2 ### Enhancements diff --git a/android/build.gradle b/android/build.gradle index 11e4ec2..46fdafd 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -91,6 +91,6 @@ dependencies { implementation "com.facebook.react:react-native:+" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation "com.superwall.sdk:superwall-android:1.2.9" + implementation "com.superwall.sdk:superwall-android:1.3.0" implementation 'com.android.billingclient:billing:6.1.0' } diff --git a/android/src/main/java/com/superwallreactnative/SuperwallReactNativeModule.kt b/android/src/main/java/com/superwallreactnative/SuperwallReactNativeModule.kt index 276f869..11c108d 100644 --- a/android/src/main/java/com/superwallreactnative/SuperwallReactNativeModule.kt +++ b/android/src/main/java/com/superwallreactnative/SuperwallReactNativeModule.kt @@ -237,4 +237,18 @@ class SuperwallReactNativeModule(private val reactContext: ReactApplicationConte promise.resolve(null) } } + + @ReactMethod + fun confirmAllAssignments(promise: Promise) { + CoroutineScope(Dispatchers.IO).launch { + val result = Superwall.instance.confirmAllAssignments() + val array = Arguments.createArray() + result.forEach { assignment -> + array.pushMap(assignment.toJson()) + } + launch(Dispatchers.Main) { + promise.resolve(array) + } + } + } } diff --git a/android/src/main/java/com/superwallreactnative/models/ConfirmedAssignments.kt b/android/src/main/java/com/superwallreactnative/models/ConfirmedAssignments.kt new file mode 100644 index 0000000..986df04 --- /dev/null +++ b/android/src/main/java/com/superwallreactnative/models/ConfirmedAssignments.kt @@ -0,0 +1,14 @@ +package com.superwallreactnative.models + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.ReadableMap + +import com.superwall.sdk.models.triggers.Experiment +import com.superwall.sdk.models.assignment.ConfirmedAssignment + +fun ConfirmedAssignment.toJson(): ReadableMap { + val assignmentMap = Arguments.createMap() + assignmentMap.putString("experimentId", this.experimentId) + assignmentMap.putMap("variant", this.variant.toJson()) + return assignmentMap +} diff --git a/android/src/main/java/com/superwallreactnative/models/Experiment.kt b/android/src/main/java/com/superwallreactnative/models/Experiment.kt index 7c660c5..57bce3a 100644 --- a/android/src/main/java/com/superwallreactnative/models/Experiment.kt +++ b/android/src/main/java/com/superwallreactnative/models/Experiment.kt @@ -8,10 +8,7 @@ import com.superwall.sdk.paywall.presentation.internal.state.PaywallSkippedReaso class Experiment { companion object { fun toJson(experiment: Experiment): ReadableMap { - val variantMap = Arguments.createMap() - variantMap.putString("id",experiment.variant.id) - variantMap.putString("type", experiment.variant.type.toString()) - variantMap.putString("paywallId", experiment.variant.paywallId) + val variantMap = experiment.variant.toJson() val experimentMap = Arguments.createMap() experimentMap.putString("id", experiment.id) diff --git a/android/src/main/java/com/superwallreactnative/models/SuperwallEvent.kt b/android/src/main/java/com/superwallreactnative/models/SuperwallEvent.kt index 745f520..3d8cdfc 100644 --- a/android/src/main/java/com/superwallreactnative/models/SuperwallEvent.kt +++ b/android/src/main/java/com/superwallreactnative/models/SuperwallEvent.kt @@ -196,6 +196,9 @@ class SuperwallEvent { is SuperwallEvent.ConfigFail -> { map.putString("event", "configFail") } + is SuperwallEvent.ConfirmAllAssignments -> { + map.putString("event", "confirmAllAssignments") + } } return map } diff --git a/android/src/main/java/com/superwallreactnative/models/SuperwallOptions.kt b/android/src/main/java/com/superwallreactnative/models/SuperwallOptions.kt index b8cb471..e9e97fc 100644 --- a/android/src/main/java/com/superwallreactnative/models/SuperwallOptions.kt +++ b/android/src/main/java/com/superwallreactnative/models/SuperwallOptions.kt @@ -14,6 +14,7 @@ class SuperwallOptions { options.localeIdentifier = json.getString("localeIdentifier") options.isExternalDataCollectionEnabled = json.getBoolean("isExternalDataCollectionEnabled") options.isGameControllerEnabled = json.getBoolean("isGameControllerEnabled") + options.passIdentifiersToPlayStore = json.getBoolean("passIdentifiersToPlayStore") val networkEnvironment = when (json.getString("networkEnvironment")) { "release" -> SuperwallOptions.NetworkEnvironment.Release() diff --git a/android/src/main/java/com/superwallreactnative/models/Variant.kt b/android/src/main/java/com/superwallreactnative/models/Variant.kt new file mode 100644 index 0000000..ddb96f5 --- /dev/null +++ b/android/src/main/java/com/superwallreactnative/models/Variant.kt @@ -0,0 +1,15 @@ +package com.superwallreactnative.models + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.ReadableMap +import com.superwall.sdk.models.triggers.Experiment + + +fun Experiment.Variant.toJson(): ReadableMap { + val variantMap = Arguments.createMap() + variantMap.putString("id", this.id) + variantMap.putString("type", this.type.toString()) + variantMap.putString("paywallId", this.paywallId) + + return variantMap +} diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index d7013fe..b00ade8 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1122,8 +1122,8 @@ PODS: - glog - RCT-Folly (= 2022.05.16.00) - React-Core - - SuperwallKit (= 3.10.0) - - SuperwallKit (3.10.0) + - SuperwallKit (= 3.10.1) + - SuperwallKit (3.10.1) - Yoga (1.14.0) DEPENDENCIES: @@ -1389,8 +1389,8 @@ SPEC CHECKSUMS: RevenueCat: 7be0d7bde9efb2fc1ebd1888522c55bb4f9feb18 RNPurchases: 06957eb2f35bd7bb336d32fccf3534d45a3fda8a SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 - superwall-react-native: 056b4dde47a30405c1c688bee51aa374a21ca552 - SuperwallKit: e2d162d30c5e0a464f111b32950d54dc827a9d1b + superwall-react-native: 9092fa4e0d385c480e835a032132b46a3c13b2bc + SuperwallKit: 89cfaba57c139f97a578efc6bbb1f3963d2aa6b2 Yoga: 1b901a6d6eeba4e8a2e8f308f708691cdb5db312 PODFILE CHECKSUM: 76fced934770e056b70a3087a2bc377b3556bae1 diff --git a/ios/Json/ConfirmedAssignments+Json.swift b/ios/Json/ConfirmedAssignments+Json.swift new file mode 100644 index 0000000..df80dce --- /dev/null +++ b/ios/Json/ConfirmedAssignments+Json.swift @@ -0,0 +1,11 @@ +import Foundation +import SuperwallKit + +extension ConfirmedAssignment { + func toJson() -> [String: Any] { + return [ + "experimentId": experimentId, + "variant": variant.toJson(), + ] + } +} diff --git a/ios/Json/Experiment+Json.swift b/ios/Json/Experiment+Json.swift index cd3a0b5..61f6dc1 100644 --- a/ios/Json/Experiment+Json.swift +++ b/ios/Json/Experiment+Json.swift @@ -2,16 +2,10 @@ import SuperwallKit extension Experiment { func toJson() -> [String: Any] { - var variant: [String: Any] = [ - "id": variant.id, - "type": variant.type.rawValue, - "paywallId": variant.paywallId - ] - return [ "id": id, "groupId": groupId, - "variant": variant + "variant": variant.toJson() ] } } diff --git a/ios/Json/PaywallInfo+Json.swift b/ios/Json/PaywallInfo+Json.swift index 5463649..5ea3f59 100644 --- a/ios/Json/PaywallInfo+Json.swift +++ b/ios/Json/PaywallInfo+Json.swift @@ -15,7 +15,7 @@ extension PaywallInfo { map["name"] = self.name map["url"] = self.url.absoluteString if let experiment = self.experiment { - map["experiment"] = Experiment.toJson(experiment) + map["experiment"] = experiment.toJson() } map["triggerSessionId"] = triggerSessionId diff --git a/ios/Json/Variant+Json.swift b/ios/Json/Variant+Json.swift new file mode 100644 index 0000000..bc7d179 --- /dev/null +++ b/ios/Json/Variant+Json.swift @@ -0,0 +1,22 @@ +import SuperwallKit + +extension Experiment.Variant { + func toJson() -> [String: Any] { + return [ + "id": self.id, + "type": self.type.toJson(), + "paywallId": self.paywallId, + ] + } +} + +extension Experiment.Variant.VariantType { + func toJson() -> String { + switch self { + case .treatment: + return "TREATMENT" + case .holdout: + return "HOLDOUT" + } + } +} diff --git a/ios/SuperwallReactNative.mm b/ios/SuperwallReactNative.mm index 37f3581..ca40864 100644 --- a/ios/SuperwallReactNative.mm +++ b/ios/SuperwallReactNative.mm @@ -62,6 +62,11 @@ @interface RCT_EXTERN_MODULE(SuperwallReactNative, NSObject) withRejecter:(RCTPromiseRejectBlock)reject ) +RCT_EXTERN_METHOD( + confirmAllAssignments:(RCTPromiseResolveBlock)resolve + withRejecter:(RCTPromiseRejectBlock)reject +) + + (BOOL)requiresMainQueueSetup { return NO; diff --git a/ios/SuperwallReactNative.swift b/ios/SuperwallReactNative.swift index a4bdb66..ca8071e 100644 --- a/ios/SuperwallReactNative.swift +++ b/ios/SuperwallReactNative.swift @@ -26,7 +26,7 @@ class SuperwallReactNative: RCTEventEmitter { "didDismissPaywall", "didPresentPaywall", "paywallWillOpenDeepLink", - "handleLog" + "handleLog", ] } @@ -87,38 +87,42 @@ class SuperwallReactNative: RCTEventEmitter { handler = PaywallPresentationHandler() handler?.onPresent { [weak self] paywallInfo in - let data = [ - "paywallInfoJson": paywallInfo.toJson(), - "method": "onPresent", - "handlerId": handlerId - ] as [String : Any] + let data = + [ + "paywallInfoJson": paywallInfo.toJson(), + "method": "onPresent", + "handlerId": handlerId, + ] as [String: Any] self?.sendEvent(withName: "paywallPresentationHandler", body: data) } handler?.onDismiss { [weak self] paywallInfo in - let data = [ - "paywallInfoJson": paywallInfo.toJson(), - "method": "onDismiss", - "handlerId": handlerId - ] as [String : Any] + let data = + [ + "paywallInfoJson": paywallInfo.toJson(), + "method": "onDismiss", + "handlerId": handlerId, + ] as [String: Any] self?.sendEvent(withName: "paywallPresentationHandler", body: data) } handler?.onError { [weak self] error in - let data = [ - "method": "onError", - "errorString": error.localizedDescription, - "handlerId": handlerId - ] as [String : Any] + let data = + [ + "method": "onError", + "errorString": error.localizedDescription, + "handlerId": handlerId, + ] as [String: Any] self?.sendEvent(withName: "paywallPresentationHandler", body: data) } handler?.onSkip { [weak self] reason in - let data = [ - "method": "onSkip", - "skippedReason": reason.toJson(), - "handlerId": handlerId - ] as [String : Any] + let data = + [ + "method": "onSkip", + "skippedReason": reason.toJson(), + "handlerId": handlerId, + ] as [String: Any] self?.sendEvent(withName: "paywallPresentationHandler", body: data) } } @@ -214,4 +218,14 @@ class SuperwallReactNative: RCTEventEmitter { resolve(nil) } } + + @objc(confirmAllAssignments:withRejecter:) + func confirmAllAssignments( + resolve: @escaping RCTPromiseResolveBlock, + reject: @escaping RCTPromiseRejectBlock + ) { + Superwall.shared.confirmAllAssignments { assignments in + resolve(assignments.map { $0.toJson() }) + } + } } diff --git a/package.json b/package.json index 087b776..6743ea9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@superwall/react-native-superwall", - "version": "1.3.2", + "version": "1.3.3", "description": "The React Native package for Superwall", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/src/index.tsx b/src/index.tsx index 7867223..88597dc 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -11,6 +11,7 @@ import { NativeEventEmitter } from 'react-native'; import { IdentityOptions } from './public/IdentityOptions'; import { EventEmitter } from 'events'; import { ConfigurationStatus } from './public/ConfigurationStatus'; +import { ConfirmedAssignment } from './public/ConfirmedAssigments'; const { version } = require('../package.json'); const LINKING_ERROR = @@ -319,6 +320,14 @@ export default class Superwall { ); } + async confirmAllAssignments(): Promise { + await this.awaitConfig(); + const assignments = await SuperwallReactNative.confirmAllAssignments(); + return assignments.map((assignment: any) => + ConfirmedAssignment.fromJson(assignment) + ); + } + async getConfigurationStatus(): Promise { const configurationStatusString = await SuperwallReactNative.getConfigurationStatus(); diff --git a/src/public/ConfirmedAssigments.ts b/src/public/ConfirmedAssigments.ts new file mode 100644 index 0000000..65650e7 --- /dev/null +++ b/src/public/ConfirmedAssigments.ts @@ -0,0 +1,18 @@ +import { Variant } from './Experiment'; + +export class ConfirmedAssignment { + experimentId: String; + variant: Variant; + + constructor(experimentId: String, variant: Variant) { + this.experimentId = experimentId; + this.variant = variant; + } + + static fromJson(json: any): ConfirmedAssignment { + return new ConfirmedAssignment( + json.experimentId, + Variant.fromJson(json.variant) + ); + } +} diff --git a/src/public/SuperwallOptions.ts b/src/public/SuperwallOptions.ts index df9fc98..4bf637d 100644 --- a/src/public/SuperwallOptions.ts +++ b/src/public/SuperwallOptions.ts @@ -28,6 +28,7 @@ export class SuperwallOptions { isGameControllerEnabled: boolean = false; logging: LoggingOptions = new LoggingOptions(); collectAdServicesAttribution: boolean = false; + passIdentifiersToPlayStore: boolean = false; // Optionally, add a constructor for customization or methods for manipulation constructor(init?: Partial) { @@ -47,6 +48,7 @@ export class SuperwallOptions { isGameControllerEnabled: this.isGameControllerEnabled, logging: this.logging.toJson(), collectAdServicesAttribution: this.collectAdServicesAttribution, + passIdentifiersToPlayStore: this.passIdentifiersToPlayStore, }; } } diff --git a/superwall-react-native.podspec b/superwall-react-native.podspec index d0ac6fa..ad7d306 100644 --- a/superwall-react-native.podspec +++ b/superwall-react-native.podspec @@ -15,7 +15,7 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/superwall-me/Superwall-React-Native.git", :tag => "#{s.version}" } s.source_files = "ios/**/*.{h,m,mm,swift}" - s.dependency "SuperwallKit", '3.10.0' + s.dependency "SuperwallKit", '3.10.1' # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0. # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.