Skip to content

Commit

Permalink
feat: tracking and in-app added (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
Shahroz16 authored Dec 5, 2022
1 parent 2589675 commit c23f2d9
Show file tree
Hide file tree
Showing 16 changed files with 515 additions and 94 deletions.
160 changes: 127 additions & 33 deletions android/src/main/kotlin/io/customer/customer_io/CustomerIoPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.content.Context
import androidx.annotation.NonNull
import io.customer.customer_io.constant.Keys
import io.customer.customer_io.extension.*
import io.customer.messaginginapp.ModuleMessagingInApp
import io.customer.sdk.CustomerIO
import io.customer.sdk.CustomerIOShared
import io.customer.sdk.data.store.Client
Expand All @@ -19,7 +20,7 @@ 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 {
class CustomerIoPlugin : FlutterPlugin, MethodCallHandler {
/// 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
Expand All @@ -28,56 +29,149 @@ class CustomerIOPlugin : FlutterPlugin, MethodCallHandler {
private lateinit var context: Context

private val logger: Logger
get() = CustomerIOShared.instance().diGraph.logger
get() = CustomerIOShared.instance().diStaticGraph.logger

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
context = flutterPluginBinding.applicationContext
flutterCommunicationChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "customer_io")
flutterCommunicationChannel =
MethodChannel(flutterPluginBinding.binaryMessenger, "customer_io")
flutterCommunicationChannel.setMethodCallHandler(this)
}

private fun MethodCall.toNativeMethodCall(
result: Result,
performAction: (params: Map<String, Any>) -> Unit
) {
try {
val params = this.arguments as? Map<String, Any> ?: emptyMap()
performAction(params)
result.success(true)
} catch (e: Exception) {
result.error(this.method, e.localizedMessage, null);
}
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
when (call.method) {
"getPlatformVersion" -> {
result.success("Android-${android.os.Build.VERSION.RELEASE}")
Keys.Methods.INITIALIZE -> {
call.toNativeMethodCall(result) {
initialize(it)
}
}
Keys.Methods.IDENTIFY -> {
call.toNativeMethodCall(result) {
identify(it)
}
}
Keys.Methods.SCREEN -> {
call.toNativeMethodCall(result) {
screen(it)
}
}
Keys.Methods.TRACK -> {
call.toNativeMethodCall(result) {
track(it)
}
}
"initialize" -> {
initialize(call, result)
Keys.Methods.SET_DEVICE_ATTRIBUTES -> {
call.toNativeMethodCall(result) {
setDeviceAttributes(it)
}
}
Keys.Methods.SET_PROFILE_ATTRIBUTES -> {
call.toNativeMethodCall(result) {
setProfileAttributes(it)
}
}
Keys.Methods.CLEAR_IDENTIFY -> {
clearIdentity()
}

else -> {
result.notImplemented()
}
}
}

private fun clearIdentity() {
CustomerIO.instance().clearIdentify()
}

private fun initialize(call: MethodCall, result: Result) {
try {
val application: Application = context.applicationContext as Application
val configData = call.arguments as? Map<String, Any> ?: emptyMap()
val siteId = configData.getString(Keys.Environment.SITE_ID)
val apiKey = configData.getString(Keys.Environment.API_KEY)
val region = configData.getProperty<String>(
Keys.Environment.REGION
)?.takeIfNotBlank().toRegion()

CustomerIO.Builder(
siteId = siteId,
apiKey = apiKey,
region = region,
appContext = application,
).apply {
setClient(client = getUserAgentClient(packageConfig = configData))
setupConfig(configData)
}.build()
logger.info("Customer.io instance initialized successfully")
result.success(true)
} catch (e: Exception) {
logger.error("Failed to initialize Customer.io instance from app, ${e.message}")
result.error("FlutterSegmentException", e.localizedMessage, null);
private fun identify(params: Map<String, Any>) {
val identifier = params.getString(Keys.Tracking.IDENTIFIER)
val attributes =
params.getProperty<Map<String, Any>>(Keys.Tracking.ATTRIBUTES) ?: emptyMap()
CustomerIO.instance().identify(identifier, attributes)
}

fun track(params: Map<String, Any>) {
val name = params.getString(Keys.Tracking.EVENT_NAME)
val attributes =
params.getProperty<Map<String, Any>>(Keys.Tracking.ATTRIBUTES) ?: emptyMap()

if (attributes.isEmpty()) {
CustomerIO.instance().track(name)
} else {
CustomerIO.instance().track(name, attributes)
}
}

fun setDeviceAttributes(params: Map<String, Any>) {
val attributes =
params.getProperty<Map<String, Any>>(Keys.Tracking.ATTRIBUTES) ?: emptyMap()

CustomerIO.instance().deviceAttributes = attributes
}

fun setProfileAttributes(params: Map<String, Any>) {
val attributes =
params.getProperty<Map<String, Any>>(Keys.Tracking.ATTRIBUTES) ?: return

CustomerIO.instance().profileAttributes = attributes
}

fun screen(params: Map<String, Any>) {
val name = params.getString(Keys.Tracking.EVENT_NAME)
val attributes =
params.getProperty<Map<String, Any>>(Keys.Tracking.ATTRIBUTES) ?: emptyMap()

if (attributes.isEmpty()) {
CustomerIO.instance().screen(name)
} else {
CustomerIO.instance().screen(name, attributes)
}
}

private fun initialize(configData: Map<String, Any>) {
val application: Application = context.applicationContext as Application
val siteId = configData.getString(Keys.Environment.SITE_ID)
val apiKey = configData.getString(Keys.Environment.API_KEY)
val region = configData.getProperty<String>(
Keys.Environment.REGION
)?.takeIfNotBlank().toRegion()
val organizationId = configData.getProperty<String>(
Keys.Environment.ORGANIZATION_ID
)?.takeIfNotBlank()

CustomerIO.Builder(
siteId = siteId,
apiKey = apiKey,
region = region,
appContext = application,
).apply {
setClient(client = getUserAgentClient(packageConfig = configData))
setupConfig(configData)
if (!organizationId.isNullOrBlank()) {
addCustomerIOModule(
module = ModuleMessagingInApp(
organizationId = organizationId,
)
)
}
}.build()
logger.info("Customer.io instance initialized successfully")
}

private fun getUserAgentClient(packageConfig: Map<String, Any?>?): Client {
val sourceSDKVersion = packageConfig?.getProperty<String>(
Keys.PackageConfig.SOURCE_SDK_VERSION
Expand All @@ -96,8 +190,8 @@ class CustomerIOPlugin : FlutterPlugin, MethodCallHandler {
config.getProperty<Boolean>(Keys.Config.AUTO_TRACK_DEVICE_ATTRIBUTES)?.let { value ->
autoTrackDeviceAttributes(shouldTrackDeviceAttributes = value)
}
config.getProperty<Double>(Keys.Config.BACKGROUND_QUEUE_MIN_NUMBER_OF_TASKS)?.let { value ->
setBackgroundQueueMinNumberOfTasks(backgroundQueueMinNumberOfTasks = value.toInt())
config.getProperty<Int>(Keys.Config.BACKGROUND_QUEUE_MIN_NUMBER_OF_TASKS)?.let { value ->
setBackgroundQueueMinNumberOfTasks(backgroundQueueMinNumberOfTasks = value)
}
config.getProperty<Double>(Keys.Config.BACKGROUND_QUEUE_SECONDS_DELAY)?.let { value ->
setBackgroundQueueSecondsDelay(backgroundQueueSecondsDelay = value)
Expand Down
17 changes: 17 additions & 0 deletions android/src/main/kotlin/io/customer/customer_io/constant/Keys.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
package io.customer.customer_io.constant

internal object Keys {

object Methods {
const val INITIALIZE = "initialize"
const val IDENTIFY = "identify"
const val CLEAR_IDENTIFY = "clearIdentify"
const val TRACK = "track"
const val SCREEN = "screen"
const val SET_DEVICE_ATTRIBUTES = "setDeviceAttributes"
const val SET_PROFILE_ATTRIBUTES = "setProfileAttributes"
}

object Tracking {
const val IDENTIFIER = "identifier"
const val ATTRIBUTES = "attributes"
const val EVENT_NAME = "eventName"
}

object Environment {
const val SITE_ID = "siteId"
const val API_KEY = "apiKey"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal inline fun <reified T> Map<String, Any?>.getPropertyUnsafe(key: String)
internal inline fun <reified T> Map<String, Any?>.getProperty(key: String): T? = try {
getPropertyUnsafe(key)
} catch (ex: IllegalArgumentException) {
CustomerIOShared.instance().diGraph.logger.error(
CustomerIOShared.instance().diStaticGraph.logger.error(
ex.message ?: "getProperty($key) -> IllegalArgumentException"
)
null
Expand All @@ -29,7 +29,7 @@ internal fun Map<String, Any?>.getString(key: String): String = try {
"Invalid value provided for $key, must not be blank"
)
} catch (ex: IllegalArgumentException) {
CustomerIOShared.instance().diGraph.logger.error(
CustomerIOShared.instance().diStaticGraph.logger.error(
ex.message ?: "getString($key) -> IllegalArgumentException"
)
throw ex
Expand Down
27 changes: 16 additions & 11 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
PODS:
- customer_io (0.0.1):
- CustomerIO/Tracking
- CustomerIOMessagingInApp (~> 1.2.6)
- CustomerIOTracking (~> 1.2.6)
- Flutter
- CustomerIO/Tracking (1.2.2):
- CustomerIOTracking (= 1.2.2)
- CustomerIOCommon (1.2.2)
- CustomerIOTracking (1.2.2):
- CustomerIOCommon (= 1.2.2)
- CustomerIOCommon (1.2.6)
- CustomerIOMessagingInApp (1.2.6):
- CustomerIOTracking (= 1.2.6)
- Gist (~> 2.2.1)
- CustomerIOTracking (1.2.6):
- CustomerIOCommon (= 1.2.6)
- Flutter (1.0.0)
- Gist (2.2.2)

DEPENDENCIES:
- customer_io (from `.symlinks/plugins/customer_io/ios`)
- Flutter (from `Flutter`)

SPEC REPOS:
trunk:
- CustomerIO
- CustomerIOCommon
- CustomerIOMessagingInApp
- CustomerIOTracking
- Gist

EXTERNAL SOURCES:
customer_io:
Expand All @@ -26,11 +30,12 @@ EXTERNAL SOURCES:
:path: Flutter

SPEC CHECKSUMS:
customer_io: 99ae280180a2fe4c0514f28a8da5e7a66734a612
CustomerIO: 0a31ad1baed6cd952469b9098e2e73fa96cec70e
CustomerIOCommon: 3bf82c3574205819a69baa1f0bc5b47671dd2d19
CustomerIOTracking: 101dc8c25eff807eadc8fbcf83b76f98fb5832a5
customer_io: 1d87e347f5413fd849e9b185be08d3d0b4de16b8
CustomerIOCommon: a427cf053f8effbaafc715c151342732c0f8d4b3
CustomerIOMessagingInApp: 34505598985348b913d10cbdc9cdd288bff715b5
CustomerIOTracking: 52a97a4d8f5adb789add4439f3e483907c6d475e
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
Gist: 3269391440cbe3637db6733964dd53ea32a3ce56

PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

Expand Down
11 changes: 7 additions & 4 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1410;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
Expand Down Expand Up @@ -321,6 +321,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
Expand All @@ -339,7 +340,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
Expand Down Expand Up @@ -394,6 +395,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
Expand All @@ -418,7 +420,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -449,6 +451,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
Expand All @@ -467,7 +470,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1410"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Loading

0 comments on commit c23f2d9

Please sign in to comment.