Skip to content

Commit 06a697d

Browse files
committed
simplify device id stuff
1 parent 4735527 commit 06a697d

File tree

5 files changed

+49
-43
lines changed

5 files changed

+49
-43
lines changed

android/src/main/java/com/amplitude/android/Amplitude.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.amplitude.android.migration.MigrationManager
66
import com.amplitude.android.plugins.AnalyticsConnectorIdentityPlugin
77
import com.amplitude.android.plugins.AnalyticsConnectorPlugin
88
import com.amplitude.android.plugins.AndroidContextPlugin
9+
import com.amplitude.android.plugins.AndroidContextPlugin.Companion.validDeviceId
910
import com.amplitude.android.plugins.AndroidLifecyclePlugin
1011
import com.amplitude.android.plugins.AndroidNetworkConnectivityCheckerPlugin
1112
import com.amplitude.android.storage.AndroidStorageContextV3
@@ -96,7 +97,11 @@ open class Amplitude internal constructor(
9697
}
9798
androidContextPlugin = AndroidContextPlugin()
9899
add(androidContextPlugin)
99-
setDeviceId(androidContextPlugin.generateDeviceId(forceNew = false))
100+
val deviceId =
101+
configuration.deviceId
102+
?: store.deviceId?.takeIf { validDeviceId(it, allowAppSetId = false) }
103+
?: androidContextPlugin.createDeviceId()
104+
setDeviceId(deviceId)
100105
add(GetAmpliExtrasPlugin())
101106
add(AndroidLifecyclePlugin(activityLifecycleCallbacks))
102107
add(AnalyticsConnectorIdentityPlugin())
@@ -117,7 +122,7 @@ open class Amplitude internal constructor(
117122
logger.error("Cannot reset identity before Amplitude is initialized.")
118123
return this
119124
}
120-
val newDeviceId = androidContextPlugin.generateDeviceId(forceNew = true)
125+
val newDeviceId = configuration.deviceId ?: androidContextPlugin.createDeviceId()
121126
val newIdentity = Identity(userId = null, deviceId = newDeviceId)
122127
store.identity = newIdentity
123128
(timeline as Timeline).queueSetIdentity(newIdentity)

android/src/main/java/com/amplitude/android/plugins/AndroidContextPlugin.kt

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,12 @@ open class AndroidContextPlugin : ContextPlugin() {
3030
}
3131

3232
/**
33-
* Generate a device ID using Android-specific logic.
34-
* Priority: configuration -> store (if not forceNew) -> advertising ID -> app set ID -> random UUID
35-
*
36-
* @param forceNew If true, skip checking the store and generate a fresh deviceId
37-
* @return the generated device ID (never null for Android)
33+
* Create a device ID from available sources.
34+
* Priority: advertising ID -> app set ID -> random UUID
3835
*/
39-
fun generateDeviceId(forceNew: Boolean = false): String {
36+
internal fun createDeviceId(): String {
4037
val configuration = amplitude.configuration as Configuration
4138

42-
// Check configuration (always respected, even with forceNew)
43-
configuration.deviceId?.let { return it }
44-
45-
// Check store (skip if forcing new)
46-
if (!forceNew) {
47-
amplitude.store.deviceId?.let { deviceId ->
48-
if (validDeviceId(deviceId) && !deviceId.endsWith("S")) {
49-
return deviceId
50-
}
51-
}
52-
}
53-
5439
// Check advertising ID (if enabled and not per-install)
5540
if (!configuration.newDeviceIdPerInstall &&
5641
configuration.useAdvertisingIdForDeviceId &&
@@ -67,21 +52,25 @@ open class AndroidContextPlugin : ContextPlugin() {
6752
if (configuration.useAppSetIdForDeviceId) {
6853
contextProvider.appSetId?.let { appSetId ->
6954
if (validDeviceId(appSetId)) {
70-
return "${appSetId}S"
55+
return "$appSetId$DEVICE_ID_SUFFIX_APP_SET_ID"
7156
}
7257
}
7358
}
7459

7560
// Generate random ID
76-
return UUID.randomUUID().toString() + "R"
61+
return UUID.randomUUID().toString() + DEVICE_ID_SUFFIX_RANDOM
7762
}
7863

7964
@Deprecated(
8065
message = "Use generateDeviceId() instead. Amplitude now handles setting the deviceId.",
8166
replaceWith = ReplaceWith("generateDeviceId()"),
8267
)
8368
fun initializeDeviceId(configuration: Configuration) {
84-
amplitude.setDeviceId(generateDeviceId(forceNew = false))
69+
val deviceId =
70+
configuration.deviceId
71+
?: amplitude.store.deviceId?.takeIf { validDeviceId(it, allowAppSetId = false) }
72+
?: createDeviceId()
73+
amplitude.setDeviceId(deviceId)
8574
}
8675

8776
@Deprecated(
@@ -187,11 +176,33 @@ open class AndroidContextPlugin : ContextPlugin() {
187176
const val PLATFORM = "Android"
188177
const val SDK_LIBRARY = "amplitude-analytics-android"
189178
const val SDK_VERSION = BuildConfig.AMPLITUDE_VERSION
179+
180+
/**
181+
* Device ID suffix indicating the ID was derived from App Set ID.
182+
*
183+
* When a stored device ID ends with this suffix, [createDeviceId] will attempt
184+
* to regenerate it to potentially upgrade to a better identifier (e.g., advertising ID
185+
* if the user later grants permission).
186+
*/
187+
private const val DEVICE_ID_SUFFIX_APP_SET_ID = "S"
188+
189+
/**
190+
* Device ID suffix indicating the ID is a randomly generated UUID.
191+
*/
192+
private const val DEVICE_ID_SUFFIX_RANDOM = "R"
193+
190194
private val INVALID_DEVICE_IDS =
191195
setOf("", "9774d56d682e549c", "unknown", "000000000000000", "Android", "DEFACE", "00000000-0000-0000-0000-000000000000")
192196

193-
fun validDeviceId(deviceId: String): Boolean {
194-
return !(deviceId.isEmpty() || INVALID_DEVICE_IDS.contains(deviceId))
197+
fun validDeviceId(
198+
deviceId: String,
199+
allowAppSetId: Boolean = true,
200+
): Boolean {
201+
return when {
202+
deviceId.isEmpty() || INVALID_DEVICE_IDS.contains(deviceId) -> false
203+
!allowAppSetId && deviceId.endsWith(DEVICE_ID_SUFFIX_APP_SET_ID) -> false
204+
else -> true
205+
}
195206
}
196207
}
197208
}

core/src/main/java/com/amplitude/core/Amplitude.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,8 @@ open class Amplitude(
163163
EventBridgeContainer.getInstance(
164164
configuration.instanceName,
165165
).eventBridge.setEventReceiver(EventChannel.EVENT, AnalyticsEventReceiver(this))
166-
val contextPlugin = ContextPlugin()
167-
add(contextPlugin)
168-
contextPlugin.generateDeviceId()?.let { setDeviceId(it) }
166+
configuration.deviceId?.let { setDeviceId(it) }
167+
add(ContextPlugin())
169168
add(GetAmpliExtrasPlugin())
170169
add(AmplitudeDestination())
171170
}

core/src/main/java/com/amplitude/core/State.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ class State {
6060
/**
6161
* Notify observers about identity change. Called outside the lock.
6262
*/
63-
private fun notifyObservers(changeInfo: IdentityChangeInfo) = with(changeInfo) {
64-
plugins.forEach { plugin ->
65-
if (userIdChanged) plugin.onUserIdChanged(changeInfo.newIdentity.userId)
66-
if (deviceIdChanged) plugin.onDeviceIdChanged(changeInfo.newIdentity.deviceId)
63+
private fun notifyObservers(changeInfo: IdentityChangeInfo) =
64+
with(changeInfo) {
65+
plugins.forEach { plugin ->
66+
if (userIdChanged) plugin.onUserIdChanged(changeInfo.newIdentity.userId)
67+
if (deviceIdChanged) plugin.onDeviceIdChanged(changeInfo.newIdentity.deviceId)
68+
}
6769
}
68-
}
6970

7071
private data class IdentityChangeInfo(
7172
val newIdentity: Identity,

core/src/main/java/com/amplitude/core/platform/plugins/ContextPlugin.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,6 @@ open class ContextPlugin : Plugin {
1010
override val type: Plugin.Type = Plugin.Type.Before
1111
override lateinit var amplitude: Amplitude
1212

13-
/**
14-
* Generate a device ID based on platform-specific logic.
15-
* Subclasses can override to provide platform-specific generation (e.g., advertising ID).
16-
*
17-
* @return the generated device ID, or null if no deviceId is configured
18-
*/
19-
open fun generateDeviceId(): String? {
20-
return amplitude.configuration.deviceId
21-
}
22-
2313
override fun execute(event: BaseEvent): BaseEvent? {
2414
applyContextData(event)
2515
return event

0 commit comments

Comments
 (0)