友盟廠商推送華為獲取Token報錯:ApiException: 907135003,bks證書檢驗失敗

ZhaoYun 2021-08-15 18:16:45 阅读数:575

本文一共[544]字,预计阅读时长:1分钟~
推送 token apiexception bks

問題出現:

項目需要使用接入友盟廠商推送,在其他廠商都調試成功了,在測試華為廠商推送的時候,初始化一直報錯HuaWeiRegister: getToken failed.ApiException: 907135003: client api invalid

I/NAccs.HuaWeiRegister: register begin isChannel:false
I/NAccs.HuaWeiRegister: onToken appId:103885137
E/HuaWeiRegister: getToken failed.
com.huawei.hms.common.ApiException: 907135003: client api invalid
複制代碼

1.png 面向搜索引擎編程的我各種搜索,有的說是沒有鏈接上華為移動服務,有的說是bks證書不對,什麼昇級手機上的華為服務,各種方法都嘗試過都是沒有效果。

我意識到問題和大部分的人不同,因為我們項目與華為健康有合作,所以還接入了華為登錄,華為健康等華為系SDK,所以自己開始嘗試解决。

附上我的SDK版本

友盟其他的SDK都是最新的,其中華為廠商推送版本為

 implementation 'com.huawei.hms:push:5.1.1.301'
implementation 'com.umeng.umsdk:huawei-umengaccs:1.3.1'
複制代碼

定比特問題

  1. 單獨接入廠商推送

因為我友盟退出廠商推送這個功能的時候,我就接入過,而且過程頁比較順利,這次再接入,我預計1個小時完成。但是卻出了問題。於是我新建了一個項目,包名已經其他項目保持與主項目一致,初始化華為廠商推送失敗成功

  1. 在上面的基礎上,引入華為登錄,華為健康SDK。初始化華為廠商推送失敗

猜測:1.廠商推送本身沒有問題,但是與華為其他SDK一起接入時,會出現問題。
猜測:2.華為推送SDK與華為其他SDK一起接入時,會出現問題。

於是我去友盟,華為分別進行技術諮詢:

  • 友盟回複:請看文檔XXX,如果還不行再看文檔xxx,最後給的回複是:我們沒有問題,報錯是華為的异常

根據華為的技術要求提供了一些日志,他們看完之後回複

  • 華為回複:項目生成的bks證書校對失敗,讓我嘗試單獨接入華為系SDK
  1. 不接入友盟的華為廠商推送,只安卓華為文檔結束華為的推送SDK。在初始化的時候,成功的獲取到了華為推送token,接入成功

於是排除華為系SDK內部導致bks證書可能,那麼就只有一個情况:

友盟廠商推送的華為渠道SDK,在項目中 如果同時還接入了華為的其他SDK,則會導致項目的bks證書出現問題,以至於連接不上華為服務,進而獲取不到華為推送token

於是再次建立友盟工單,與技術溝通,再次得到簡單的回複:

友盟再次回複:我們的華為渠道SDK沒有問題!

。。。。我心裏都真是XXOO,單獨接入華為沒問題,接入友盟的華為廠商推送bks證書就不對,還沒問題麼?除了會提供幾個不是文檔地址讓我對著看。。就是我們沒問題。。而且更奇怪的是,友盟的官網文檔是很久很久以前的,按著官網文檔接入現在會出問題,但是你一把問題給客服一說,他們立馬發另一個文檔地址給你。。那既然你們知道官網文檔有問題也有新的解决文檔。。你們就不可以把官網的文檔更新一下麼。哎,還是自己來吧

分析問題

算了,深呼吸,還是我自己再嘗試解决吧。現在的情况是,我按照華為的推送文檔,可以拿到推送token,其實已經可以離線推送成功了。但是我們想的肯定是後端只需要在友盟後臺觸發推送就好,而不是友盟發一次,華為再發一次。

思考:

友盟集成廠商推送,我們還是需要在各大廠商注册賬號,獲取參數,所以可以肯定,友盟也只是封裝了一層,讓使用者只需要在他們那邊填好參數,觸發消息推送,然後友盟內部再觸發各自的廠商推送。那麼問題來了,友盟是如何封裝的這一層呢?

我們可以看到友盟的華為推送要求依賴2個庫,一個是和華為自己推送的SDK一模一樣,

'com.huawei.hms:push:5.1.1.301'
複制代碼

另一個是友盟自己SDK

'com.umeng.umsdk:huawei-umengaccs:1.3.1'
複制代碼

包括其他幾個渠道的依賴方式也是類似的。所以我在想友盟會不會是先拿著各自渠道的token,然後注册到自己的推送中,用戶觸發友盟推送,友盟在再觸發各自的廠商推送。

為了驗證這個猜測,我去觀察了5個廠商的推送初始化日志,他們有一個共同點:

先是廠商自己的推送注册成功的日志,然後再是友盟的注册成功日志。

那解决問題的方案就來了:我現在是能獲取到華為的token,那我不使用友盟的華為廠商SDK,我自己將華為的token,注册到友盟推送裏不就好了。

解决問題

友盟華為渠道的初始化就一行代碼

HuaWeiRegister.register(application)
複制代碼

好在內部沒有混淆,可以很清楚的看到邏輯

 org.android.agoo.huawei.HuaWeiRegister
private static void getToken(final Context context) {
ThreadPoolExecutorFactory.execute(new Runnable() {
public void run() {
try {
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 128);
String value = appInfo.metaData.getString("com.huawei.hms.client.appid");
String appId = "";
if (!TextUtils.isEmpty(value)) {
appId = value.replace("appid=", "");
}
ALog.i("HuaWeiRegister", "onToken", new Object[]{"appId", appId});
String token;
關鍵代碼獲取華為推送token
if (TextUtils.isEmpty(appId)) {
token = HmsInstanceId.getInstance(context).getToken();
} else {
token = HmsInstanceId.getInstance(context).getToken(appId, "HCM");
}
if (!TextUtils.isEmpty(token)) {
ALog.i("HuaWeiRegister", "onToken", new Object[]{"token", token});
NotifManager notifyManager = new NotifManager();
notifyManager.init(context);
上報第三方token到友盟內部
notifyManager.reportThirdPushToken(token, "HW_TOKEN");
}
} catch (Exception var6) {
Log.e("HuaWeiRegister", "getToken failed.", var6);
}
}
});
}
複制代碼

其他代碼就不貼了,只看關鍵方法getToken

因為剛剛單獨接入過華為推送SDK,所以我看到token = HmsInstanceId.getInstance(context).getToken(appId, "HCM");這行代碼時我很興奮,因為這個代碼就是華為的token的獲取方式,在友盟的SDK裏再次出現也證明了我的猜測,所以只需要找到友盟是怎麼拿著這麼token注册到自己內部就好。 下面有一行代碼已經很明顯了reportThirdPushToken上報第三方推送token。

所以:我們只需要拿著我們已有的華為token,然後自己調用友盟的上報方法即可。

於是我項目裏,不引用'com.umeng.umsdk:huawei-umengaccs:1.3.1',自己照著友盟的HuaWeiRegister類重新封裝一個類,負責把華為的推送token注册到友盟中。同時我們還缺少一個HuaweiPushMessageService這個類我們只需要從友盟的華為推送SDK裏複制出來就好。 然後把項目裏對'com.umeng.umsdk:huawei-umengaccs:1.3.1'的依賴删除。 項目中對於華為廠商推送的結構如下

1629011180(1).png

在進行初始化的時候,使用自己的方法HuaWeiPushManager.getInstance.register(application)去替代友盟的初始化代碼HuaWeiRegister.register(application)。代碼如下

 /**
* 廠商推送
* 根據官方文檔推薦,在app收個activity的onCreate中注册
* 接OPPO產商推送,買一送二(onePlus realme)
*/
private fun registerDeviceChannel(application: Application) {
//小米推送
MiPushRegistar.register(
application,
UMENG_XIAOMI_ID,
UMENG_XIAOMI_KEY
)
//華為推送
//HuaWeiRegister.register(application)
HuaWeiPushManager.getInstance.register(application)
//OPPO推送
OppoRegister.register(
application,
UMENG_OPPO_KEY,
UMENG_OPPO_SECRET
)
//VIVO推送
VivoRegister.register(application)
}
複制代碼

然後重新運行項目,獲取華為token成功,友盟廠商推送注册成功,友盟後臺觸發離線推送,華為手機在關閉APP後,也能正常收到推送。問題得以解决

後語

總算解决了這個問題,心裏松了一口氣,同時把這個情况分別告訴了華為的技術和友盟的技術。如果以後還有搬磚的反饋這種問題,他們也能有點印象。當然還是希望友盟能盡快解决這個問題。 分別和華為和友盟技術溝通後,心裏感慨:華為牛逼,友盟。。呵呵

然後也看了友盟封裝的華為推送SDK的代碼,確實比較簡單,怪不得他們一直很自信的說自己沒有問題。畢竟沒幾行代碼。我也想不明白問題出在哪裏,但是可以肯定'com.umeng.umsdk:huawei-umengaccs:1.3.1' 這個SDK有問題。

封裝後的代碼

最後附我封裝後的類

import android.app.Application
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import com.huawei.agconnect.config.AGConnectServicesConfig
import com.huawei.hms.aaid.HmsInstanceId
import com.huawei.hms.common.ApiException
import org.android.agoo.control.NotifManager
import timber.log.Timber
/**
* @author : ZhaoYun
* @desc : 自己稍微封裝一下友盟的華為初始化(代替'com.umeng.umsdk:huawei-umengaccs:1.3.1')
*/
class HuaWeiPushManager {
companion object {
val getInstance: HuaWeiPushManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
HuaWeiPushManager()
}
}
fun register(application: Application) {
if (checkDevice() && Build.VERSION.SDK_INT >= 17) {
Timber.i("MobiUMengManager HuaWei register")
getHuaWeiToken(application)
} else {
Timber.i("MobiUMengManager HuaWei register: register not in main process, return")
}
}
/**
* 華為華為推送token,向友盟注册華為推送
*/
private fun getHuaWeiToken(application: Application) {
// 創建一個新線程
object : Thread() {
override fun run() {
try {
// 從agconnect-service.json文件中讀取appId
val appId =
AGConnectServicesConfig.fromContext(application).getString("client/app_id")
// 輸入token標識"HCM"
val tokenScope = "HCM"
val token = HmsInstanceId.getInstance(application).getToken(appId, tokenScope)
Timber.i("MobiUMengManager HuaWei get token:$token")
val handler = Handler(Looper.getMainLooper())
handler.postDelayed({
val notifyManager = NotifManager()
notifyManager.init(application)
notifyManager.reportThirdPushToken(token, "HW_TOKEN")
Timber.i("MobiUMengManager HuaWei registe token:$token")
}, 5000L)
// 判斷token是否為空
if (!TextUtils.isEmpty(token)) {
sendRegTokenToServer(token)
}
} catch (e: ApiException) {
Timber.i("MobiUMengManager HuaWei get token failed, $e")
}
}
}.start()
}
private fun sendRegTokenToServer(token: String?) {
Timber.i("MobiUMengManager HuaWei sending token to server. token:$token")
}
/**
* 檢查是是否為華為設備
*/
private fun checkDevice(): Boolean {
var result = false
if (Build.BRAND.equals(
"huawei",
ignoreCase = true
) || Build.BRAND.equals("honor", ignoreCase = true)
) {
result = true
}
return result
}
}
複制代碼
版权声明:本文为[ZhaoYun]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210815181419016y.html