diff --git a/android/build.gradle b/android/build.gradle index 08127ad..3462b05 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -58,7 +58,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" // Customer.io SDK - def cioVersion = "[3.4.2,4.0)" + def cioVersion = "[3.5.0,4.0)" implementation "io.customer.android:tracking:$cioVersion" implementation "io.customer.android:messaging-push-fcm:$cioVersion" implementation "io.customer.android:messaging-in-app:$cioVersion" diff --git a/android/src/main/kotlin/io/customer/customer_io/CustomerIoPlugin.kt b/android/src/main/kotlin/io/customer/customer_io/CustomerIoPlugin.kt index efc77f9..a6847ac 100644 --- a/android/src/main/kotlin/io/customer/customer_io/CustomerIoPlugin.kt +++ b/android/src/main/kotlin/io/customer/customer_io/CustomerIoPlugin.kt @@ -5,6 +5,7 @@ import android.app.Application import android.content.Context import androidx.annotation.NonNull import io.customer.customer_io.constant.Keys +import io.customer.customer_io.messaginginapp.CustomerIOInAppMessaging import io.customer.customer_io.messagingpush.CustomerIOPushMessaging import io.customer.messaginginapp.MessagingInAppModuleConfig import io.customer.messaginginapp.ModuleMessagingInApp @@ -42,7 +43,8 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { private lateinit var flutterCommunicationChannel: MethodChannel private lateinit var context: Context private var activity: WeakReference? = null - private lateinit var pushMessagingModule: CustomerIOPushMessaging + + private lateinit var modules: List private val logger: Logger get() = CustomerIOShared.instance().diStaticGraph.logger @@ -68,8 +70,17 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { flutterCommunicationChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "customer_io") flutterCommunicationChannel.setMethodCallHandler(this) - pushMessagingModule = CustomerIOPushMessaging(flutterPluginBinding) - pushMessagingModule.onAttachedToEngine() + + // Initialize modules + modules = listOf( + CustomerIOPushMessaging(flutterPluginBinding), + CustomerIOInAppMessaging(flutterPluginBinding) + ) + + // Attach modules to engine + modules.forEach { + it.onAttachedToEngine() + } } private fun MethodCall.toNativeMethodCall( @@ -275,7 +286,10 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { flutterCommunicationChannel.setMethodCallHandler(null) - pushMessagingModule.onDetachedFromEngine() + + modules.forEach { + it.onDetachedFromEngine() + } } } diff --git a/android/src/main/kotlin/io/customer/customer_io/constant/Keys.kt b/android/src/main/kotlin/io/customer/customer_io/constant/Keys.kt index 4a9a179..4f09b1a 100644 --- a/android/src/main/kotlin/io/customer/customer_io/constant/Keys.kt +++ b/android/src/main/kotlin/io/customer/customer_io/constant/Keys.kt @@ -13,6 +13,7 @@ internal object Keys { const val REGISTER_DEVICE_TOKEN = "registerDeviceToken" const val TRACK_METRIC = "trackMetric" const val ON_MESSAGE_RECEIVED = "onMessageReceived" + const val DISMISS_MESSAGE = "dismissMessage" } object Tracking { diff --git a/android/src/main/kotlin/io/customer/customer_io/messaginginapp/CustomerIOInAppMessaging.kt b/android/src/main/kotlin/io/customer/customer_io/messaginginapp/CustomerIOInAppMessaging.kt new file mode 100644 index 0000000..7e51ff5 --- /dev/null +++ b/android/src/main/kotlin/io/customer/customer_io/messaginginapp/CustomerIOInAppMessaging.kt @@ -0,0 +1,45 @@ +package io.customer.customer_io.messaginginapp + +import io.customer.customer_io.CustomerIOPluginModule +import io.customer.customer_io.constant.Keys +import io.customer.customer_io.invokeNative +import io.customer.messaginginapp.di.inAppMessaging +import io.customer.sdk.CustomerIO +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel + +/** + * Flutter module implementation for messaging in-app module in native SDKs. All functionality + * linked with the module should be placed here. + */ +internal class CustomerIOInAppMessaging( + pluginBinding: FlutterPlugin.FlutterPluginBinding, +) : CustomerIOPluginModule, MethodChannel.MethodCallHandler { + override val moduleName: String = "InAppMessaging" + private val flutterCommunicationChannel: MethodChannel = + MethodChannel(pluginBinding.binaryMessenger, "customer_io_messaging_in_app") + + override fun onAttachedToEngine() { + flutterCommunicationChannel.setMethodCallHandler(this) + } + + override fun onDetachedFromEngine() { + flutterCommunicationChannel.setMethodCallHandler(null) + } + + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + when (call.method) { + Keys.Methods.DISMISS_MESSAGE -> { + call.invokeNative(result) { + CustomerIO.instance().inAppMessaging().dismissMessage() + } + } + + else -> { + result.notImplemented() + } + } + } + +} \ No newline at end of file diff --git a/android/src/main/kotlin/io/customer/customer_io/messagingpush/CustomerIOPushMessaging.kt b/android/src/main/kotlin/io/customer/customer_io/messagingpush/CustomerIOPushMessaging.kt index 40133c7..f438d1c 100644 --- a/android/src/main/kotlin/io/customer/customer_io/messagingpush/CustomerIOPushMessaging.kt +++ b/android/src/main/kotlin/io/customer/customer_io/messagingpush/CustomerIOPushMessaging.kt @@ -46,6 +46,7 @@ internal class CustomerIOPushMessaging( ) } } + else -> { result.notImplemented() } diff --git a/ios/Classes/CustomerIOInAppMessaging.swift b/ios/Classes/CustomerIOInAppMessaging.swift new file mode 100644 index 0000000..187e97f --- /dev/null +++ b/ios/Classes/CustomerIOInAppMessaging.swift @@ -0,0 +1,38 @@ +import Foundation +import Flutter +import CioMessagingInApp + +public class CusomterIOInAppMessaging: NSObject, FlutterPlugin { + + private var methodChannel: FlutterMethodChannel! + + public static func register(with registrar: FlutterPluginRegistrar) { + } + + init(with registrar: FlutterPluginRegistrar) { + super.init() + + methodChannel = FlutterMethodChannel(name: "customer_io_messaging_in_app", binaryMessenger: registrar.messenger()) + registrar.addMethodCallDelegate(self, channel: methodChannel) + } + + + deinit { + methodChannel.setMethodCallHandler(nil) + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + // Handle method calls for this method channel + switch(call.method) { + case Keys.Methods.dismissMessage: + MessagingInApp.shared.dismissMessage() + default: + result(FlutterMethodNotImplemented) + } + } + + func detachFromEngine() { + methodChannel.setMethodCallHandler(nil) + methodChannel = nil + } +} diff --git a/ios/Classes/Keys.swift b/ios/Classes/Keys.swift index ab8936a..06f1f62 100644 --- a/ios/Classes/Keys.swift +++ b/ios/Classes/Keys.swift @@ -12,7 +12,7 @@ struct Keys { static let setProfileAttributes = "setProfileAttributes" static let registerDeviceToken = "registerDeviceToken" static let trackMetric = "trackMetric" - + static let dismissMessage = "dismissMessage" } struct Tracking { diff --git a/ios/Classes/SwiftCustomerIoPlugin.swift b/ios/Classes/SwiftCustomerIoPlugin.swift index 8dcbe82..4048341 100644 --- a/ios/Classes/SwiftCustomerIoPlugin.swift +++ b/ios/Classes/SwiftCustomerIoPlugin.swift @@ -7,59 +7,63 @@ import CioMessagingInApp public class SwiftCustomerIoPlugin: NSObject, FlutterPlugin { private var methodChannel: FlutterMethodChannel! + private var inAppMessagingChannelHandler: CusomterIOInAppMessaging! public static func register(with registrar: FlutterPluginRegistrar) { let instance = SwiftCustomerIoPlugin() instance.methodChannel = FlutterMethodChannel(name: "customer_io", binaryMessenger: registrar.messenger()) registrar.addMethodCallDelegate(instance, channel: instance.methodChannel) + + instance.inAppMessagingChannelHandler = CusomterIOInAppMessaging(with: registrar) } deinit { self.methodChannel.setMethodCallHandler(nil) + self.inAppMessagingChannelHandler.detachFromEngine() } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch(call.method) { - case Keys.Methods.initialize: - call.toNativeMethodCall( - result: result) { - initialize(params: $0) + case Keys.Methods.initialize: + call.toNativeMethodCall( + result: result) { + initialize(params: $0) + } + case Keys.Methods.clearIdentify: + clearIdentify() + case Keys.Methods.track: + call.toNativeMethodCall( + result: result) { + track(params: $0) + } + case Keys.Methods.screen: + call.toNativeMethodCall( + result: result) { + screen(params: $0) + } + case Keys.Methods.identify: + call.toNativeMethodCall( + result: result) { + identify(params: $0) + } + case Keys.Methods.setProfileAttributes: + call.toNativeMethodCall(result: result) { + setProfileAttributes(params: $0) } - case Keys.Methods.clearIdentify: - clearIdentify() - case Keys.Methods.track: - call.toNativeMethodCall( - result: result) { - track(params: $0) + case Keys.Methods.setDeviceAttributes: + call.toNativeMethodCall(result: result) { + setDeviceAttributes(params: $0) } - case Keys.Methods.screen: - call.toNativeMethodCall( - result: result) { - screen(params: $0) + case Keys.Methods.registerDeviceToken: + call.toNativeMethodCall(result: result) { + registerDeviceToken(params: $0) } - case Keys.Methods.identify: - call.toNativeMethodCall( - result: result) { - identify(params: $0) + case Keys.Methods.trackMetric: + call.toNativeMethodCall(result: result) { + trackMetric(params: $0) } - case Keys.Methods.setProfileAttributes: - call.toNativeMethodCall(result: result) { - setProfileAttributes(params: $0) - } - case Keys.Methods.setDeviceAttributes: - call.toNativeMethodCall(result: result) { - setDeviceAttributes(params: $0) - } - case Keys.Methods.registerDeviceToken: - call.toNativeMethodCall(result: result) { - registerDeviceToken(params: $0) - } - case Keys.Methods.trackMetric: - call.toNativeMethodCall(result: result) { - trackMetric(params: $0) - } - default: - result(FlutterMethodNotImplemented) + default: + result(FlutterMethodNotImplemented) } } @@ -165,7 +169,7 @@ public class SwiftCustomerIoPlugin: NSObject, FlutterPlugin { config.modify(params: params) } - + if let enableInApp = params[Keys.Environment.enableInApp] as? Bool { if enableInApp{ initializeInApp() diff --git a/ios/customer_io.podspec b/ios/customer_io.podspec index efaa1b0..aa67e82 100755 --- a/ios/customer_io.podspec +++ b/ios/customer_io.podspec @@ -4,7 +4,7 @@ # Pod::Spec.new do |s| s.name = 'customer_io' - s.version = '1.1.2' + s.version = '1.2.0' s.summary = 'Customer.io plugin for Flutter' s.homepage = 'https://customer.io/' s.license = { :file => '../LICENSE' } diff --git a/lib/customer_io.dart b/lib/customer_io.dart index e74b94c..41bc593 100644 --- a/lib/customer_io.dart +++ b/lib/customer_io.dart @@ -4,6 +4,7 @@ import 'customer_io_config.dart'; import 'customer_io_enums.dart'; import 'customer_io_inapp.dart'; import 'customer_io_platform_interface.dart'; +import 'messaging_in_app/platform_interface.dart'; import 'messaging_push/platform_interface.dart'; class CustomerIO { @@ -14,6 +15,9 @@ class CustomerIO { static CustomerIOMessagingPushPlatform get _customerIOMessagingPush => CustomerIOMessagingPushPlatform.instance; + static CustomerIOMessagingInAppPlatform get _customerIOMessagingInApp => + CustomerIOMessagingInAppPlatform.instance; + /// To initialize the plugin /// /// @param config includes required and optional configs etc @@ -108,4 +112,8 @@ class CustomerIO { static CustomerIOMessagingPushPlatform messagingPush() { return _customerIOMessagingPush; } + + static CustomerIOMessagingInAppPlatform messagingInApp() { + return _customerIOMessagingInApp; + } } diff --git a/lib/customer_io_const.dart b/lib/customer_io_const.dart index 92d2a06..b7dfa58 100644 --- a/lib/customer_io_const.dart +++ b/lib/customer_io_const.dart @@ -9,6 +9,7 @@ class MethodConsts { static const String setProfileAttributes = "setProfileAttributes"; static const String registerDeviceToken = "registerDeviceToken"; static const String onMessageReceived = "onMessageReceived"; + static const String dismissMessage = "dismissMessage"; } class TrackingConsts { diff --git a/lib/customer_io_plugin_version.dart b/lib/customer_io_plugin_version.dart index 800db07..467bf5a 100755 --- a/lib/customer_io_plugin_version.dart +++ b/lib/customer_io_plugin_version.dart @@ -1,2 +1,2 @@ // Don't modify this line - it's automatically updated -const version = "1.1.2"; +const version = "1.2.0"; diff --git a/lib/messaging_in_app/method_channel.dart b/lib/messaging_in_app/method_channel.dart new file mode 100644 index 0000000..cd5a046 --- /dev/null +++ b/lib/messaging_in_app/method_channel.dart @@ -0,0 +1,29 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; + +import '../customer_io_const.dart'; +import 'platform_interface.dart'; + +/// An implementation of [CustomerIOMessagingInAppPlatform] that uses method +/// channels. +class CustomerIOMessagingInAppMethodChannel + extends CustomerIOMessagingInAppPlatform { + /// The method channel used to interact with the native platform. + @visibleForTesting + final methodChannel = const MethodChannel('customer_io_messaging_in_app'); + + @override + void dismissMessage() async { + try { + methodChannel.invokeMethod(MethodConsts.dismissMessage); + } on PlatformException catch (e) { + handleException(e); + } + } + + void handleException(PlatformException exception) { + if (kDebugMode) { + print(exception); + } + } +} diff --git a/lib/messaging_in_app/platform_interface.dart b/lib/messaging_in_app/platform_interface.dart new file mode 100644 index 0000000..b05daf7 --- /dev/null +++ b/lib/messaging_in_app/platform_interface.dart @@ -0,0 +1,30 @@ +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +import 'method_channel.dart'; + +/// The default instance of [CustomerIOMessagingInAppPlatform] to use +/// +/// Platform-specific plugins should override this with their own +/// platform-specific class that extends [CustomerIOMessagingInAppPlatform] +/// when they register themselves. +/// +/// Defaults to [CustomerIOMessagingInAppMethodChannel] +abstract class CustomerIOMessagingInAppPlatform extends PlatformInterface { + CustomerIOMessagingInAppPlatform() : super(token: _token); + + static final Object _token = Object(); + + static CustomerIOMessagingInAppPlatform _instance = + CustomerIOMessagingInAppMethodChannel(); + + static CustomerIOMessagingInAppPlatform get instance => _instance; + + static set instance(CustomerIOMessagingInAppPlatform instance) { + PlatformInterface.verifyToken(instance, _token); + _instance = instance; + } + + void dismissMessage() { + throw UnimplementedError('dismissMessage() has not been implemented.'); + } +}