fix(push): complete OPPO offline push registration

这个提交包含在:
XuqmGroup 2026-07-13 16:12:06 +08:00
父节点 1cdcc7e7b4
当前提交 999e21bcf2
共有 3 个文件被更改,包括 56 次插入114 次删除

查看文件

@ -17,6 +17,10 @@
# ── Vendor push services instantiated via reflection inside PushSDK ───────── # ── Vendor push services instantiated via reflection inside PushSDK ─────────
-keep class com.xuqm.sdk.push.vendor.** { *; } -keep class com.xuqm.sdk.push.vendor.** { *; }
# OPPO SDK is initialized from the vendor adapter and also instantiates callback
# services from the manifest. Keep its API and service classes in minified apps.
-keep class com.heytap.msp.** { *; }
# ── Enum values used as strings ─────────────────────────────────────────────── # ── Enum values used as strings ───────────────────────────────────────────────
-keepclassmembers enum com.xuqm.sdk.push.model.PushVendor { -keepclassmembers enum com.xuqm.sdk.push.model.PushVendor {
public static **[] values(); public static **[] values();

查看文件

@ -346,7 +346,7 @@ object PushSDK {
xiaomiAppId = pushConfig?.getAsJsonObject("xiaomi")?.get("appId")?.asString.orEmpty(), xiaomiAppId = pushConfig?.getAsJsonObject("xiaomi")?.get("appId")?.asString.orEmpty(),
xiaomiAppKey = pushConfig?.getAsJsonObject("xiaomi")?.get("appKey")?.asString.orEmpty(), xiaomiAppKey = pushConfig?.getAsJsonObject("xiaomi")?.get("appKey")?.asString.orEmpty(),
oppoAppKey = pushConfig?.getAsJsonObject("oppo")?.get("appKey")?.asString.orEmpty(), oppoAppKey = pushConfig?.getAsJsonObject("oppo")?.get("appKey")?.asString.orEmpty(),
oppoAppSecret = pushConfig?.getAsJsonObject("oppo")?.get("masterSecret")?.asString.orEmpty(), oppoAppSecret = pushConfig?.getAsJsonObject("oppo")?.get("appSecret")?.asString.orEmpty(),
vivoAppId = pushConfig?.getAsJsonObject("vivo")?.get("appId")?.asString.orEmpty(), vivoAppId = pushConfig?.getAsJsonObject("vivo")?.get("appId")?.asString.orEmpty(),
vivoAppKey = pushConfig?.getAsJsonObject("vivo")?.get("appKey")?.asString.orEmpty(), vivoAppKey = pushConfig?.getAsJsonObject("vivo")?.get("appKey")?.asString.orEmpty(),
honorAppId = pushConfig?.getAsJsonObject("honor")?.get("appId")?.asString.orEmpty(), honorAppId = pushConfig?.getAsJsonObject("honor")?.get("appId")?.asString.orEmpty(),

查看文件

@ -1,150 +1,88 @@
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.heytap.msp.push.HeytapPushManager
import com.heytap.msp.push.callback.ICallBackResultService
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
import com.xuqm.sdk.push.model.PushVendorConfig import com.xuqm.sdk.push.model.PushVendorConfig
import java.lang.reflect.Proxy
/** /** OPPO/OnePlus/realme 离线推送注册。凭据来自租户 PUSH 配置。 */
* OPPO 推送集成OPPO Push 依赖由 sdk-push 自身声明注册参数优先来自租户 PUSH 配置
*/
class OppoPushService : PushVendorInterface { class OppoPushService : PushVendorInterface {
override val vendor: PushVendor = PushVendor.OPPO override val vendor: PushVendor = PushVendor.OPPO
override fun isAvailable(context: Context): Boolean { override fun isAvailable(context: Context): Boolean =
return runCatching { runCatching { HeytapPushManager.isSupportPush(context.applicationContext) }
resolvePushManagerClass() .onFailure { Log.w(TAG, "OPPO push availability check failed: ${it.message}") }
true .getOrDefault(false)
}.getOrDefault(false)
}
override fun register(context: Context, config: PushVendorConfig) { override fun register(context: Context, config: PushVendorConfig) {
runCatching { val appContext = context.applicationContext
val meta = context.packageManager.getApplicationInfo( val appKey = config.oppoAppKey.trim()
context.packageName, PackageManager.GET_META_DATA val appSecret = config.oppoAppSecret.trim()
).metaData ?: Bundle.EMPTY if (appKey.isBlank() || appSecret.isBlank()) {
val appKey = config.oppoAppKey.ifBlank { meta.getString("XUQM_OPPO_APP_KEY", "") } Log.e(TAG, "OPPO appKey/appSecret not configured on control plane, skipping registration")
val appSecret = config.oppoAppSecret.ifBlank { meta.getString("XUQM_OPPO_APP_SECRET", "") } return
}
if (appKey.isNotBlank() && appSecret.isNotBlank()) { runCatching {
if (!registerWithHeytapMsp(context, appKey, appSecret)) { HeytapPushManager.init(appContext, false)
registerWithLegacyMcs(context, appKey, appSecret) if (!HeytapPushManager.isSupportPush(appContext)) {
Log.w(TAG, "OPPO push is not supported on this device")
return
} }
HeytapPushManager.register(appContext, appKey, appSecret, callback(appContext))
runCatching { HeytapPushManager.requestNotificationPermission() }
Log.i(TAG, "OPPO push registration requested") Log.i(TAG, "OPPO push registration requested")
} else {
Log.w(TAG, "OPPO appKey/appSecret not configured, skipping registration")
}
}.onFailure { error -> }.onFailure { error ->
Log.w(TAG, "OPPO push registration failed: ${error.message}") Log.e(TAG, "OPPO push registration failed: ${error.message}", error)
} }
} }
override fun unregister(context: Context) { override fun unregister(context: Context) {
runCatching { runCatching {
val pushManagerClass = resolvePushManagerClass() HeytapPushManager.unRegister()
if (pushManagerClass.name == "com.heytap.msp.push.HeytapPushManager") {
pushManagerClass.getMethod("unRegister").invoke(null)
} else {
val instance = pushManagerClass.getMethod("getInstance").invoke(null)
pushManagerClass.getMethod("unRegister", Context::class.java).invoke(instance, context)
}
Log.i(TAG, "OPPO push unregistered") Log.i(TAG, "OPPO push unregistered")
}.onFailure { error -> }.onFailure { error ->
Log.w(TAG, "OPPO push unregistration failed: ${error.message}") Log.w(TAG, "OPPO push unregistration failed: ${error.message}")
} }
} }
companion object { private fun callback(context: Context) = object : ICallBackResultService {
private const val TAG = "OppoPushService" override fun onRegister(code: Int, regId: String?) {
if (code == SUCCESS && !regId.isNullOrBlank()) {
private fun resolvePushManagerClass(): Class<*> {
return runCatching {
Class.forName("com.heytap.msp.push.HeytapPushManager")
}.getOrElse {
Class.forName("com.heytap.mcssdk.PushManager")
}
}
}
private fun registerWithHeytapMsp(
context: Context,
appKey: String,
appSecret: String,
): Boolean {
val pushManagerClass = runCatching {
Class.forName("com.heytap.msp.push.HeytapPushManager")
}.getOrNull() ?: return false
runCatching {
pushManagerClass.getMethod("init", Context::class.java, java.lang.Boolean.TYPE)
.invoke(null, context, false)
}
val supported = runCatching {
pushManagerClass.getMethod("isSupportPush", Context::class.java)
.invoke(null, context) as? Boolean
}.getOrElse {
runCatching { pushManagerClass.getMethod("isSupportPush").invoke(null) as? Boolean }
.getOrDefault(true)
} ?: true
if (!supported) {
Log.w(TAG, "OPPO push is not supported on this device")
return true
}
val callbackClass = Class.forName("com.heytap.msp.push.callback.ICallBackResultService")
val callback = buildCallback(context.applicationContext, callbackClass)
pushManagerClass.getMethod(
"register",
Context::class.java,
String::class.java,
String::class.java,
callbackClass,
).invoke(null, context, appKey, appSecret, callback)
runCatching { pushManagerClass.getMethod("requestNotificationPermission").invoke(null) }
return true
}
private fun registerWithLegacyMcs(
context: Context,
appKey: String,
appSecret: String,
) {
val pushManagerClass = Class.forName("com.heytap.mcssdk.PushManager")
val instance = pushManagerClass.getMethod("getInstance").invoke(null)
val callbackClass = Class.forName("com.heytap.mcssdk.callback.PushCallback")
val callback = buildCallback(context.applicationContext, callbackClass)
pushManagerClass.getMethod(
"register",
Context::class.java,
String::class.java,
String::class.java,
callbackClass,
).invoke(instance, context, appKey, appSecret, callback)
}
private fun buildCallback(context: Context, callbackClass: Class<*>): Any {
return Proxy.newProxyInstance(
callbackClass.classLoader,
arrayOf(callbackClass)
) { _, method, args ->
if (method.name == "onRegister") {
val code = args?.getOrNull(0) as? Int
val regId = args?.getOrNull(1) as? String
if ((code == null || code == 0) && !regId.isNullOrBlank()) {
PushSDK.updateNativePushToken(context, vendor, regId) PushSDK.updateNativePushToken(context, vendor, regId)
Log.i(TAG, "OPPO push token acquired") Log.i(TAG, "OPPO push token acquired")
} else { } else {
Log.w(TAG, "OPPO push register callback code=$code") Log.e(TAG, "OPPO push register callback failed: code=$code, message=$regId")
} }
} }
null
override fun onUnRegister(code: Int) {
Log.i(TAG, "OPPO push unregister callback: code=$code")
}
override fun onSetPushTime(code: Int, message: String?) {
Log.d(TAG, "OPPO set push time callback: code=$code, message=$message")
}
override fun onGetPushStatus(code: Int, status: Int) {
Log.d(TAG, "OPPO push status callback: code=$code, status=$status")
}
override fun onGetNotificationStatus(code: Int, status: Int) {
Log.d(TAG, "OPPO notification status callback: code=$code, status=$status")
}
override fun onError(code: Int, message: String?) {
Log.e(TAG, "OPPO push error: code=$code, message=$message")
} }
} }
private companion object {
const val TAG = "OppoPushService"
const val SUCCESS = 0
}
} }