@@ -6,12 +6,11 @@ import android.content.Context
6
6
import android.content.Intent
7
7
import android.content.pm.PackageInfo
8
8
import android.content.res.Resources
9
+ import android.media.MediaDrm
9
10
import android.net.ConnectivityManager
10
11
import android.net.NetworkCapabilities
11
12
import android.net.Uri
12
13
import android.os.Build
13
- import android.provider.Settings
14
- import android.provider.Settings.Secure.getString
15
14
import android.util.Log
16
15
import androidx.core.content.pm.PackageInfoCompat
17
16
import com.facebook.react.ReactActivity
@@ -21,6 +20,8 @@ import com.facebook.react.module.annotations.ReactModule
21
20
import com.sovranreactnative.SovranModule
22
21
import java.lang.Exception
23
22
import java.util.*
23
+ import java.security.MessageDigest
24
+ import java.util.UUID
24
25
25
26
26
27
enum class ConnectionType {
@@ -54,88 +55,118 @@ class AnalyticsReactNativeModule : ReactContextBaseJavaModule, ActivityEventList
54
55
return PackageInfoCompat .getLongVersionCode(pInfo).toString()
55
56
}
56
57
57
- @SuppressLint(" HardwareIds" )
58
- private fun getUniqueId (collectDeviceId : Boolean ): String? {
59
- if (collectDeviceId) {
60
- return getString(reactApplicationContext.contentResolver, Settings .Secure .ANDROID_ID )
58
+ fun ByteArray.toHexString () = joinToString(" " ) { " %02x" .format(it) }
59
+
60
+ /* *
61
+ * Workaround for not able to get device id on Android 10 or above using DRM API
62
+ * {@see https://stackoverflow.com/questions/58103580/android-10-imei-no-longer-available-on-api-29-looking-for-alternatives}
63
+ * {@see https://developer.android.com/training/articles/user-data-ids}
64
+ */
65
+ private fun getUniqueId (collectDeviceId : Boolean ): String? {
66
+ if (collectDeviceId) {
67
+ if (Build .VERSION .SDK_INT < Build .VERSION_CODES .JELLY_BEAN_MR2 )
68
+ return null
69
+
70
+ val WIDEVINE_UUID = UUID (- 0x121074568629b532L , - 0x5c37d8232ae2de13L )
71
+ var wvDrm: MediaDrm ? = null
72
+ try {
73
+ wvDrm = MediaDrm (WIDEVINE_UUID )
74
+ val wideVineId = wvDrm.getPropertyByteArray(MediaDrm .PROPERTY_DEVICE_UNIQUE_ID )
75
+ val md = MessageDigest .getInstance(" SHA-256" )
76
+ md.update(wideVineId)
77
+ return md.digest().toHexString()
78
+ } catch (e: Exception ) {
79
+ return null
80
+ } finally {
81
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .P ) {
82
+ wvDrm?.close()
83
+ } else {
84
+ wvDrm?.release()
85
+ }
61
86
}
62
- return null
63
87
}
88
+ return null
89
+ }
64
90
65
- private fun getConnectionType (context : Context ): ConnectionType {
66
- val cm = context.getSystemService(Context .CONNECTIVITY_SERVICE ) as ConnectivityManager ?
67
- var result: ConnectionType = ConnectionType .Unknown
68
-
69
- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
70
- cm?.run {
71
- cm.getNetworkCapabilities(cm.activeNetwork)?.run {
72
- if (hasTransport(NetworkCapabilities .TRANSPORT_WIFI )) {
73
- result = ConnectionType .Wifi
74
- } else if (hasTransport(NetworkCapabilities .TRANSPORT_CELLULAR )) {
75
- result = ConnectionType .Cellular
76
- } else {
77
- result = ConnectionType .Unknown
78
- }
91
+ private fun getConnectionType (context : Context ): ConnectionType {
92
+ val cm = context.getSystemService(Context .CONNECTIVITY_SERVICE ) as ConnectivityManager ?
93
+ var result: ConnectionType = ConnectionType .Unknown
94
+
95
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
96
+ cm?.run {
97
+ cm.getNetworkCapabilities(cm.activeNetwork)?.run {
98
+ if (hasTransport(NetworkCapabilities .TRANSPORT_WIFI )) {
99
+ result = ConnectionType .Wifi
100
+ } else if (hasTransport(NetworkCapabilities .TRANSPORT_CELLULAR )) {
101
+ result = ConnectionType .Cellular
102
+ } else {
103
+ result = ConnectionType .Unknown
79
104
}
80
105
}
81
- } else {
82
- cm?. run {
83
- cm.activeNetworkInfo ?.run {
84
- if (type == ConnectivityManager . TYPE_WIFI ) {
85
- result = ConnectionType . Wifi
86
- } else if (type == ConnectivityManager . TYPE_MOBILE ) {
87
- result = ConnectionType . Cellular
88
- } else {
89
- result = ConnectionType . Unknown
90
- }
106
+ }
107
+ } else {
108
+ cm ?.run {
109
+ cm.activeNetworkInfo?. run {
110
+ if (type == ConnectivityManager . TYPE_WIFI ) {
111
+ result = ConnectionType . Wifi
112
+ } else if (type == ConnectivityManager . TYPE_MOBILE ) {
113
+ result = ConnectionType . Cellular
114
+ } else {
115
+ result = ConnectionType . Unknown
91
116
}
92
117
}
93
118
}
94
- return result
95
119
}
120
+ return result
121
+ }
96
122
97
- @ReactMethod
98
- fun getContextInfo (config : ReadableMap , promise : Promise ) {
99
- val appName: String = reactApplicationContext.applicationInfo.loadLabel(reactApplicationContext.packageManager).toString()
100
- val appVersion: String = pInfo.versionName
101
- val buildNumber = getBuildNumber()
102
- val bundleId = reactApplicationContext.packageName
123
+ @ReactMethod
124
+ fun getContextInfo (config : ReadableMap , promise : Promise ) {
125
+ val appName: String = reactApplicationContext.applicationInfo.loadLabel(reactApplicationContext.packageManager).toString()
126
+ val appVersion: String = pInfo.versionName
127
+ val buildNumber = getBuildNumber()
128
+ val bundleId = reactApplicationContext.packageName
103
129
104
- val connectionType: ConnectionType = getConnectionType(reactApplicationContext)
105
- val timezone: TimeZone = TimeZone .getDefault()
106
- val currentLocale: Locale = Locale .getDefault()
107
- val locale: String = " ${currentLocale.language} -${currentLocale.country} "
130
+ val connectionType: ConnectionType = getConnectionType(reactApplicationContext)
131
+ val timezone: TimeZone = TimeZone .getDefault()
132
+ val currentLocale: Locale = Locale .getDefault()
133
+ val locale: String = " ${currentLocale.language} -${currentLocale.country} "
108
134
109
- val screenWidth = Resources .getSystem().displayMetrics.widthPixels
110
- val screenHeight = Resources .getSystem().displayMetrics.heightPixels
135
+ val screenWidth = Resources .getSystem().displayMetrics.widthPixels
136
+ val screenHeight = Resources .getSystem().displayMetrics.heightPixels
111
137
112
- val screenDensity = Resources .getSystem().displayMetrics.density;
138
+ val screenDensity = Resources .getSystem().displayMetrics.density;
113
139
114
- val contextInfo: WritableMap = Arguments .createMap()
140
+ val contextInfo: WritableMap = Arguments .createMap()
115
141
116
- contextInfo.putString(" appName" , appName)
117
- contextInfo.putString(" appVersion" , appVersion)
118
- contextInfo.putString(" buildNumber" , buildNumber)
119
- contextInfo.putString(" bundleId" , bundleId)
120
- contextInfo.putString(" deviceId" , getUniqueId(config.hasKey(" collectDeviceId" ) && config.getBoolean(" collectDeviceId" )))
121
- contextInfo.putString(" deviceName" , Build .DEVICE )
122
- contextInfo.putString(" deviceType" , " android" )
123
- contextInfo.putString(" manufacturer" , Build .MANUFACTURER )
124
- contextInfo.putString(" model" , Build .MODEL )
142
+ // generate random identifier that does not persist across installations
143
+ // use it as the fallback in case DRM API failed to generate one.
144
+ val fallbackDeviceId = UUID .randomUUID().toString()
145
+ val deviceId = getUniqueId(config.hasKey(" collectDeviceId" ) && config.getBoolean(" collectDeviceId" ))? : fallbackDeviceId
125
146
126
- contextInfo.putString(" timezone" , timezone.id)
127
- contextInfo.putString(" locale" , locale)
128
- contextInfo.putString(" networkType" , connectionType.toString().toLowerCase(currentLocale))
147
+ contextInfo.putString(" appName" , appName)
148
+ contextInfo.putString(" appVersion" , appVersion)
149
+ contextInfo.putString(" buildNumber" , buildNumber)
150
+ contextInfo.putString(" bundleId" , bundleId)
151
+ contextInfo.putString(" deviceId" , deviceId)
152
+ contextInfo.putString(" deviceName" , Build .DEVICE )
153
+ contextInfo.putString(" deviceType" , " android" )
154
+ contextInfo.putString(" manufacturer" , Build .MANUFACTURER )
155
+ contextInfo.putString(" model" , Build .MODEL )
129
156
130
- contextInfo.putString(" osName" , " Android" )
131
- contextInfo.putString(" osVersion" , Build .VERSION .RELEASE )
157
+ contextInfo.putString(" timezone" , timezone.id)
158
+ contextInfo.putString(" locale" , locale)
159
+ contextInfo.putString(" networkType" , connectionType.toString().toLowerCase(currentLocale))
132
160
133
- contextInfo.putInt(" screenWidth" , screenWidth)
134
- contextInfo.putInt(" screenHeight" , screenHeight)
135
- contextInfo.putDouble(" screenDensity" , screenDensity.toDouble())
161
+ contextInfo.putString(" osName" , " Android" )
162
+ contextInfo.putString(" osVersion" , Build .VERSION .RELEASE )
136
163
137
- promise.resolve(contextInfo)
138
- }
164
+ contextInfo.putInt(" screenWidth" , screenWidth)
165
+ contextInfo.putInt(" screenHeight" , screenHeight)
166
+ contextInfo.putDouble(" screenDensity" , screenDensity.toDouble())
167
+
168
+ promise.resolve(contextInfo)
169
+ }
139
170
140
171
fun getReferrer (activity : Activity ): Uri ? {
141
172
return if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .LOLLIPOP_MR1 ) {
0 commit comments