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

feat: send impression and push primer analytics events (RMCCX-6936, RMCCX-6937) #389

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
@@ -0,0 +1,7 @@
package com.rakuten.tech.mobile.analytics

class RatTracker {
companion object {
fun event(type: String, parameters: Map<String, Any>): Event = Event(type, parameters)
}
}
2 changes: 2 additions & 0 deletions inappmessaging/USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ All the events "launch the app event, login event, purchase successful event, cu
- RMCCX-6711: Supported redirecting to App Notification Settings on tapping PushPrimer button action.
- RMCCX-6706: Prevented showing Push Primer campaign for unsupported devices (Android 12 and below) and when push permission is granted.
- RMCCX-6711: Limited CustomJson feature to RMC SDK.
- RMCCX-6936: Supported sending `_rem_rmc_iam_impressions` event to app and SDK RAT accounts upon impression.
- RMCCX-6937: Supported sending `_rem_rmc_iam_pushprimer` event to app and SDK RAT accounts upon selection from the native push permission prompt.

#### 7.5.0 (2023-12-12)
* SDKCF-6575: Added sending of device Id in all IAM requests.
Expand Down
3 changes: 3 additions & 0 deletions inappmessaging/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ android {
resValue 'string', 'inappmessaging__version', project.version
versionName version
consumerProguardFiles 'proguard-rules.pro'

buildConfigField("boolean", "IS_CACHE_HANDLING", "true")
buildConfigField("String","VERSION_NAME","\"${defaultConfig.versionName}\"")
buildConfigField("int", "IAM_RAT_ACC", CONFIG.property("IAM_RAT_ACC"))
buildConfigField("int", "IAM_RAT_AID", CONFIG.property("IAM_RAT_AID"))

resValue("string", "config_url", CONFIG.property("CONFIG_URL_TEST_PROD") ?: "")
resValue("string", "test_sub_key", CONFIG.property("IAM_TEST_SUBSCRIPTION_KEY") ?: "test_sub_key")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package com.rakuten.tech.mobile.inappmessaging.runtime

import android.text.TextUtils
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.ClassUtil
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger

internal object EventTrackerHelper {

private const val TAG = "EventTrackerHelper"

/**
* This method sends event data to Analytics module for processing.
* This method will only send the analytics event when the real Event class exists at
Expand All @@ -15,6 +18,8 @@ internal object EventTrackerHelper {
* @param data the given Event parameters to be tracked.
* @return true if the analytics event has been sent, false otherwise.
*/
@SuppressWarnings("TooGenericExceptionCaught")
@JvmStatic
fun sendEvent(eventName: String, data: Map<String, *>?): Boolean {
if (!TextUtils.isEmpty(eventName)) {
val serializableData: HashMap<String, *> = when (data) {
Expand All @@ -23,9 +28,13 @@ internal object EventTrackerHelper {
else -> HashMap(data)
}

if (ClassUtil.hasClass("com.rakuten.tech.mobile.analytics.Event")) {
com.rakuten.tech.mobile.analytics.Event(eventName, serializableData).track()
return true
if (ClassUtil.hasClass("com.rakuten.tech.mobile.analytics.RatTracker")) {
try {
com.rakuten.tech.mobile.analytics.RatTracker.event(eventName, serializableData).track()
return true
} catch (e: Exception) {
InAppLogger(TAG).warn("Could not send event: $e")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.annotation.RestrictTo
import androidx.annotation.RestrictTo.Scope.LIBRARY
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.EventType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.Attribute
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.AnalyticsKey
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants
import org.jetbrains.annotations.NotNull
import java.util.Locale
Expand Down Expand Up @@ -72,8 +73,8 @@ abstract class BaseEvent(
@NotNull
override fun getRatEventMap(): Map<String, Any> {
val map = HashMap<String, Any>()
map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_NAME] = eventName
map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_TIMESTAMP] = timestamp
map[AnalyticsKey.EVENT_NAME.key] = eventName
map[AnalyticsKey.TIMESTAMP.key] = timestamp
return Collections.unmodifiableMap(map)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.EventType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.ValueType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.Attribute
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.rat.RatAttribute
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.AnalyticsKey
import org.jetbrains.annotations.NotNull
import java.util.Collections
import java.util.Date
Expand Down Expand Up @@ -92,7 +92,7 @@ class CustomEvent(@NonNull eventName: String) : BaseEvent(EventType.CUSTOM, even

// Inherit basic attributes, and add custom attributes.
val map = HashMap(super.getRatEventMap())
map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_CUSTOM_ATTRIBUTE] = ratAttributeList
map[AnalyticsKey.CUSTOM_ATTRIBUTES.key] = ratAttributeList

return Collections.unmodifiableMap(map)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.EventType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.ValueType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.Attribute
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.rat.RatAttribute
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.AnalyticsKey
import org.jetbrains.annotations.NotNull
import java.util.Collections
import kotlin.collections.ArrayList
Expand Down Expand Up @@ -84,7 +84,7 @@ class PurchaseSuccessfulEvent : BaseEvent(EventType.PURCHASE_SUCCESSFUL, EventTy

// Inherit basic attributes, and add custom attributes.
val map = HashMap(super.getRatEventMap())
map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_CUSTOM_ATTRIBUTE] = attributeList
map[AnalyticsKey.CUSTOM_ATTRIBUTES.key] = attributeList

return Collections.unmodifiableMap(map)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.rakuten.tech.mobile.inappmessaging.runtime.manager

import com.rakuten.tech.mobile.inappmessaging.runtime.BuildConfig
import com.rakuten.tech.mobile.inappmessaging.runtime.EventTrackerHelper
import com.rakuten.tech.mobile.inappmessaging.runtime.RmcHelper
import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.HostAppInfoRepository

internal enum class AnalyticsEvent(val iamName: String?, val rmcName: String?) {
IMPRESSION("_rem_iam_impressions", "_rem_rmc_iam_impressions"),
PUSH_PRIMER(null, "_rem_rmc_iam_pushprimer"),
}

internal enum class AnalyticsKey(val key: String) {
EVENT_NAME("eventName"),
CUSTOM_ATTRIBUTES("customAttributes"),
CAMPAIGN_ID("campaign_id"),
SUBS_ID("subscription_id"),
DEVICE_ID("device_id"),
TIMESTAMP("timestamp"),
CUSTOM_PARAM("cp"),
ACCOUNT("acc"),
APP_ID("aid"),
IMPRESSIONS("impressions"),
PUSH_PERMISSION("push_permission"),
}

internal object AnalyticsManager {

/**
* Sends the event [analyticsEvent]. For RMC, the event is sent to both the host app account and SDK account.
* This method attaches common metadata to the event such as Device Id etc., so only add custom information that is
* specific to the event on [data].
*/
@SuppressWarnings("LongMethod")
@JvmStatic
fun sendEvent(analyticsEvent: AnalyticsEvent, campaignId: String, data: MutableMap<String, Any>) {
// Common metadata
data[AnalyticsKey.CAMPAIGN_ID.key] = campaignId
data[AnalyticsKey.SUBS_ID.key] = HostAppInfoRepository.instance().getSubscriptionKey()
data[AnalyticsKey.DEVICE_ID.key] = HostAppInfoRepository.instance().getDeviceId()

val params = hashMapOf<String, Any>()
params[AnalyticsKey.CUSTOM_PARAM.key] = data

if (RmcHelper.isRmcIntegrated()) {
if (analyticsEvent.rmcName == null) {
return
}

val paramsCopy = HashMap<String, Any>(params)
paramsCopy[AnalyticsKey.ACCOUNT.key] = BuildConfig.IAM_RAT_ACC
paramsCopy[AnalyticsKey.APP_ID.key] = BuildConfig.IAM_RAT_AID

EventTrackerHelper.sendEvent(analyticsEvent.rmcName, params)
EventTrackerHelper.sendEvent(analyticsEvent.rmcName, paramsCopy)
} else {
if (analyticsEvent.iamName == null) {
return
}

EventTrackerHelper.sendEvent(analyticsEvent.iamName, params)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
package com.rakuten.tech.mobile.inappmessaging.runtime.manager

import com.rakuten.tech.mobile.inappmessaging.runtime.BuildConfig
import com.rakuten.tech.mobile.inappmessaging.runtime.EventTrackerHelper
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.ImpressionType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.rat.RatImpression
import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.HostAppInfoRepository
import com.rakuten.tech.mobile.inappmessaging.runtime.data.requests.Impression
import com.rakuten.tech.mobile.inappmessaging.runtime.data.requests.ImpressionRequest
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_CAMP_ID
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_IMP
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_KEY_IMPRESSION
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_SUBS_ID
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.RuntimeUtil
import com.rakuten.tech.mobile.inappmessaging.runtime.workmanager.schedulers.ImpressionScheduler
import java.util.Date
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.collections.set

/**
Expand All @@ -32,16 +26,11 @@ internal object ImpressionManager {
* Reporting impression list to IAM backend, and sending to analytics. This method is invoked on
* main thread.
*/
fun scheduleReportImpression(
impressionList: List<Impression>,
campaignId: String,
isTestMessage: Boolean,
sendEvent: (String, data: Map<String, *>?) -> Boolean = EventTrackerHelper::sendEvent,
) {
fun scheduleReportImpression(impressionList: List<Impression>, campaignId: String, isTestMessage: Boolean) {
if (impressionList.isEmpty()) return

// send user action impression
sendImpressionEvent(campaignId, impressionList, sendEvent)
sendImpressionEvent(campaignId, impressionList)

val impListRequest = impressionList.toMutableList()
impressionMap[campaignId]?.let { mapData ->
Expand All @@ -66,7 +55,6 @@ internal object ImpressionManager {
internal fun sendImpressionEvent(
campaignId: String,
impressionList: List<Impression>,
sendEvent: (String, data: Map<String, *>?) -> Boolean = EventTrackerHelper::sendEvent,
impressionTypeOnly: Boolean = false,
) {
if (impressionList.isEmpty()) return
Expand All @@ -75,12 +63,9 @@ internal object ImpressionManager {
impressionMap[campaignId] = impressionList[0] // if impression type only, it is assumed that only one entry
}

val params: MutableMap<String, Any?> = HashMap()
params[RAT_EVENT_CAMP_ID] = campaignId
params[RAT_EVENT_SUBS_ID] = HostAppInfoRepository.instance().getSubscriptionKey()
params[RAT_EVENT_IMP] = createRatImpressionList(impressionList)

sendEvent(RAT_EVENT_KEY_IMPRESSION, params)
val params = hashMapOf<String, Any>()
params[AnalyticsKey.IMPRESSIONS.key] = createRatImpressionList(impressionList)
AnalyticsManager.sendEvent(AnalyticsEvent.IMPRESSION, campaignId, params)
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
package com.rakuten.tech.mobile.inappmessaging.runtime.manager

import com.rakuten.tech.mobile.inappmessaging.runtime.EventTrackerHelper
import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.HostAppInfoRepository
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants

internal object PushPrimerTrackerManager {
internal var campaignId = ""

internal fun sendPrimerEvent(
permission: Int,
sendEvent: (String, data: Map<String, *>?) -> Boolean = EventTrackerHelper::sendEvent,
) {
val params: MutableMap<String, Any?> = HashMap()
params[InAppMessagingConstants.RAT_EVENT_CAMP_ID] = campaignId
params[InAppMessagingConstants.RAT_EVENT_SUBS_ID] = HostAppInfoRepository.instance().getSubscriptionKey()
params[InAppMessagingConstants.RAT_EVENT_KEY_PERMISSION] = permission
internal fun sendPrimerEvent(permission: Int) {
val params: MutableMap<String, Any> = HashMap()
params[AnalyticsKey.PUSH_PERMISSION.key] = permission

sendEvent(InAppMessagingConstants.RAT_EVENT_KEY_PRIMER, params)
AnalyticsManager.sendEvent(AnalyticsEvent.PUSH_PRIMER, campaignId, params)

campaignId = "" // reset value
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,6 @@ internal object InAppMessagingConstants {
// -------------------------------URL Only--------------------------------------------------------
const val TEMPLATE_BASE_URL = "http://your.base.url/"

// ------------------------------ Analytics Event KEYS ---------------------------------------------
const val RAT_EVENT_KEY_IMPRESSION = "_rem_iam_impressions"
const val RAT_EVENT_KEY_PRIMER = "_rem_iam_pushprimer"
const val RAT_EVENT_KEY_EVENT_NAME = "eventName"
const val RAT_EVENT_KEY_EVENT_TIMESTAMP = "timestamp"
const val RAT_EVENT_KEY_EVENT_CUSTOM_ATTRIBUTE = "customAttributes"
const val RAT_EVENT_CAMP_ID = "campaign_id"
const val RAT_EVENT_SUBS_ID = "subscription_id"
const val RAT_EVENT_IMP = "impressions"
const val RAT_EVENT_KEY_PERMISSION = "push_permission"

// ------------------------------ API HEADER KEYS ---------------------------------------------

const val DEVICE_ID_HEADER = "device_id"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.rakuten.tech.mobile.analytics

class RatTracker {
companion object {
fun event(type: String, parameters: Map<String, Any>): Event = Event(type, parameters)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
arrayOf(Manifest.permission.POST_NOTIFICATIONS), intArrayOf(PackageManager.PERMISSION_GRANTED),
)

verify(mockMgr).sendPrimerEvent(eq(1), any())
verify(mockMgr).sendPrimerEvent(eq(1))
}

@Test
Expand All @@ -686,7 +686,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
arrayOf(Manifest.permission.POST_NOTIFICATIONS), intArrayOf(PackageManager.PERMISSION_DENIED),
)

verify(mockMgr).sendPrimerEvent(eq(0), any())
verify(mockMgr).sendPrimerEvent(eq(0))
}

@Test
Expand All @@ -697,7 +697,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), intArrayOf(PackageManager.PERMISSION_DENIED),
)

verify(mockMgr, never()).sendPrimerEvent(any(), any())
verify(mockMgr, never()).sendPrimerEvent(any())
}

@Test
Expand All @@ -709,7 +709,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
intArrayOf(PackageManager.PERMISSION_DENIED, PackageManager.PERMISSION_GRANTED),
)

verify(mockMgr, never()).sendPrimerEvent(any(), any())
verify(mockMgr, never()).sendPrimerEvent(any())
}

@Test
Expand All @@ -721,7 +721,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
intArrayOf(PackageManager.PERMISSION_DENIED),
)

verify(mockMgr, never()).sendPrimerEvent(any(), any())
verify(mockMgr, never()).sendPrimerEvent(any())
}

@Test
Expand All @@ -734,6 +734,6 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
intArrayOf(PackageManager.PERMISSION_DENIED, PackageManager.PERMISSION_GRANTED),
)

verify(mockMgr, never()).sendPrimerEvent(any(), any())
verify(mockMgr, never()).sendPrimerEvent(any())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.rakuten.tech.mobile.inappmessaging.runtime.data.models.appevents

import com.rakuten.tech.mobile.inappmessaging.runtime.BaseTest
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.ValueType
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.AnalyticsKey
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants
import org.amshove.kluent.shouldBeEqualTo
import org.amshove.kluent.shouldBeFalse
Expand Down Expand Up @@ -124,9 +125,9 @@ class CustomEventParameterizedSpec(
event.getAttributeMap()[key]?.value shouldBeEqualTo value
event.getAttributeMap()[key]?.valueType shouldBeEqualTo type
val ratMap = event.getRatEventMap()
ratMap shouldHaveKey InAppMessagingConstants.RAT_EVENT_KEY_EVENT_NAME
ratMap shouldHaveKey InAppMessagingConstants.RAT_EVENT_KEY_EVENT_TIMESTAMP
ratMap shouldHaveKey InAppMessagingConstants.RAT_EVENT_KEY_EVENT_CUSTOM_ATTRIBUTE
ratMap shouldHaveKey AnalyticsKey.EVENT_NAME.key
ratMap shouldHaveKey AnalyticsKey.TIMESTAMP.key
ratMap shouldHaveKey AnalyticsKey.CUSTOM_ATTRIBUTES.key
}

companion object {
Expand Down
Loading
Loading