11package com.myunidays.segmenkt
22
3+ import android.Manifest
34import android.app.Activity
5+ import android.content.Context
6+ import android.content.pm.PackageManager
47import android.os.Bundle
8+ import com.google.firebase.analytics.FirebaseAnalytics
59import com.myunidays.segmenkt.integrations.AliasPayload
610import com.myunidays.segmenkt.integrations.GroupPayload
711import com.myunidays.segmenkt.integrations.IdentifyPayload
812import com.myunidays.segmenkt.integrations.Integration
913import com.myunidays.segmenkt.integrations.IntegrationFactory
1014import com.myunidays.segmenkt.integrations.ScreenPayload
1115import com.myunidays.segmenkt.integrations.TrackPayload
16+ import com.segment.analytics.Analytics
17+ import com.segment.analytics.Properties
18+ import com.segment.analytics.ValueMap
19+ import com.segment.analytics.integrations.Logger
20+ import com.segment.analytics.internal.Utils
21+ import kotlin.math.min
1222
1323@Suppress(" TooManyFunctions" )
1424actual class FirebaseIntegration internal constructor(
15- private val android : com.segment.analytics.integrations. Integration < * >
25+ private val android : AndroidFirebaseIntegration
1626) : Integration<FirebaseIntegration> {
1727 fun onActivityCreated (activity : Activity ? , savedInstanceState : Bundle ? ) =
1828 android.onActivityCreated(activity, savedInstanceState)
@@ -38,6 +48,243 @@ actual class FirebaseIntegration internal constructor(
3848 actual fun factory (
3949 delegate : Any? ,
4050 deeplinkHandler : Any?
41- ): IntegrationFactory = com.segment.analytics.android.integrations.firebase.FirebaseIntegration .FACTORY
51+ ): IntegrationFactory = AndroidFirebaseIntegration .FACTORY
52+ }
53+ }
54+
55+ /* *
56+ * A kotlin converted implementation of FirebaseIntegration https://github.com/segment-integrations/analytics-android-integration-firebase
57+ */
58+ internal class AndroidFirebaseIntegration (context : Context ? , private val logger : Logger ) :
59+ com.segment.analytics.integrations.Integration <FirebaseAnalytics ?>() {
60+ private val firebaseAnalytics = FirebaseAnalytics .getInstance(context!! )
61+ private var currentActivity: Activity ? = null
62+
63+ override fun onActivityResumed (activity : Activity ? ) {
64+ super .onActivityResumed(activity)
65+
66+ val packageManager = activity?.packageManager
67+ try {
68+ val info =
69+ packageManager?.getActivityInfo(activity.componentName, PackageManager .GET_META_DATA )
70+ val activityLabel = info?.loadLabel(packageManager).toString()
71+ firebaseAnalytics.setCurrentScreen(activity!! , activityLabel, null )
72+ logger.verbose(" firebaseAnalytics.setCurrentScreen(activity, %s, null);" , activityLabel)
73+ } catch (e: PackageManager .NameNotFoundException ) {
74+ throw AssertionError (" Activity Not Found: $e " )
75+ }
76+ }
77+
78+ override fun onActivityStarted (activity : Activity ? ) {
79+ super .onActivityStarted(activity)
80+
81+ this .currentActivity = activity
82+ }
83+
84+ override fun onActivityStopped (activity : Activity ? ) {
85+ super .onActivityStopped(activity)
86+
87+ this .currentActivity = null
88+ }
89+
90+ override fun identify (identify : com.segment.analytics.integrations.IdentifyPayload ) {
91+ super .identify(identify)
92+
93+ if (! Utils .isNullOrEmpty(identify.userId())) {
94+ firebaseAnalytics.setUserId(identify.userId())
95+ }
96+ val traits: Map <String ?, Any > = identify.traits()
97+ for (entry in traits.entries) {
98+ var trait = entry.key
99+ val value = entry.value.toString()
100+ trait = makeKey(trait)
101+ firebaseAnalytics.setUserProperty(trait, value)
102+ logger.verbose(" firebaseAnalytics.setUserProperty(%s, %s);" , trait, value)
103+ }
104+ }
105+
106+ override fun track (track : com.segment.analytics.integrations.TrackPayload ) {
107+ super .track(track)
108+
109+ val event = track.event()
110+ val eventName = if (EVENT_MAPPER .containsKey(event)) {
111+ EVENT_MAPPER [event]
112+ } else {
113+ makeKey(event)
114+ }
115+ val properties = track.properties()
116+ val formattedProperties = formatProperties(properties)
117+ firebaseAnalytics.logEvent(eventName!! , formattedProperties)
118+ logger.verbose(" firebaseAnalytics.logEvent(%s, %s);" , eventName, formattedProperties)
119+ }
120+
121+ override fun screen (screen : com.segment.analytics.integrations.ScreenPayload ) {
122+ super .screen(screen)
123+
124+ val propertiesBundle = Bundle ()
125+ for ((key, value) in screen) {
126+ propertiesBundle.putString(key, value.toString())
127+ }
128+ propertiesBundle.putString(FirebaseAnalytics .Param .SCREEN_NAME , screen.name())
129+ firebaseAnalytics.logEvent(FirebaseAnalytics .Event .SCREEN_VIEW , propertiesBundle)
130+ logger.verbose(" firebaseAnalytics.screen(activity, %s, null);" , screen.name())
131+ }
132+
133+ companion object {
134+ val FACTORY : Factory = object : Factory {
135+ @Suppress(" ReturnCount" )
136+ override fun create (
137+ settings : ValueMap ,
138+ analytics : Analytics
139+ ): com.segment.analytics.integrations.Integration <* >? {
140+ val logger = analytics.logger(FIREBASE_ANALYTICS_KEY )
141+ if (! Utils .hasPermission(
142+ analytics.application, Manifest .permission.ACCESS_NETWORK_STATE
143+ )
144+ ) {
145+ logger.debug(" ACCESS_NETWORK_STATE is required for Firebase Analytics." )
146+ return null
147+ }
148+ if (! Utils .hasPermission(analytics.application, Manifest .permission.WAKE_LOCK )) {
149+ logger.debug(" WAKE_LOCK is required for Firebase Analytics." )
150+ return null
151+ }
152+
153+ val context: Context = analytics.application
154+
155+ return AndroidFirebaseIntegration (context, logger)
156+ }
157+
158+ override fun key (): String {
159+ return FIREBASE_ANALYTICS_KEY
160+ }
161+ }
162+
163+ private const val FIREBASE_ANALYTICS_KEY = " Firebase"
164+ private val EVENT_MAPPER = createEventMap()
165+ private fun createEventMap (): Map <String , String > {
166+ val EVENT_MAPPER : MutableMap <String , String > = HashMap ()
167+ EVENT_MAPPER [" Product Added" ] = FirebaseAnalytics .Event .ADD_TO_CART
168+ EVENT_MAPPER [" Checkout Started" ] = FirebaseAnalytics .Event .BEGIN_CHECKOUT
169+ EVENT_MAPPER [" Order Completed" ] = FirebaseAnalytics .Event .PURCHASE
170+ EVENT_MAPPER [" Order Refunded" ] = FirebaseAnalytics .Event .REFUND
171+ EVENT_MAPPER [" Product Viewed" ] = FirebaseAnalytics .Event .VIEW_ITEM
172+ EVENT_MAPPER [" Product List Viewed" ] = FirebaseAnalytics .Event .VIEW_ITEM_LIST
173+ EVENT_MAPPER [" Payment Info Entered" ] = FirebaseAnalytics .Event .ADD_PAYMENT_INFO
174+ EVENT_MAPPER [" Promotion Viewed" ] = FirebaseAnalytics .Event .VIEW_PROMOTION
175+ EVENT_MAPPER [" Product Added to Wishlist" ] = FirebaseAnalytics .Event .ADD_TO_WISHLIST
176+ EVENT_MAPPER [" Product Shared" ] = FirebaseAnalytics .Event .SHARE
177+ EVENT_MAPPER [" Product Clicked" ] = FirebaseAnalytics .Event .SELECT_CONTENT
178+ EVENT_MAPPER [" Products Searched" ] = FirebaseAnalytics .Event .SEARCH
179+ return EVENT_MAPPER
180+ }
181+
182+ private val PROPERTY_MAPPER = createPropertyMap()
183+
184+ private fun createPropertyMap (): Map <String ?, String > {
185+ val PROPERTY_MAPPER : MutableMap <String ?, String > = HashMap ()
186+ PROPERTY_MAPPER [" category" ] = FirebaseAnalytics .Param .ITEM_CATEGORY
187+ PROPERTY_MAPPER [" product_id" ] = FirebaseAnalytics .Param .ITEM_ID
188+ PROPERTY_MAPPER [" name" ] = FirebaseAnalytics .Param .ITEM_NAME
189+ PROPERTY_MAPPER [" price" ] = FirebaseAnalytics .Param .PRICE
190+ PROPERTY_MAPPER [" quantity" ] = FirebaseAnalytics .Param .QUANTITY
191+ PROPERTY_MAPPER [" query" ] = FirebaseAnalytics .Param .SEARCH_TERM
192+ PROPERTY_MAPPER [" shipping" ] = FirebaseAnalytics .Param .SHIPPING
193+ PROPERTY_MAPPER [" tax" ] = FirebaseAnalytics .Param .TAX
194+ PROPERTY_MAPPER [" total" ] = FirebaseAnalytics .Param .VALUE
195+ PROPERTY_MAPPER [" revenue" ] = FirebaseAnalytics .Param .VALUE
196+ PROPERTY_MAPPER [" order_id" ] = FirebaseAnalytics .Param .TRANSACTION_ID
197+ PROPERTY_MAPPER [" currency" ] = FirebaseAnalytics .Param .CURRENCY
198+ PROPERTY_MAPPER [" products" ] = FirebaseAnalytics .Param .ITEMS
199+ return PROPERTY_MAPPER
200+ }
201+
202+ private val PRODUCT_MAPPER = createProductMap()
203+
204+ private fun createProductMap (): Map <String ?, String > {
205+ val MAPPER : MutableMap <String ?, String > = HashMap ()
206+ MAPPER [" category" ] = FirebaseAnalytics .Param .ITEM_CATEGORY
207+ MAPPER [" product_id" ] = FirebaseAnalytics .Param .ITEM_ID
208+ MAPPER [" id" ] = FirebaseAnalytics .Param .ITEM_ID
209+ MAPPER [" name" ] = FirebaseAnalytics .Param .ITEM_NAME
210+ MAPPER [" price" ] = FirebaseAnalytics .Param .PRICE
211+ MAPPER [" quantity" ] = FirebaseAnalytics .Param .QUANTITY
212+ return MAPPER
213+ }
214+
215+ private fun formatProperties (properties : Properties ): Bundle {
216+ val bundle = Bundle ()
217+ if ((properties.revenue() != 0.0 || properties.total() != 0.0 ) && Utils .isNullOrEmpty(properties.currency())
218+ ) {
219+ bundle.putString(FirebaseAnalytics .Param .CURRENCY , " USD" )
220+ }
221+ for (entry in properties.entries) {
222+ val value = entry.value
223+ var property = entry.key
224+ property = if (PROPERTY_MAPPER .containsKey(property)) {
225+ PROPERTY_MAPPER [property]
226+ } else {
227+ makeKey(property)
228+ }
229+ if (property == FirebaseAnalytics .Param .ITEMS && value != null ) {
230+ val products = properties.getList(
231+ " products" ,
232+ ValueMap ::class .java
233+ )
234+ val mappedProducts = formatProducts(products)
235+ bundle.putParcelableArrayList(property, mappedProducts)
236+ } else {
237+ putValue(bundle, property, value)
238+ }
239+ }
240+ return bundle
241+ }
242+
243+ private fun formatProducts (products : List <ValueMap >? ): ArrayList <Bundle > {
244+ val mappedProducts = ArrayList <Bundle >()
245+ if (products == null ) return mappedProducts
246+
247+ for (product in products) {
248+ val mappedProduct = Bundle ()
249+ for (innerEntry in product.entries) {
250+ var key = innerEntry.key
251+ val value = innerEntry.value
252+ key = if (PRODUCT_MAPPER .containsKey(key)) {
253+ PRODUCT_MAPPER [key]
254+ } else {
255+ makeKey(key)
256+ }
257+ putValue(mappedProduct, key, value)
258+ }
259+ mappedProducts.add(mappedProduct)
260+ }
261+ return mappedProducts
262+ }
263+
264+ private fun putValue (bundle : Bundle , key : String? , value : Any? ) {
265+ if (value is Int ) {
266+ bundle.putInt(key, value)
267+ } else if (value is Double ) {
268+ bundle.putDouble(key, value)
269+ } else if (value is Long ) {
270+ bundle.putLong(key, value)
271+ } else {
272+ val stringValue = value.toString()
273+ bundle.putString(key, stringValue)
274+ }
275+ }
276+
277+ @Suppress(" MagicNumber" )
278+ fun makeKey (key : String? ): String {
279+ var key = key
280+ val forbiddenChars = arrayOf(" ." , " -" , " " , " :" )
281+ for (forbidden in forbiddenChars) {
282+ if (key!! .contains(forbidden)) {
283+ key = key.trim { it <= ' ' }.replace(forbidden, " _" )
284+ }
285+ }
286+
287+ return key!! .substring(0 , min(key.length.toDouble(), 40.0 ).toInt())
288+ }
42289 }
43290}
0 commit comments