diff --git a/sdk-core/src/main/java/com/xuqm/sdk/utils/DeviceUtils.kt b/sdk-core/src/main/java/com/xuqm/sdk/utils/DeviceUtils.kt index 6f0348b..d81cf3a 100644 --- a/sdk-core/src/main/java/com/xuqm/sdk/utils/DeviceUtils.kt +++ b/sdk-core/src/main/java/com/xuqm/sdk/utils/DeviceUtils.kt @@ -1,14 +1,15 @@ package com.xuqm.sdk.utils -import android.content.Context import android.os.Build -import android.provider.Settings +import com.xuqm.sdk.XuqmSDK object DeviceUtils { - fun getDeviceId(context: Context): String = - Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID) - ?: Build.FINGERPRINT + /** + * 获取统一设备 ID(来源:XuqmSDK.deviceId)。 + * 所有 SDK 模块应使用此方法获取 deviceId,确保同一设备在所有服务中标识一致。 + */ + fun getDeviceId(): String = XuqmSDK.deviceId fun getDeviceModel(): String = "${Build.MANUFACTURER} ${Build.MODEL}" @@ -21,4 +22,13 @@ object DeviceUtils { "vivo", "iqoo" -> "VIVO" else -> "FCM" } + + /** 获取完整设备信息 Map,用于 API 上报。 */ + fun getDeviceInfo(): Map = mapOf( + "deviceId" to getDeviceId(), + "model" to getDeviceModel(), + "osVersion" to getOsVersion(), + "vendor" to getVendor(), + "platform" to "ANDROID", + ) } diff --git a/sdk-license/src/main/java/com/xuqm/sdk/license/LicenseSDK.kt b/sdk-license/src/main/java/com/xuqm/sdk/license/LicenseSDK.kt index 9a773cc..7cc77a0 100644 --- a/sdk-license/src/main/java/com/xuqm/sdk/license/LicenseSDK.kt +++ b/sdk-license/src/main/java/com/xuqm/sdk/license/LicenseSDK.kt @@ -226,7 +226,7 @@ object LicenseSDK { private fun getOrCreateDeviceId(): String { store.deviceId?.let { return it } - val newId = DeviceInfoProvider.getDeviceId(appContext) + val newId = DeviceInfoProvider.getDeviceId() store.deviceId = newId return newId } diff --git a/sdk-license/src/main/java/com/xuqm/sdk/license/internal/DeviceInfoProvider.kt b/sdk-license/src/main/java/com/xuqm/sdk/license/internal/DeviceInfoProvider.kt index 8f07cbd..7769e23 100644 --- a/sdk-license/src/main/java/com/xuqm/sdk/license/internal/DeviceInfoProvider.kt +++ b/sdk-license/src/main/java/com/xuqm/sdk/license/internal/DeviceInfoProvider.kt @@ -1,50 +1,22 @@ package com.xuqm.sdk.license.internal -import android.content.Context import android.os.Build -import android.provider.Settings -import java.util.UUID +import com.xuqm.sdk.utils.DeviceUtils /** * Provides stable device information for license checks. + * deviceId 统一使用 XuqmSDK.deviceId(通过 DeviceUtils)。 */ internal object DeviceInfoProvider { - private const val FALLBACK_PREFS = "xuqm_license_device_fallback" - private const val KEY_FALLBACK_ID = "fallback_device_id" + /** 统一设备 ID,来源:XuqmSDK.deviceId */ + fun getDeviceId(): String = DeviceUtils.getDeviceId() - /** - * Get stable device ID. - * Priority: - * 1. ANDROID_ID (stable per app signing key + device + user, survives reinstall with same signer) - * 2. Persisted fallback UUID - * - * Note: ANDROID_ID changes on factory reset or if app is reinstalled with different signing key. - */ - fun getDeviceId(context: Context): String { - val androidId = try { - Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID) - } catch (_: Exception) { null } - - if (!androidId.isNullOrBlank() && androidId != "9774d56d682e549c") { - return androidId - } - - // Fallback to persisted UUID - val prefs = context.getSharedPreferences(FALLBACK_PREFS, Context.MODE_PRIVATE) - var fallbackId = prefs.getString(KEY_FALLBACK_ID, null) - if (fallbackId == null) { - fallbackId = UUID.randomUUID().toString() - prefs.edit().putString(KEY_FALLBACK_ID, fallbackId).apply() - } - return fallbackId - } - - fun getDeviceModel(): String = "${Build.MANUFACTURER} ${Build.MODEL}" + fun getDeviceModel(): String = DeviceUtils.getDeviceModel() fun getDeviceVendor(): String = Build.MANUFACTURER - fun getOsVersion(): String = "Android ${Build.VERSION.RELEASE}" + fun getOsVersion(): String = DeviceUtils.getOsVersion() fun getDeviceName(): String = getDeviceModel() } diff --git a/sdk-push/src/main/java/com/xuqm/sdk/push/PushSDK.kt b/sdk-push/src/main/java/com/xuqm/sdk/push/PushSDK.kt index 3fa22db..bc68895 100644 --- a/sdk-push/src/main/java/com/xuqm/sdk/push/PushSDK.kt +++ b/sdk-push/src/main/java/com/xuqm/sdk/push/PushSDK.kt @@ -54,7 +54,7 @@ object PushSDK { api.setReceivePush( appKey = XuqmSDK.appKey, userId = userId, - deviceId = DeviceUtils.getDeviceId(context), + deviceId = DeviceUtils.getDeviceId(), enabled = enabled, ) if (enabled) { @@ -127,7 +127,7 @@ object PushSDK { fun currentRegistration(context: Context): PushRegistrationSnapshot? { XuqmSDK.requireInit() - val deviceId = DeviceUtils.getDeviceId(context) + val deviceId = DeviceUtils.getDeviceId() val detectedVendor = detectVendor() val registration = store(context).load(deviceId = deviceId, fallbackVendor = detectedVendor) ?: return null @@ -190,7 +190,7 @@ object PushSDK { val registration = currentRegistration(context) val vendor = registration?.vendor ?: detectVendor() val pushToken = registration?.pushToken?.takeIf { it.isNotBlank() } - val deviceId = DeviceUtils.getDeviceId(context) + val deviceId = DeviceUtils.getDeviceId() if (pushToken.isNullOrBlank()) { Log.w("XuqmPushSDK", "Native push token not ready yet, waiting for onNewToken()") ensureNativePushTokenInternal(context) @@ -215,8 +215,8 @@ object PushSDK { vendor = vendor.name, token = pushToken, deviceId = deviceId, - brand = Build.MANUFACTURER.orEmpty(), - model = Build.MODEL.orEmpty(), + brand = DeviceUtils.getVendor(), + model = DeviceUtils.getDeviceModel(), osVersion = DeviceUtils.getOsVersion(), appVersion = appVersion(context), ) @@ -235,14 +235,14 @@ object PushSDK { scope.launch { runCatching { val reg = store(XuqmSDK.appContext).load( - deviceId = DeviceUtils.getDeviceId(XuqmSDK.appContext), + deviceId = DeviceUtils.getDeviceId(), fallbackVendor = detectVendor(), ) api.unregisterDevice( XuqmSDK.appKey, userId, reg?.vendor?.name ?: detectVendor().name, - DeviceUtils.getDeviceId(XuqmSDK.appContext), + DeviceUtils.getDeviceId(), ) registeredUserId.compareAndSet(userId, null) store(XuqmSDK.appContext).updateLastUserId(null) @@ -272,7 +272,7 @@ object PushSDK { private fun isReceivePushEnabled(context: Context): Boolean = store(context).load( - deviceId = DeviceUtils.getDeviceId(context), + deviceId = DeviceUtils.getDeviceId(), fallbackVendor = detectVendor(), )?.receivePush ?: true diff --git a/sdk-update/src/main/java/com/xuqm/sdk/update/UpdateSDK.kt b/sdk-update/src/main/java/com/xuqm/sdk/update/UpdateSDK.kt index 6a078f2..6f5d92c 100644 --- a/sdk-update/src/main/java/com/xuqm/sdk/update/UpdateSDK.kt +++ b/sdk-update/src/main/java/com/xuqm/sdk/update/UpdateSDK.kt @@ -184,7 +184,17 @@ object UpdateSDK { } runCatching { - val response = api.checkUpdate(XuqmSDK.appKey, "ANDROID", versionCode, userId) + val deviceInfo = com.xuqm.sdk.utils.DeviceUtils.getDeviceInfo() + val response = api.checkUpdate( + appKey = XuqmSDK.appKey, + platform = "ANDROID", + currentVersionCode = versionCode, + userId = userId, + deviceId = deviceInfo["deviceId"], + model = deviceInfo["model"], + osVersion = deviceInfo["osVersion"], + vendor = deviceInfo["vendor"], + ) if (response.code == 40404) { throw IllegalStateException("更新服务未开通 (code=40404) [appKey=${XuqmSDK.appKey}]") } diff --git a/sdk-update/src/main/java/com/xuqm/sdk/update/api/UpdateApi.kt b/sdk-update/src/main/java/com/xuqm/sdk/update/api/UpdateApi.kt index 140f698..dc520f2 100644 --- a/sdk-update/src/main/java/com/xuqm/sdk/update/api/UpdateApi.kt +++ b/sdk-update/src/main/java/com/xuqm/sdk/update/api/UpdateApi.kt @@ -40,5 +40,9 @@ internal interface UpdateApi { @Query("platform") platform: String, @Query("currentVersionCode") currentVersionCode: Int, @Query("userId") userId: String? = null, + @Query("deviceId") deviceId: String? = null, + @Query("model") model: String? = null, + @Query("osVersion") osVersion: String? = null, + @Query("vendor") vendor: String? = null, ): ApiResponse }