@@ -29,6 +29,7 @@ import com.mparticle.MParticle
2929import com.mparticle.commerce.CommerceEvent
3030import com.mparticle.commerce.Product
3131import com.mparticle.consent.ConsentState
32+ import com.mparticle.identity.MParticleUser
3233import com.mparticle.internal.Logger
3334import com.mparticle.internal.MPUtility
3435import org.json.JSONArray
@@ -47,7 +48,8 @@ class AppsFlyerKit :
4748 KitIntegration .CommerceListener ,
4849 AppsFlyerConversionListener ,
4950 KitIntegration .ActivityListener ,
50- KitIntegration .UserAttributeListener {
51+ KitIntegration .UserAttributeListener ,
52+ KitIntegration .IdentityListener {
5153 override fun getInstance (): AppsFlyerLib = AppsFlyerLib .getInstance()
5254
5355 override fun getName () = NAME
@@ -74,6 +76,8 @@ class AppsFlyerKit :
7476 setIntegrationAttributes(integrationAttributes)
7577 AppsFlyerLib .getInstance().subscribeForDeepLink(deepLinkListener())
7678
79+ updateCustomerUserIDIfNeededForUser(currentUser)
80+
7781 val messages: MutableList <ReportingMessage > = ArrayList ()
7882 messages.add(
7983 ReportingMessage (
@@ -107,6 +111,7 @@ class AppsFlyerKit :
107111 ): List <ReportingMessage > = emptyList()
108112
109113 override fun logEvent (event : CommerceEvent ): List <ReportingMessage > {
114+ val event = commerceEventWithAppsFlyerCustomerUserId(event)
110115 val messages: MutableList <ReportingMessage > = LinkedList ()
111116 val eventValues: MutableMap <String , Any ?> = HashMap ()
112117 val productList = event.products
@@ -215,9 +220,13 @@ class AppsFlyerKit :
215220 event.productAction == Product .PURCHASE
216221
217222 override fun logEvent (event : MPEvent ): List <ReportingMessage > {
218- var hashMap: HashMap <String ?, Any ?>? = hashMapOf()
219- if (event.customAttributes?.isNotEmpty() == true ) {
220- hashMap = event.customAttributes?.let { HashMap (it) }
223+ val hashMap: HashMap <String ?, Any ?> =
224+ event.customAttributes
225+ ?.takeIf { it.isNotEmpty() }
226+ ?.let { HashMap (it) }
227+ ? : hashMapOf()
228+ customerIdForAppsFlyer(currentUser)?.takeIf { it.isNotEmpty() }?.let { cid ->
229+ hashMap[AF_CUSTOMER_USER_ID ] = cid
221230 }
222231 instance.logEvent(context, event.eventName, hashMap)
223232 val messages: MutableList <ReportingMessage > = LinkedList ()
@@ -307,7 +316,11 @@ class AppsFlyerKit :
307316 override fun removeUserIdentity (identityType : MParticle .IdentityType ) {
308317 with (instance) {
309318 if (MParticle .IdentityType .CustomerId == identityType) {
310- setCustomerUserId(" " )
319+ if (isUserIdentificationMPID() || isUserIdentificationCustomerId()) {
320+ updateCustomerUserIDIfNeededForUser(currentUser)
321+ } else {
322+ setCustomerUserId(" " )
323+ }
311324 } else if (MParticle .IdentityType .Email == identityType) {
312325 setUserEmails(AppsFlyerProperties .EmailsCryptType .NONE , " " )
313326 }
@@ -320,7 +333,9 @@ class AppsFlyerKit :
320333 ) {
321334 with (instance) {
322335 if (MParticle .IdentityType .CustomerId == identityType) {
323- setCustomerUserId(identity)
336+ if (! isUserIdentificationMPID()) {
337+ setCustomerUserId(identity)
338+ }
324339 } else if (MParticle .IdentityType .Email == identityType) {
325340 setUserEmails(AppsFlyerProperties .EmailsCryptType .NONE , identity)
326341 }
@@ -329,6 +344,71 @@ class AppsFlyerKit :
329344
330345 override fun logout (): List <ReportingMessage > = emptyList()
331346
347+ override fun onIdentifyCompleted (
348+ mParticleUser : MParticleUser ,
349+ identityApiRequest : FilteredIdentityApiRequest ,
350+ ) {
351+ updateCustomerUserIDIfNeededForUser(mParticleUser)
352+ }
353+
354+ override fun onLoginCompleted (
355+ mParticleUser : MParticleUser ,
356+ identityApiRequest : FilteredIdentityApiRequest ,
357+ ) {
358+ updateCustomerUserIDIfNeededForUser(mParticleUser)
359+ }
360+
361+ override fun onLogoutCompleted (
362+ mParticleUser : MParticleUser ,
363+ identityApiRequest : FilteredIdentityApiRequest ,
364+ ) {
365+ updateCustomerUserIDIfNeededForUser(mParticleUser)
366+ }
367+
368+ override fun onModifyCompleted (
369+ mParticleUser : MParticleUser ,
370+ identityApiRequest : FilteredIdentityApiRequest ,
371+ ) {
372+ updateCustomerUserIDIfNeededForUser(mParticleUser)
373+ }
374+
375+ override fun onUserIdentified (mParticleUser : MParticleUser ) {
376+ updateCustomerUserIDIfNeededForUser(mParticleUser)
377+ }
378+
379+ private fun isUserIdentificationMPID (): Boolean = USER_IDENTIFICATION_MPID == settings[USER_IDENTIFICATION_TYPE ]
380+
381+ private fun isUserIdentificationCustomerId (): Boolean = USER_IDENTIFICATION_CUSTOMER_ID == settings[USER_IDENTIFICATION_TYPE ]
382+
383+ private fun customerIdForAppsFlyer (user : MParticleUser ? ): String? {
384+ if (user == null ) {
385+ return null
386+ }
387+ return when {
388+ isUserIdentificationMPID() -> user.id.toString()
389+ isUserIdentificationCustomerId() ->
390+ user.getUserIdentities()[MParticle .IdentityType .CustomerId ]
391+ else -> user.id.toString()
392+ }
393+ }
394+
395+ private fun updateCustomerUserIDIfNeededForUser (user : MParticleUser ? ) {
396+ if (! isUserIdentificationMPID() && ! isUserIdentificationCustomerId()) {
397+ return
398+ }
399+ instance.setCustomerUserId(customerIdForAppsFlyer(user))
400+ }
401+
402+ private fun commerceEventWithAppsFlyerCustomerUserId (event : CommerceEvent ): CommerceEvent {
403+ val cid = customerIdForAppsFlyer(currentUser)?.takeIf { it.isNotEmpty() } ? : return event
404+ val newAttrs = HashMap <String , String >()
405+ event.customAttributes?.forEach { (key, value) ->
406+ newAttrs[key] = value?.toString() ? : " "
407+ }
408+ newAttrs[AF_CUSTOMER_USER_ID ] = cid
409+ return CommerceEvent .Builder (event).customAttributes(newAttrs).build()
410+ }
411+
332412 private fun parseToNestedMap (jsonString : String ): Map <String , Any > {
333413 val topLevelMap = mutableMapOf<String , Any >()
334414 try {
@@ -608,6 +688,19 @@ class AppsFlyerKit :
608688 }
609689
610690 const val MANUAL_START = " manualStart"
691+
692+ /* *
693+ * Kit setting: use [USER_IDENTIFICATION_MPID], [USER_IDENTIFICATION_CUSTOMER_ID], or omit for legacy (MPID).
694+ * When set to [USER_IDENTIFICATION_MPID] or [USER_IDENTIFICATION_CUSTOMER_ID], AppsFlyer customer user ID
695+ * is synced on identity changes and `setUserIdentity(CustomerId)` does not override MPID mode.
696+ */
697+ const val USER_IDENTIFICATION_TYPE = " userIdentificationType"
698+
699+ const val USER_IDENTIFICATION_MPID = " MPID"
700+ const val USER_IDENTIFICATION_CUSTOMER_ID = " CustomerId"
701+
702+ const val AF_CUSTOMER_USER_ID = " af_customer_user_id"
703+
611704 private const val CONSENT_MAPPING = " consentMapping"
612705
613706 @Suppress(" ktlint:standard:property-naming" )
0 commit comments