Skip to content

Commit

Permalink
chore: rename android classes and method extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
mrehan27 committed Nov 25, 2024
1 parent bd03be8 commit 577eed9
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,6 @@ package io.customer.customer_io
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel

/**
* Returns the value corresponding to the given key after casting to the generic type provided, or
* null if such key is not present in the map or value cannot be casted to the given type.
*/
internal inline fun <reified T> Map<String, Any>.getAsTypeOrNull(key: String): T? {
if (containsKey(key)) {
return get(key) as? T
}
return null
}

/**
* Invokes lambda method that can be used to call matching native method conveniently. The lambda
* expression receives function parameters as arguments and should return the desired result. Any
Expand Down
57 changes: 29 additions & 28 deletions android/src/main/kotlin/io/customer/customer_io/CustomerIoPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package io.customer.customer_io
import android.app.Application
import android.content.Context
import androidx.annotation.NonNull
import io.customer.customer_io.bridge.NativeModuleBridge
import io.customer.customer_io.constant.Keys
import io.customer.customer_io.messaginginapp.CustomerIOInAppMessaging
import io.customer.customer_io.messagingpush.CustomerIOPushMessaging
import io.customer.customer_io.utils.getAs
import io.customer.sdk.CustomerIO
import io.customer.sdk.CustomerIOBuilder
import io.customer.sdk.core.di.SDKComponent
Expand All @@ -26,15 +28,15 @@ import io.flutter.plugin.common.MethodChannel.Result
* Android implementation of plugin that will let Flutter developers to
* interact with a Android platform
* */
class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
class CustomerIOPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var flutterCommunicationChannel: MethodChannel
private lateinit var context: Context

private lateinit var modules: List<CustomerIOPluginModule>
private lateinit var modules: List<NativeModuleBridge>

private val logger: Logger = SDKComponent.logger

Expand Down Expand Up @@ -133,8 +135,8 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}

private fun identify(params: Map<String, Any>) {
val userId = params.getAsTypeOrNull<String>(Keys.Tracking.USER_ID)
val traits = params.getAsTypeOrNull<Map<String, Any>>(Keys.Tracking.TRAITS) ?: emptyMap()
val userId = params.getAs<String>(Keys.Tracking.USER_ID)
val traits = params.getAs<Map<String, Any>>(Keys.Tracking.TRAITS) ?: emptyMap()

if (userId == null && traits.isEmpty()) {
logger.error("Please provide either an ID or traits to identify.")
Expand All @@ -151,10 +153,10 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}

private fun track(params: Map<String, Any>) {
val name = requireNotNull(params.getAsTypeOrNull<String>(Keys.Tracking.NAME)) {
val name = requireNotNull(params.getAs<String>(Keys.Tracking.NAME)) {
"Event name is missing in params: $params"
}
val properties = params.getAsTypeOrNull<Map<String, Any>>(Keys.Tracking.PROPERTIES)
val properties = params.getAs<Map<String, Any>>(Keys.Tracking.PROPERTIES)

if (properties.isNullOrEmpty()) {
CustomerIO.instance().track(name)
Expand All @@ -164,16 +166,16 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}

private fun registerDeviceToken(params: Map<String, Any>) {
val token = requireNotNull(params.getAsTypeOrNull<String>(Keys.Tracking.TOKEN)) {
val token = requireNotNull(params.getAs<String>(Keys.Tracking.TOKEN)) {
"Device token is missing in params: $params"
}
CustomerIO.instance().registerDeviceToken(token)
}

private fun trackMetric(params: Map<String, Any>) {
val deliveryId = params.getAsTypeOrNull<String>(Keys.Tracking.DELIVERY_ID)
val deliveryToken = params.getAsTypeOrNull<String>(Keys.Tracking.DELIVERY_TOKEN)
val eventName = params.getAsTypeOrNull<String>(Keys.Tracking.METRIC_EVENT)
val deliveryId = params.getAs<String>(Keys.Tracking.DELIVERY_ID)
val deliveryToken = params.getAs<String>(Keys.Tracking.DELIVERY_TOKEN)
val eventName = params.getAs<String>(Keys.Tracking.METRIC_EVENT)

if (deliveryId == null || deliveryToken == null || eventName == null) {
throw IllegalArgumentException("Missing required parameters")
Expand All @@ -191,7 +193,7 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}

private fun setDeviceAttributes(params: Map<String, Any>) {
val attributes = params.getAsTypeOrNull<Map<String, Any>>(Keys.Tracking.ATTRIBUTES)
val attributes = params.getAs<Map<String, Any>>(Keys.Tracking.ATTRIBUTES)

if (attributes.isNullOrEmpty()) {
logger.error("Device attributes are missing in params: $params")
Expand All @@ -202,7 +204,7 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}

private fun setProfileAttributes(params: Map<String, Any>) {
val attributes = params.getAsTypeOrNull<Map<String, Any>>(Keys.Tracking.ATTRIBUTES)
val attributes = params.getAs<Map<String, Any>>(Keys.Tracking.ATTRIBUTES)

if (attributes.isNullOrEmpty()) {
logger.error("Profile attributes are missing in params: $params")
Expand All @@ -213,10 +215,10 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}

private fun screen(params: Map<String, Any>) {
val title = requireNotNull(params.getAsTypeOrNull<String>(Keys.Tracking.TITLE)) {
val title = requireNotNull(params.getAs<String>(Keys.Tracking.TITLE)) {
"Screen title is missing in params: $params"
}
val properties = params.getAsTypeOrNull<Map<String, Any>>(Keys.Tracking.PROPERTIES)
val properties = params.getAs<Map<String, Any>>(Keys.Tracking.PROPERTIES)

if (properties.isNullOrEmpty()) {
CustomerIO.instance().screen(title)
Expand All @@ -227,12 +229,12 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {

private fun initialize(args: Map<String, Any>): kotlin.Result<Unit> = runCatching {
val application: Application = context.applicationContext as Application
val cdpApiKey = requireNotNull(args.getAsTypeOrNull<String>("cdpApiKey")) {
val cdpApiKey = requireNotNull(args.getAs<String>("cdpApiKey")) {
"CDP API Key is required to initialize Customer.io"
}

val logLevelRawValue = args.getAsTypeOrNull<String>("logLevel")
val regionRawValue = args.getAsTypeOrNull<String>("region")
val logLevelRawValue = args.getAs<String>("logLevel")
val regionRawValue = args.getAs<String>("region")
val givenRegion = regionRawValue.let { Region.getRegion(it) }

CustomerIOBuilder(
Expand All @@ -242,28 +244,27 @@ class CustomerIoPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
logLevelRawValue?.let { logLevel(CioLogLevel.getLogLevel(it)) }
regionRawValue?.let { region(givenRegion) }

args.getAsTypeOrNull<String>("migrationSiteId")?.let(::migrationSiteId)
args.getAsTypeOrNull<Boolean>("autoTrackDeviceAttributes")
?.let(::autoTrackDeviceAttributes)
args.getAsTypeOrNull<Boolean>("trackApplicationLifecycleEvents")
args.getAs<String>("migrationSiteId")?.let(::migrationSiteId)
args.getAs<Boolean>("autoTrackDeviceAttributes")?.let(::autoTrackDeviceAttributes)
args.getAs<Boolean>("trackApplicationLifecycleEvents")
?.let(::trackApplicationLifecycleEvents)

args.getAsTypeOrNull<Int>("flushAt")?.let(::flushAt)
args.getAsTypeOrNull<Int>("flushInterval")?.let(::flushInterval)
args.getAs<Int>("flushAt")?.let(::flushAt)
args.getAs<Int>("flushInterval")?.let(::flushInterval)

args.getAsTypeOrNull<String>("apiHost")?.let(::apiHost)
args.getAsTypeOrNull<String>("cdnHost")?.let(::cdnHost)
args.getAs<String>("apiHost")?.let(::apiHost)
args.getAs<String>("cdnHost")?.let(::cdnHost)
// Configure in-app messaging module based on config provided by customer app
args.getAsTypeOrNull<Map<String, Any>>(key = "inApp")?.let { inAppConfig ->
args.getAs<Map<String, Any>>(key = "inApp")?.let { inAppConfig ->
modules.filterIsInstance<CustomerIOInAppMessaging>().forEach {
it.configureModule(
builder = this,
config = inAppConfig.plus("region" to givenRegion),
config = inAppConfig.plus("region" to givenRegion.code),
)
}
}
// Configure push messaging module based on config provided by customer app
args.getAsTypeOrNull<Map<String, Any>>(key = "push").let { pushConfig ->
args.getAs<Map<String, Any>>(key = "push").let { pushConfig ->
modules.filterIsInstance<CustomerIOPushMessaging>().forEach {
it.configureModule(
builder = this,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.customer.customer_io
package io.customer.customer_io.bridge

import io.customer.sdk.CustomerIOBuilder
import io.flutter.embedding.engine.plugins.FlutterPlugin
Expand All @@ -11,7 +11,7 @@ import io.flutter.plugin.common.MethodChannel
* should be treated as module in Flutter SDK and should be used to hold all relevant methods at
* single place.
*/
internal interface CustomerIOPluginModule : MethodChannel.MethodCallHandler, ActivityAware {
internal interface NativeModuleBridge : MethodChannel.MethodCallHandler, ActivityAware {
/**
* Unique name of module to identify between other modules
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package io.customer.customer_io.messaginginapp

import android.app.Activity
import io.customer.customer_io.CustomerIOPluginModule
import io.customer.customer_io.bridge.NativeModuleBridge
import io.customer.customer_io.constant.Keys
import io.customer.customer_io.getAsTypeOrNull
import io.customer.customer_io.invokeNative
import io.customer.customer_io.utils.getAs
import io.customer.messaginginapp.MessagingInAppModuleConfig
import io.customer.messaginginapp.ModuleMessagingInApp
import io.customer.messaginginapp.di.inAppMessaging
Expand All @@ -27,7 +27,7 @@ import java.lang.ref.WeakReference
*/
internal class CustomerIOInAppMessaging(
pluginBinding: FlutterPlugin.FlutterPluginBinding,
) : CustomerIOPluginModule, MethodChannel.MethodCallHandler, ActivityAware {
) : NativeModuleBridge, MethodChannel.MethodCallHandler, ActivityAware {
override val moduleName: String = "InAppMessaging"
override val flutterCommunicationChannel: MethodChannel =
MethodChannel(pluginBinding.binaryMessenger, "customer_io_messaging_in_app")
Expand Down Expand Up @@ -74,8 +74,8 @@ internal class CustomerIOInAppMessaging(
builder: CustomerIOBuilder,
config: Map<String, Any>
) {
val siteId = config.getAsTypeOrNull<String>("siteId")
val regionRawValue = config.getAsTypeOrNull<String>("region")
val siteId = config.getAs<String>("siteId")
val regionRawValue = config.getAs<String>("region")
val givenRegion = regionRawValue.let { Region.getRegion(it) }

if (siteId.isNullOrBlank()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package io.customer.customer_io.messagingpush

import android.content.Context
import io.customer.customer_io.CustomerIOPluginModule
import io.customer.customer_io.bridge.NativeModuleBridge
import io.customer.customer_io.constant.Keys
import io.customer.customer_io.getAsTypeOrNull
import io.customer.customer_io.invokeNative
import io.customer.customer_io.utils.getAs
import io.customer.customer_io.utils.takeIfNotBlank
import io.customer.messagingpush.CustomerIOFirebaseMessagingService
import io.customer.messagingpush.MessagingPushModuleConfig
import io.customer.messagingpush.ModuleMessagingPushFCM
Expand All @@ -16,15 +17,15 @@ import io.customer.sdk.core.util.Logger
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import java.util.*
import java.util.UUID

/**
* Flutter module implementation for messaging push module in native SDKs. All functionality
* linked with the module should be placed here.
*/
internal class CustomerIOPushMessaging(
pluginBinding: FlutterPlugin.FlutterPluginBinding,
) : CustomerIOPluginModule, MethodChannel.MethodCallHandler {
) : NativeModuleBridge, MethodChannel.MethodCallHandler {
override val moduleName: String = "PushMessaging"
private val applicationContext: Context = pluginBinding.applicationContext
override val flutterCommunicationChannel: MethodChannel =
Expand All @@ -42,8 +43,8 @@ internal class CustomerIOPushMessaging(
Keys.Methods.ON_MESSAGE_RECEIVED -> {
call.invokeNative(result) { args ->
return@invokeNative onMessageReceived(
message = args.getAsTypeOrNull<Map<String, Any>>("message"),
handleNotificationTrigger = args.getAsTypeOrNull<Boolean>("handleNotificationTrigger")
message = args.getAs<Map<String, Any>>("message"),
handleNotificationTrigger = args.getAs<Boolean>("handleNotificationTrigger")
)
}
}
Expand Down Expand Up @@ -75,8 +76,8 @@ internal class CustomerIOPushMessaging(
}

// Generate destination string, see docs on receiver method for more details
val destination = (message["to"] as? String)?.takeIf { it.isNotBlank() }
?: UUID.randomUUID().toString()
val destination =
(message["to"] as? String)?.takeIfNotBlank() ?: UUID.randomUUID().toString()
return CustomerIOFirebaseMessagingService.onMessageReceived(
context = applicationContext,
remoteMessage = message.toFCMRemoteMessage(destination = destination),
Expand All @@ -99,14 +100,13 @@ internal class CustomerIOPushMessaging(
builder: CustomerIOBuilder,
config: Map<String, Any>
) {
val androidConfig =
config.getAsTypeOrNull<Map<String, Any>>(key = "android") ?: emptyMap()
val androidConfig = config.getAs<Map<String, Any>>(key = "android") ?: emptyMap()
// Prefer `android` object for push configurations as it's more specific to Android
// For common push configurations, use `config` object instead of `android`

// Default push click behavior is to prevent restart of activity in Flutter apps
val pushClickBehavior = androidConfig.getAsTypeOrNull<String>("pushClickBehavior")
?.takeIf { it.isNotBlank() }
val pushClickBehavior = androidConfig.getAs<String>("pushClickBehavior")
?.takeIfNotBlank()
?.let { value ->
runCatching { enumValueOf<PushClickBehavior>(value) }.getOrNull()
} ?: PushClickBehavior.ACTIVITY_PREVENT_RESTART
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.customer.customer_io.messagingpush

import com.google.firebase.messaging.RemoteMessage
import io.customer.customer_io.getAsTypeOrNull
import io.customer.customer_io.utils.getAs

/**
* Safely transforms any value to string
Expand All @@ -23,8 +23,8 @@ private fun Any.toStringOrNull(): String? = try {
* string for it.
*/
internal fun Map<String, Any>.toFCMRemoteMessage(destination: String): RemoteMessage {
val notification = getAsTypeOrNull<Map<String, Any>>("notification")
val data = getAsTypeOrNull<Map<String, Any>>("data")
val notification = getAs<Map<String, Any>>("notification")
val data = getAs<Map<String, Any>>("data")
val messageParams = buildMap {
notification?.let { result -> putAll(result) }
// Adding `data` after `notification` so `data` params take more value as we mainly use
Expand All @@ -42,10 +42,10 @@ internal fun Map<String, Any>.toFCMRemoteMessage(destination: String): RemoteMes
value.toStringOrNull()?.let { v -> addData(key, v) }
}
}
getAsTypeOrNull<String>("messageId")?.let { id -> setMessageId(id) }
getAsTypeOrNull<String>("messageType")?.let { type -> setMessageType(type) }
getAsTypeOrNull<String>("collapseKey")?.let { key -> setCollapseKey(key) }
getAsTypeOrNull<Int>("ttl")?.let { time -> ttl = time }
getAs<String>("messageId")?.let { id -> setMessageId(id) }
getAs<String>("messageType")?.let { type -> setMessageType(type) }
getAs<String>("collapseKey")?.let { key -> setCollapseKey(key) }
getAs<Int>("ttl")?.let { time -> ttl = time }
return@with build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.customer.customer_io.utils

/**
* Returns the value corresponding to the given key after casting to the generic type provided, or
* null if such key is not present in the map or value cannot be casted to the given type.
*/
internal inline fun <reified T> Map<String, Any>.getAs(key: String): T? {
if (containsKey(key)) {
return get(key) as? T
}
return null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.customer.customer_io.utils

/**
* Extension function to return the string if it is not null or blank.
*/
internal fun String?.takeIfNotBlank(): String? = takeIf { !it.isNullOrBlank() }
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ flutter:
platforms:
android:
package: io.customer.customer_io
pluginClass: CustomerIoPlugin
pluginClass: CustomerIOPlugin
ios:
pluginClass: CustomerIoPlugin
native_sdk_version: 3.5.1

0 comments on commit 577eed9

Please sign in to comment.