Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: rename android classes and method extensions #179

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can rename package to follow more conventional format, but I avoided doing it for now. Happy to make the change if we feel we should go for it.

pluginClass: CustomerIoPlugin
pluginClass: CustomerIOPlugin
ios:
pluginClass: CustomerIoPlugin
native_sdk_version: 3.5.1
Loading