From f06cea91c0f5734a0f679d9385fb96c05dfd8391 Mon Sep 17 00:00:00 2001 From: Maria Bordunova Date: Wed, 26 May 2021 15:39:13 +0300 Subject: [PATCH 1/2] Add support for Android v2 embedding --- .../QonversionFlutterSdkPlugin.kt | 159 ++++++++++++------ .../android/app/src/main/AndroidManifest.xml | 2 +- example/pubspec.yaml | 1 + 3 files changed, 106 insertions(+), 56 deletions(-) diff --git a/android/src/main/kotlin/com/qonversion/flutter/sdk/qonversion_flutter_sdk/QonversionFlutterSdkPlugin.kt b/android/src/main/kotlin/com/qonversion/flutter/sdk/qonversion_flutter_sdk/QonversionFlutterSdkPlugin.kt index 4d0b6197..73b3aa78 100644 --- a/android/src/main/kotlin/com/qonversion/flutter/sdk/qonversion_flutter_sdk/QonversionFlutterSdkPlugin.kt +++ b/android/src/main/kotlin/com/qonversion/flutter/sdk/qonversion_flutter_sdk/QonversionFlutterSdkPlugin.kt @@ -6,42 +6,65 @@ import androidx.annotation.NonNull import androidx.preference.PreferenceManager import com.google.gson.Gson import com.qonversion.android.sdk.* -import io.flutter.plugin.common.MethodCall -import io.flutter.plugin.common.MethodChannel -import io.flutter.plugin.common.MethodChannel.MethodCallHandler -import io.flutter.plugin.common.MethodChannel.Result -import io.flutter.plugin.common.PluginRegistry.Registrar - import com.qonversion.android.sdk.dto.QLaunchResult import com.qonversion.android.sdk.dto.QPermission import com.qonversion.android.sdk.dto.eligibility.QEligibility import com.qonversion.android.sdk.dto.offerings.QOfferings import com.qonversion.android.sdk.dto.products.QProduct +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.activity.ActivityAware +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import io.flutter.plugin.common.MethodChannel.Result +import io.flutter.plugin.common.PluginRegistry.Registrar /** QonversionFlutterSdkPlugin */ -class QonversionFlutterSdkPlugin internal constructor(registrar: Registrar): MethodCallHandler { - private val activity: Activity = registrar.activity() - private val application: Application = activity.application +class QonversionFlutterSdkPlugin : MethodCallHandler, FlutterPlugin, ActivityAware { + private var activity: Activity? = null + private var application: Application? = null + private var channel: MethodChannel? = null private var deferredPurchasesStreamHandler: BaseEventStreamHandler? = null companion object { + const val METHOD_CHANNEL = "qonversion_flutter_sdk" + const val EVENT_CHANNEL_PROMO_PURCHASES = "promo_purchases" + const val EVENT_CHANNEL_DEFERRED_PURCHASES = "updated_purchases" + @JvmStatic fun registerWith(registrar: Registrar) { - val channel = MethodChannel(registrar.messenger(), "qonversion_flutter_sdk") - val instance = QonversionFlutterSdkPlugin(registrar) - channel.setMethodCallHandler(instance) - - // Register deferred purchases events - val purchasesListener = BaseListenerWrapper(registrar.messenger(), "updated_purchases") - purchasesListener.register() - instance.deferredPurchasesStreamHandler = purchasesListener.eventStreamHandler - - // Register promo purchases events. Android SDK does not generate any promo purchases yet - val promoPurchasesListener = BaseListenerWrapper(registrar.messenger(), "promo_purchases") - promoPurchasesListener.register() + val instance = QonversionFlutterSdkPlugin() + instance.setup(registrar.messenger(), registrar.activity().application) + instance.activity = registrar.activity() } } + override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { + setup(binding.binaryMessenger, binding.applicationContext as Application) + } + + override fun onAttachedToActivity(binding: ActivityPluginBinding) { + activity = binding.activity + } + + override fun onDetachedFromActivityForConfigChanges() { + onDetachedFromActivity() + } + + override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { + onAttachedToActivity(binding) + } + + override fun onDetachedFromActivity() { + activity = null + } + + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { + tearDown() + } + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { // Methods without args @@ -96,25 +119,25 @@ class QonversionFlutterSdkPlugin internal constructor(registrar: Registrar): Met } private fun launch(args: Map, result: Result) { - val apiKey = args["key"] as? String ?: return result.noApiKeyError() - val isObserveMode = args["isObserveMode"] as? Boolean ?: return result.noArgsError() - - Qonversion.launch( - application, - apiKey, - isObserveMode, - callback = object: QonversionLaunchCallback { - override fun onSuccess(launchResult: QLaunchResult) { - result.success(launchResult.toMap()) - } - - override fun onError(error: QonversionError) { - result.qonversionError(error.description, error.additionalMessage) + application?.let { application -> + val apiKey = args["key"] as? String ?: return result.noApiKeyError() + val isObserveMode = args["isObserveMode"] as? Boolean ?: return result.noArgsError() + Qonversion.launch( + application, + apiKey, + isObserveMode, + callback = object : QonversionLaunchCallback { + override fun onSuccess(launchResult: QLaunchResult) { + result.success(launchResult.toMap()) + } + + override fun onError(error: QonversionError) { + result.qonversionError(error.description, error.additionalMessage) + } } - } - ) - - startListeningPendingPurchasesEvents() + ) + startListeningPendingPurchasesEvents() + } ?: result.error(QonversionErrorCode.UnknownError.name, "Couldn't launch Qonversion. There is no Application context", null) } private fun identify(userId: String?, result: Result) { @@ -143,15 +166,17 @@ class QonversionFlutterSdkPlugin internal constructor(registrar: Registrar): Met return } - Qonversion.purchase(activity, productId, callback = object: QonversionPermissionsCallback { - override fun onSuccess(permissions: Map) { - result.success(PurchaseResult(permissions).toMap()) - } + activity?.let { activity -> + Qonversion.purchase(activity, productId, callback = object : QonversionPermissionsCallback { + override fun onSuccess(permissions: Map) { + result.success(PurchaseResult(permissions).toMap()) + } - override fun onError(error: QonversionError) { - result.success(PurchaseResult(error = error).toMap()) - } - }) + override fun onError(error: QonversionError) { + result.success(PurchaseResult(error = error).toMap()) + } + }) + } ?: result.error(QonversionErrorCode.PurchaseInvalid.name, "Couldn't make purchase. There is no Activity context", null) } private fun updatePurchase(args: Map, result: Result) { @@ -159,15 +184,17 @@ class QonversionFlutterSdkPlugin internal constructor(registrar: Registrar): Met val oldProductId = args["oldProductId"] as? String ?: return result.noOldProductIdError() val prorationMode = args["proration_mode"] as? Int - Qonversion.updatePurchase(activity, newProductId, oldProductId, prorationMode, callback = object: QonversionPermissionsCallback { - override fun onSuccess(permissions: Map) { - result.success(permissions.mapValues { it.value.toMap() }) - } + activity?.let { activity -> + Qonversion.updatePurchase(activity, newProductId, oldProductId, prorationMode, callback = object : QonversionPermissionsCallback { + override fun onSuccess(permissions: Map) { + result.success(permissions.mapValues { it.value.toMap() }) + } - override fun onError(error: QonversionError) { - result.qonversionError(error.description, error.additionalMessage) - } - }) + override fun onError(error: QonversionError) { + result.qonversionError(error.description, error.additionalMessage) + } + }) + } ?: result.error(QonversionErrorCode.PurchaseInvalid.name, "Couldn't update purchase. There is no Activity context", null) } private fun checkPermissions(result: Result) { @@ -304,4 +331,26 @@ class QonversionFlutterSdkPlugin internal constructor(registrar: Registrar): Met result.success(null) } + + private fun setup(messenger: BinaryMessenger, application: Application) { + this.application = application + channel = MethodChannel(messenger, METHOD_CHANNEL) + channel?.setMethodCallHandler(this) + + // Register deferred purchases events + val purchasesListener = BaseListenerWrapper(messenger, EVENT_CHANNEL_DEFERRED_PURCHASES) + purchasesListener.register() + this.deferredPurchasesStreamHandler = purchasesListener.eventStreamHandler + + // Register promo purchases events. Android SDK does not generate any promo purchases yet + val promoPurchasesListener = BaseListenerWrapper(messenger, EVENT_CHANNEL_PROMO_PURCHASES) + promoPurchasesListener.register() + } + + private fun tearDown() { + channel?.setMethodCallHandler(null) + channel = null + this.deferredPurchasesStreamHandler = null + this.application = null + } } diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 8b80cfdd..b0b5a1ec 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -14,7 +14,7 @@ android:label="com.qonversion.sample" android:icon="@mipmap/ic_launcher"> =2.3.0 <3.0.0" + flutter: ">=1.12.13+hotfix.6" dependencies: flutter: From ae571c91cbf7d6e7fdf08a9279a1900956080a39 Mon Sep 17 00:00:00 2001 From: Maria Bordunova Date: Wed, 2 Jun 2021 15:33:07 +0300 Subject: [PATCH 2/2] Bump version to 3.2.0 --- CHANGELOG.md | 3 +++ android/build.gradle | 2 +- lib/src/qonversion.dart | 2 +- pubspec.yaml | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22a3c2a3..9ba6ac8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 3.2.0 +* Add support for Android v2 embedding + ## 3.1.0 * Add support for promo purchases on iOS * Add Identity support diff --git a/android/build.gradle b/android/build.gradle index c817fd32..4eb8fc53 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ group 'com.qonversion.flutter.sdk.qonversion_flutter_sdk' -version '3.1.0' +version '3.2.0' buildscript { ext.kotlin_version = '1.3.50' diff --git a/lib/src/qonversion.dart b/lib/src/qonversion.dart index befea8c7..89930368 100644 --- a/lib/src/qonversion.dart +++ b/lib/src/qonversion.dart @@ -16,7 +16,7 @@ import 'models/purchase_exception.dart'; import 'qa_provider.dart'; class Qonversion { - static const String _sdkVersion = "3.1.0"; + static const String _sdkVersion = "3.2.0"; static const MethodChannel _channel = MethodChannel('qonversion_flutter_sdk'); diff --git a/pubspec.yaml b/pubspec.yaml index 3e63bc50..ceeaa533 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: qonversion_flutter description: In-App Subscription Infrastructure to grow your subscription business -version: 3.1.0 +version: 3.2.0 homepage: 'https://qonversion.io' repository: 'https://github.com/qonversion/flutter-sdk'