diff --git a/build.gradle b/build.gradle index 7fb35b7..f1732b0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '2.0.20' + ext.kotlin_version = '2.2.20' if (!project.hasProperty('version') || project.version.equals('unspecified')) { project.version = '+' } @@ -36,7 +36,7 @@ apply plugin: 'com.mparticle.kit' android { namespace 'com.mparticle.kits.urbanairship' - compileSdk = 33 + compileSdk = 36 buildFeatures { buildConfig = true } @@ -59,7 +59,7 @@ android { dependencies { compileOnly 'androidx.legacy:legacy-support-v4:1.0.0' - api 'com.urbanairship.android:urbanairship-core:19.9.1' + api 'com.urbanairship.android:urbanairship-core:20.3.0' testImplementation 'junit:junit:4.13.2' testImplementation files('libs/java-json.jar') } diff --git a/src/main/kotlin/com/mparticle/kits/MParticleAutopilot.kt b/src/main/kotlin/com/mparticle/kits/MParticleAutopilot.kt index afcf39c..c57184c 100644 --- a/src/main/kotlin/com/mparticle/kits/MParticleAutopilot.kt +++ b/src/main/kotlin/com/mparticle/kits/MParticleAutopilot.kt @@ -1,14 +1,14 @@ package com.mparticle.kits import android.content.Context -import android.graphics.Color +import androidx.core.content.edit +import androidx.core.graphics.toColorInt import com.mparticle.MParticle import com.mparticle.internal.Logger import com.mparticle.kits.UrbanAirshipKit.ChannelIdListener +import com.urbanairship.Airship import com.urbanairship.AirshipConfigOptions import com.urbanairship.Autopilot -import com.urbanairship.UAirship -import com.urbanairship.util.UAStringUtil /** * Autopilot for UrbanAirshipKit integration. @@ -35,29 +35,28 @@ class MParticleAutopilot : Autopilot() { .setInProduction(true) } if ("EU".equals(preferences.getString(DOMAIN, null), true)) { - optionsBuilder.setSite(AirshipConfigOptions.SITE_EU) + optionsBuilder.setSite(AirshipConfigOptions.Site.SITE_EU) } val customDomain = preferences.getString(CUSTOM_DOMAIN_PROXY_URL, null) - if (!UAStringUtil.isEmpty(customDomain)) { + if (!customDomain.isNullOrEmpty()) { optionsBuilder.setInitialConfigUrl(customDomain).setUrlAllowList(arrayOf(customDomain)) } return optionsBuilder.build() } - override fun onAirshipReady(airship: UAirship) { + override fun onAirshipReady(context: Context) { val preferences = - UAirship - .getApplicationContext() + Airship.application.applicationContext .getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) if (preferences.getBoolean(FIRST_RUN_KEY, true)) { - preferences.edit().putBoolean(FIRST_RUN_KEY, false).apply() - airship.pushManager.userNotificationsEnabled = true + preferences.edit { putBoolean(FIRST_RUN_KEY, false) } + Airship.push.userNotificationsEnabled = true } // Restore the last registration token - val token = airship.pushManager.pushToken + val token = Airship.push.pushToken MParticlePushProvider.instance.setRegistrationToken(token) - airship.channel.addChannelListener { callChannelIdListener() } + Airship.channel.addChannelListener { callChannelIdListener() } callChannelIdListener() } @@ -96,41 +95,43 @@ class MParticleAutopilot : Autopilot() { context: Context, configuration: UrbanAirshipConfiguration, ) { - val editor = - context - .getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) - .edit() - .putString(APP_KEY, configuration.applicationKey) - .putString(APP_SECRET, configuration.applicationSecret) - .putString(DOMAIN, configuration.domain) - .putString(CUSTOM_DOMAIN_PROXY_URL, configuration.customDomainProxyUrl) + context + .getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) + .edit { + putString(APP_KEY, configuration.applicationKey) + .putString(APP_SECRET, configuration.applicationSecret) + .putString(DOMAIN, configuration.domain) + .putString(CUSTOM_DOMAIN_PROXY_URL, configuration.customDomainProxyUrl) - // Convert accent color hex string to an int - val accentColor = configuration.notificationColor - if (!UAStringUtil.isEmpty(accentColor)) { - try { - editor.putInt(NOTIFICATION_COLOR, Color.parseColor(accentColor)) - } catch (e: IllegalArgumentException) { - Logger.warning(e, "Unable to parse notification accent color: $accentColor") - } - } + // Convert accent color hex string to an int + val accentColor = configuration.notificationColor + if (!accentColor.isNullOrEmpty()) { + try { + putInt(NOTIFICATION_COLOR, accentColor.toColorInt()) + } catch (e: IllegalArgumentException) { + Logger.warning( + e, + "Unable to parse notification accent color: $accentColor", + ) + } + } - // Convert notification name to a drawable resource ID - val notificationIconName = configuration.notificationIconName - if (!UAStringUtil.isEmpty(notificationIconName)) { - val id = - context.resources.getIdentifier( - notificationIconName, - "drawable", - context.packageName, - ) - if (id != 0) { - editor.putInt(NOTIFICATION_ICON_NAME, id) - } else { - Logger.error("Unable to find notification icon with name: $notificationIconName") + // Convert notification name to a drawable resource ID + val notificationIconName = configuration.notificationIconName + if (!notificationIconName.isNullOrEmpty()) { + val id = + context.resources.getIdentifier( + notificationIconName, + "drawable", + context.packageName, + ) + if (id != 0) { + putInt(NOTIFICATION_ICON_NAME, id) + } else { + Logger.error("Unable to find notification icon with name: $notificationIconName") + } + } } - } - editor.apply() } } } diff --git a/src/main/kotlin/com/mparticle/kits/MParticlePushProvider.kt b/src/main/kotlin/com/mparticle/kits/MParticlePushProvider.kt index fe40822..8ee6282 100644 --- a/src/main/kotlin/com/mparticle/kits/MParticlePushProvider.kt +++ b/src/main/kotlin/com/mparticle/kits/MParticlePushProvider.kt @@ -1,7 +1,7 @@ package com.mparticle.kits import android.content.Context -import com.urbanairship.UAirship +import com.urbanairship.Platform import com.urbanairship.push.PushProvider /** @@ -10,9 +10,9 @@ import com.urbanairship.push.PushProvider internal class MParticlePushProvider private constructor() : PushProvider { private var token: String? = null - override fun getPlatform(): Int = UAirship.ANDROID_PLATFORM + override val platform: Platform = Platform.ANDROID - override fun getDeliveryType(): String = PushProvider.FCM_DELIVERY_TYPE + override val deliveryType: PushProvider.DeliveryType = PushProvider.DeliveryType.FCM override fun getRegistrationToken(context: Context): String? = token diff --git a/src/main/kotlin/com/mparticle/kits/UrbanAirshipKit.kt b/src/main/kotlin/com/mparticle/kits/UrbanAirshipKit.kt index d7ced6c..138b268 100644 --- a/src/main/kotlin/com/mparticle/kits/UrbanAirshipKit.kt +++ b/src/main/kotlin/com/mparticle/kits/UrbanAirshipKit.kt @@ -7,12 +7,13 @@ import com.mparticle.MParticle.IdentityType import com.mparticle.commerce.CommerceEvent import com.mparticle.commerce.Product import com.mparticle.kits.KitIntegration.CommerceListener +import com.urbanairship.Airship import com.urbanairship.Autopilot import com.urbanairship.PrivacyManager -import com.urbanairship.UAirship import com.urbanairship.analytics.CustomEvent import com.urbanairship.analytics.InstallReceiver -import com.urbanairship.analytics.RetailEventTemplate +import com.urbanairship.analytics.customEvent +import com.urbanairship.analytics.templates.RetailEventTemplate import com.urbanairship.json.JsonValue import com.urbanairship.push.PushMessage import com.urbanairship.push.PushProviderBridge @@ -65,7 +66,7 @@ class UrbanAirshipKit : } override fun setOptOut(optedOut: Boolean): List { - UAirship.shared().privacyManager.setEnabledFeatures( + Airship.privacyManager.setEnabledFeatures( if (optedOut) PrivacyManager.Feature.NONE else PrivacyManager.Feature.ALL, ) val message = @@ -79,7 +80,7 @@ class UrbanAirshipKit : } override fun setInstallReferrer(intent: Intent) { - InstallReceiver().onReceive(UAirship.getApplicationContext(), intent) + InstallReceiver().onReceive(Airship.application.applicationContext, intent) } override fun willHandlePushMessage(intent: Intent?): Boolean { @@ -131,9 +132,7 @@ class UrbanAirshipKit : override fun logEvent(event: MPEvent): List { val tagSet = extractTags(event) if (tagSet.isNotEmpty()) { - UAirship - .shared() - .channel + Airship.channel .editTags() .addTags(tagSet) .apply() @@ -148,14 +147,12 @@ class UrbanAirshipKit : ): List { val tagSet = extractScreenTags(screenName, attributes) if (tagSet.isNotEmpty()) { - UAirship - .shared() - .channel + Airship.channel .editTags() .addTags(tagSet) .apply() } - UAirship.shared().analytics.trackScreen(screenName) + Airship.analytics.trackScreen(screenName) val message = ReportingMessage( this, @@ -177,7 +174,7 @@ class UrbanAirshipKit : .Builder(eventName) .setEventValue(valueIncreased) .build() - UAirship.shared().analytics.recordCustomEvent(customEvent) + Airship.analytics.recordCustomEvent(customEvent) val message = ReportingMessage( this, @@ -191,9 +188,7 @@ class UrbanAirshipKit : override fun logEvent(commerceEvent: CommerceEvent): List { val tagSet = extractCommerceTags(commerceEvent) if (tagSet.isNotEmpty()) { - UAirship - .shared() - .channel + Airship.channel .editTags() .addTags(tagSet) .apply() @@ -216,30 +211,26 @@ class UrbanAirshipKit : ) { val airshipId = getAirshipIdentifier(identityType) if (airshipId != null) { - UAirship - .shared() - .analytics + Airship.analytics .editAssociatedIdentifiers() .addIdentifier(airshipId, identity) .apply() } if (identityType == configuration?.userIdField) { - UAirship.shared().contact.identify(identity) // Previously setting namedUser but now is immutable + Airship.contact.identify(identity) // Previously setting namedUser but now is immutable } } override fun removeUserIdentity(identityType: IdentityType) { val airshipId = getAirshipIdentifier(identityType) if (airshipId != null) { - UAirship - .shared() - .analytics + Airship.analytics .editAssociatedIdentifiers() .removeIdentifier(airshipId) .apply() } - if (identityType == configuration?.userIdField && UAirship.shared().contact.namedUserId != null) { - UAirship.shared().contact.reset() // Previously setting namedUser to null but now is immutable + if (identityType == configuration?.userIdField && Airship.contact.namedUserId != null) { + Airship.contact.reset() // Previously setting namedUser to null but now is immutable } } @@ -249,16 +240,12 @@ class UrbanAirshipKit : ) { if (configuration?.enableTags == true) { if (KitUtils.isEmpty(value)) { - UAirship - .shared() - .channel + Airship.channel .editTags() .addTag(KitUtils.sanitizeAttributeKey(key)) .apply() } else if (configuration?.includeUserAttributes == true) { - UAirship - .shared() - .channel + Airship.channel .editTags() .addTag(KitUtils.sanitizeAttributeKey(key) + "-" + value) .apply() @@ -281,9 +268,7 @@ class UrbanAirshipKit : ) { if (configuration?.enableTags == true) { val editor = - UAirship - .shared() - .channel + Airship.channel .editTags() for ((key, value) in stringAttributes) { if (KitUtils.isEmpty(value)) { @@ -297,9 +282,7 @@ class UrbanAirshipKit : } override fun removeUserAttribute(attribute: String) { - UAirship - .shared() - .channel + Airship.channel .editTags() .removeTag(attribute) .apply() @@ -320,43 +303,22 @@ class UrbanAirshipKit : return false } event.products?.let { eventProducts -> - when (event.productAction) { - Product.PURCHASE -> for (product in eventProducts) { - val template = - RetailEventTemplate - .newPurchasedTemplate() - if (!KitUtils.isEmpty( - event.transactionAttributes?.id, - ) - ) { - template.setTransactionId( - event.transactionAttributes?.id, - ) + for (product in eventProducts) { + val templateType = + when (event.productAction) { + Product.PURCHASE -> RetailEventTemplate.Type.Purchased + Product.ADD_TO_CART -> RetailEventTemplate.Type.AddedToCart + Product.CLICK -> RetailEventTemplate.Type.Browsed + Product.ADD_TO_WISHLIST -> RetailEventTemplate.Type.Starred + else -> return false } - populateRetailEventTemplate(template, product) - .createEvent() - .track() - } - Product.ADD_TO_CART -> for (product in eventProducts) { - populateRetailEventTemplate( - RetailEventTemplate.newAddedToCartTemplate(), - product, - ).createEvent() - .track() - } - Product.CLICK -> for (product in eventProducts) { - populateRetailEventTemplate(RetailEventTemplate.newBrowsedTemplate(), product) - .createEvent() - .track() - } - Product.ADD_TO_WISHLIST -> for (product in eventProducts) { - populateRetailEventTemplate( - RetailEventTemplate.newStarredProductTemplate(), - product, - ).createEvent() - .track() - } - else -> return false + customEvent( + templateType, + populateRetailEventTemplate(product), + ) { + setEventValue(product.totalAmount) + setTransactionId(event.transactionAttributes?.id) + }.track() } } return true @@ -369,16 +331,13 @@ class UrbanAirshipKit : * @param product The product. * @return The populated retail event template. */ - private fun populateRetailEventTemplate( - template: RetailEventTemplate, - product: Product, - ): RetailEventTemplate = - template - .setCategory(product.category) - .setId(product.sku) - .setDescription(product.name) - .setValue(product.totalAmount) - .setBrand(product.brand) + private fun populateRetailEventTemplate(product: Product): RetailEventTemplate.Properties = + RetailEventTemplate.Properties( + id = product.sku, + category = product.category, + eventDescription = product.name, + brand = product.brand, + ) /** * Logs an Urban Airship CustomEvent from an MPEvent. @@ -390,7 +349,7 @@ class UrbanAirshipKit : if (event.customAttributeStrings != null) { eventBuilder.setProperties(JsonValue.wrapOpt(event.customAttributeStrings).optMap()) } - UAirship.shared().analytics.recordCustomEvent(eventBuilder.build()) + Airship.analytics.recordCustomEvent(eventBuilder.build()) } fun extractTags(event: MPEvent): Set { @@ -529,7 +488,7 @@ class UrbanAirshipKit : * Sets the Urban Airship Channel ID as an mParticle integration attribute. */ private fun updateChannelIntegration() { - val channelId = UAirship.shared().channel.id + val channelId = Airship.channel.id if (!KitUtils.isEmpty(channelId)) { val integrationAttributes = HashMap(1) integrationAttributes[CHANNEL_ID_INTEGRATION_KEY] = channelId