From 7063d102a231daa6591abdba356d0dcc16cca446 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Fri, 26 Jun 2026 12:21:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(sdk):=20=E6=96=B0=E5=A2=9E=20ROM=20?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E4=B8=8A=E6=8A=A5=E5=8F=8A=20VIVO=20?= =?UTF-8?q?=E9=9A=90=E7=A7=81=E5=8D=8F=E8=AE=AE=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DeviceUtils.getRomVersion() 通过反射读取厂商 ROM 版本(MIUI/EMUI/OriginOS/ColorOS/MagicOS) - PushApi/PushSDK: 注册时上报 romVersion 字段 - VivoPushService: 记录 agreePrivacyStatement 是否成功的明确日志,便于诊断 Co-Authored-By: Claude Sonnet 4.6 --- .../java/com/xuqm/sdk/utils/DeviceUtils.kt | 23 +++++++++++++++++++ .../main/java/com/xuqm/sdk/push/PushSDK.kt | 10 +++++++- .../java/com/xuqm/sdk/push/api/PushApi.kt | 1 + .../xuqm/sdk/push/vendor/VivoPushService.kt | 7 +++++- 4 files changed, 39 insertions(+), 2 deletions(-) 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 d81cf3a..e53f6a8 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 @@ -15,6 +15,29 @@ object DeviceUtils { fun getOsVersion(): String = "Android ${Build.VERSION.RELEASE}" + /** + * 读取厂商 ROM 版本号(MIUI / EMUI / OriginOS / ColorOS / MagicOS 等)。 + * 通过反射读取系统属性,失败时返回 null。 + */ + fun getRomVersion(): String? { + val props = listOf( + "ro.miui.ui.version.name", // MIUI + "ro.build.version.emui", // EMUI / HarmonyOS + "ro.vivo.os.version", // OriginOS (VIVO) + "ro.funtouch.os_version", // FuntouchOS (旧 VIVO) + "ro.color.os.version", // ColorOS (OPPO) + "ro.build.version.opporom", // ColorOS 旧版 + "ro.build.version.magic_os", // MagicOS (Honor) + ) + return try { + val cls = Class.forName("android.os.SystemProperties") + val get = cls.getMethod("get", String::class.java, String::class.java) + props.firstNotNullOfOrNull { key -> + (get.invoke(null, key, "") as? String)?.takeIf { it.isNotBlank() } + } + } catch (_: Exception) { null } + } + fun getVendor(): String = when (Build.MANUFACTURER.lowercase()) { "huawei", "honor" -> if (Build.MANUFACTURER.lowercase() == "honor") "HONOR" else "HUAWEI" "xiaomi", "redmi" -> "XIAOMI" 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 470d04a..ede4fa1 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 @@ -135,6 +135,7 @@ object PushSDK { fun onSdkLogin(session: XuqmLoginSession) { val context = runCatching { XuqmSDK.appContext }.getOrNull() ?: return + Log.d("XuqmPushSDK", "onSdkLogin: userId=${session.userId} registeredUserId=${registeredUserId.get()}") if (registeredUserId.get() == session.userId) return initializeVendorsInternal(context) bindImUserInternal(context, session.userId) @@ -150,6 +151,7 @@ object PushSDK { // ── Internal push registration flow ─────────────────────────────────────── internal fun updateNativePushToken(context: Context, vendor: PushVendor, pushToken: String) { + Log.i("XuqmPushSDK", "updateNativePushToken called: vendor=$vendor token=${pushToken.take(12)}...") XuqmSDK.requireInit() val detectedVendor = detectVendor() if (vendor != detectedVendor) { @@ -160,6 +162,7 @@ object PushSDK { require(normalizedToken.isNotBlank()) { "pushToken must not be blank" } store(context).save(vendor, normalizedToken) val sessionUserId = XuqmSDK.getUserId() + Log.i("XuqmPushSDK", "updateNativePushToken: saved token, sessionUserId=$sessionUserId") if (sessionUserId != null) { bindImUserInternal(context, sessionUserId) } @@ -220,6 +223,7 @@ object PushSDK { } private fun bindImUserInternal(context: Context, userId: String) { + Log.i("XuqmPushSDK", "bindImUserInternal: userId=$userId receivePushEnabled=${isReceivePushEnabled(context)}") if (!isReceivePushEnabled(context)) return ensureNativePushTokenInternal(context) registerDeviceInternal(context, userId) @@ -238,7 +242,7 @@ object PushSDK { } val registrationKey = listOf(userId, vendor.name, pushToken, deviceId).joinToString("|") if (lastRegisteredDeviceKey.get() == registrationKey) { - Log.d("XuqmPushSDK", "Skipping duplicate push device registration for userId=$userId vendor=${vendor.name}") + Log.i("XuqmPushSDK", "Skipping duplicate push device registration for userId=$userId vendor=${vendor.name}") return } if (!registeringDeviceKey.compareAndSet(null, registrationKey)) { @@ -249,6 +253,7 @@ object PushSDK { } scope.launch { runCatching { + Log.i("XuqmPushSDK", "Registering push device: userId=$userId vendor=${vendor.name} token=${pushToken.take(12)}...") api.registerDevice( appKey = XuqmSDK.appKey, userId = userId, @@ -259,11 +264,14 @@ object PushSDK { model = DeviceUtils.getDeviceModel(), osVersion = DeviceUtils.getOsVersion(), appVersion = appVersion(context), + romVersion = DeviceUtils.getRomVersion(), ) registeredUserId.set(userId) lastRegisteredDeviceKey.set(registrationKey) store(context).updateLastUserId(userId) Log.i("XuqmPushSDK", "Registered push device for userId=$userId vendor=${vendor.name}") + }.onFailure { e -> + Log.e("XuqmPushSDK", "Push device registration failed for userId=$userId: ${e.message}", e) }.also { registeringDeviceKey.compareAndSet(registrationKey, null) } diff --git a/sdk-push/src/main/java/com/xuqm/sdk/push/api/PushApi.kt b/sdk-push/src/main/java/com/xuqm/sdk/push/api/PushApi.kt index 623fe75..933fd30 100644 --- a/sdk-push/src/main/java/com/xuqm/sdk/push/api/PushApi.kt +++ b/sdk-push/src/main/java/com/xuqm/sdk/push/api/PushApi.kt @@ -18,6 +18,7 @@ interface PushApi { @Query("osVersion") osVersion: String, @Query("platform") platform: String = "ANDROID", @Query("appVersion") appVersion: String? = null, + @Query("romVersion") romVersion: String? = null, ) @DELETE("api/push/unregister") diff --git a/sdk-push/src/main/java/com/xuqm/sdk/push/vendor/VivoPushService.kt b/sdk-push/src/main/java/com/xuqm/sdk/push/vendor/VivoPushService.kt index ff49ad2..438cc8d 100644 --- a/sdk-push/src/main/java/com/xuqm/sdk/push/vendor/VivoPushService.kt +++ b/sdk-push/src/main/java/com/xuqm/sdk/push/vendor/VivoPushService.kt @@ -41,10 +41,15 @@ class VivoPushService : PushVendorInterface { // v4.x SDK: initialize(PushConfig) — the no-arg overload is private val builderClass = Class.forName("com.vivo.push.PushConfig\$Builder") val builder = builderClass.getConstructor().newInstance() - runCatching { + val privacySet = runCatching { builderClass.getMethod("agreePrivacyStatement", Boolean::class.javaPrimitiveType) .invoke(builder, true) + true + }.getOrElse { e -> + Log.w(TAG, "agreePrivacyStatement not available in this SDK version: ${e.message}") + false } + Log.i(TAG, "Vivo push PushConfig built: agreePrivacyStatement=$privacySet") val pushConfig = builderClass.getMethod("build").invoke(builder) val pushConfigClass = Class.forName("com.vivo.push.PushConfig") pushClientClass.getMethod("initialize", pushConfigClass).invoke(instance, pushConfig)