feat(push): 完成 VIVO 推送集成 + Xiaomi 凭据强校验
- XuqmVivoPushReceiver 从 BroadcastReceiver 改为继承 OpenClientPushMessageReceiver,通过 onReceiveRegId 回调获取 regId(修复之前 extractRegId 的脆弱 key 匹配) - VIVO receiver android:exported 从 false 改为 true(跨进程广播必须可导出) - VivoPushService 失败日志级别从 Log.w 提升为 Log.e - Xiaomi/VIVO 凭据必须来自控制台,获取不到时抛出异常(移除 meta-data 本地兜底) - PushSDK.loadVendorConfig 失败时向上抛异常,不再 swallow Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
4f4f8564df
当前提交
344efbb0aa
@ -151,7 +151,7 @@
|
|||||||
android:exported="true" />
|
android:exported="true" />
|
||||||
<receiver
|
<receiver
|
||||||
android:name="com.xuqm.sdk.push.vivo.XuqmVivoPushReceiver"
|
android:name="com.xuqm.sdk.push.vivo.XuqmVivoPushReceiver"
|
||||||
android:exported="false">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.vivo.pushclient.action.RECEIVE" />
|
<action android:name="com.vivo.pushclient.action.RECEIVE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|||||||
@ -304,8 +304,8 @@ object PushSDK {
|
|||||||
honorAppId = pushConfig?.getAsJsonObject("honor")?.get("appId")?.asString.orEmpty(),
|
honorAppId = pushConfig?.getAsJsonObject("honor")?.get("appId")?.asString.orEmpty(),
|
||||||
)
|
)
|
||||||
}.getOrElse { error ->
|
}.getOrElse { error ->
|
||||||
Log.w("XuqmPushSDK", "Unable to load push vendor config: ${error.message}")
|
Log.e("XuqmPushSDK", "Failed to load push vendor config from control plane: ${error.message}")
|
||||||
PushVendorConfig()
|
throw IllegalStateException("Push vendor config unavailable: ${error.message}", error)
|
||||||
}
|
}
|
||||||
cachedVendorConfig = loaded
|
cachedVendorConfig = loaded
|
||||||
cachedConfigAt = now
|
cachedConfigAt = now
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class VivoPushService : PushVendorInterface {
|
|||||||
}
|
}
|
||||||
Log.i(TAG, "Vivo push registration requested")
|
Log.i(TAG, "Vivo push registration requested")
|
||||||
}.onFailure { error ->
|
}.onFailure { error ->
|
||||||
Log.w(TAG, "Vivo push registration failed: ${error.message}")
|
Log.e(TAG, "Vivo push registration failed: ${error.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +1,10 @@
|
|||||||
package com.xuqm.sdk.push.vendor
|
package com.xuqm.sdk.push.vendor
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.xuqm.sdk.push.model.PushVendor
|
import com.xuqm.sdk.push.model.PushVendor
|
||||||
import com.xuqm.sdk.push.model.PushVendorConfig
|
import com.xuqm.sdk.push.model.PushVendorConfig
|
||||||
|
|
||||||
/**
|
|
||||||
* 小米推送集成框架
|
|
||||||
*
|
|
||||||
* MiPush AAR 需要随 sdk-push 发布。注册参数优先来自租户 PUSH 配置,
|
|
||||||
* 旧版本 manifest meta-data 仅作为兼容兜底。
|
|
||||||
*/
|
|
||||||
class XiaomiPushService : PushVendorInterface {
|
class XiaomiPushService : PushVendorInterface {
|
||||||
|
|
||||||
override val vendor: PushVendor = PushVendor.XIAOMI
|
override val vendor: PushVendor = PushVendor.XIAOMI
|
||||||
@ -27,24 +19,20 @@ class XiaomiPushService : PushVendorInterface {
|
|||||||
override fun register(context: Context, config: PushVendorConfig) {
|
override fun register(context: Context, config: PushVendorConfig) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val miPushClass = Class.forName("com.xiaomi.mipush.sdk.MiPushClient")
|
val miPushClass = Class.forName("com.xiaomi.mipush.sdk.MiPushClient")
|
||||||
val meta = context.packageManager.getApplicationInfo(
|
val appId = config.xiaomiAppId
|
||||||
context.packageName, PackageManager.GET_META_DATA
|
val appKey = config.xiaomiAppKey
|
||||||
).metaData ?: Bundle.EMPTY
|
check(appId.isNotBlank() && appKey.isNotBlank()) {
|
||||||
val appId = config.xiaomiAppId.ifBlank { meta.getString("XUQM_XIAOMI_APP_ID", "") }
|
"Xiaomi push credentials not configured on control plane (xiaomi.appId / xiaomi.appKey required)"
|
||||||
val appKey = config.xiaomiAppKey.ifBlank { meta.getString("XUQM_XIAOMI_APP_KEY", "") }
|
|
||||||
if (appId.isNotBlank() && appKey.isNotBlank()) {
|
|
||||||
miPushClass.getMethod(
|
|
||||||
"registerPush",
|
|
||||||
Context::class.java,
|
|
||||||
String::class.java,
|
|
||||||
String::class.java,
|
|
||||||
).invoke(null, context, appId, appKey)
|
|
||||||
Log.i(TAG, "Xiaomi push registration requested")
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Xiaomi appId/appKey not configured, skipping registration")
|
|
||||||
}
|
}
|
||||||
|
miPushClass.getMethod(
|
||||||
|
"registerPush",
|
||||||
|
Context::class.java,
|
||||||
|
String::class.java,
|
||||||
|
String::class.java,
|
||||||
|
).invoke(null, context, appId, appKey)
|
||||||
|
Log.i(TAG, "Xiaomi push registration requested")
|
||||||
}.onFailure { error ->
|
}.onFailure { error ->
|
||||||
Log.w(TAG, "Xiaomi push registration failed: ${error.message}")
|
Log.e(TAG, "Xiaomi push registration failed: ${error.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,44 +1,31 @@
|
|||||||
package com.xuqm.sdk.push.vivo
|
package com.xuqm.sdk.push.vivo
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import com.vivo.push.model.UnvarnishedMessage
|
||||||
|
import com.vivo.push.model.UPSNotificationMessage
|
||||||
|
import com.vivo.push.sdk.OpenClientPushMessageReceiver
|
||||||
import com.xuqm.sdk.push.PushSDK
|
import com.xuqm.sdk.push.PushSDK
|
||||||
import com.xuqm.sdk.push.model.PushVendor
|
import com.xuqm.sdk.push.model.PushVendor
|
||||||
|
|
||||||
class XuqmVivoPushReceiver : BroadcastReceiver() {
|
class XuqmVivoPushReceiver : OpenClientPushMessageReceiver() {
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent?) {
|
override fun onReceiveRegId(context: Context, regId: String) {
|
||||||
if (intent == null) return
|
if (regId.isBlank()) return
|
||||||
val appContext = context.applicationContext
|
Log.i(TAG, "Vivo push registered: regId=$regId")
|
||||||
val regId = extractRegId(intent) ?: currentRegId(appContext)
|
|
||||||
if (regId.isNullOrBlank()) return
|
|
||||||
runCatching {
|
runCatching {
|
||||||
PushSDK.updateNativePushToken(appContext, PushVendor.VIVO, regId)
|
PushSDK.updateNativePushToken(context.applicationContext, PushVendor.VIVO, regId)
|
||||||
}.onFailure { error ->
|
}.onFailure { error ->
|
||||||
Log.w(TAG, "Unable to persist vivo push token: ${error.message}")
|
Log.e(TAG, "Unable to persist vivo push token: ${error.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractRegId(intent: Intent): String? {
|
override fun onTransmissionMessage(context: Context, message: UnvarnishedMessage) {
|
||||||
val extras = intent.extras ?: return null
|
Log.d(TAG, "Vivo pass-through message received: ${message.content}")
|
||||||
for (key in extras.keySet()) {
|
|
||||||
val value = extras.get(key) as? String ?: continue
|
|
||||||
if (key.contains("reg", ignoreCase = true) || key.contains("token", ignoreCase = true)) {
|
|
||||||
return value.takeIf { it.isNotBlank() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun currentRegId(context: Context): String? {
|
override fun onNotificationMessageClicked(context: Context, message: UPSNotificationMessage) {
|
||||||
return runCatching {
|
Log.d(TAG, "Vivo notification clicked: ${message.title}")
|
||||||
val pushClientClass = Class.forName("com.vivo.push.PushClient")
|
|
||||||
val instance = pushClientClass.getMethod("getInstance", Context::class.java)
|
|
||||||
.invoke(null, context)
|
|
||||||
pushClientClass.getMethod("getRegId").invoke(instance) as? String
|
|
||||||
}.getOrNull()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户