This is the 6th day of my participation in the August More Text Challenge

The previous learning records are in their own local, by the nuggets this August activity opportunity, but also to challenge themselves. You look at the officer a little praise, younger brother thanks first.

Problems arise:

The project needs to use the push from the access alliance vendor. The debugging is successful for other vendors. When testing the push from huawei vendor, an error message is always reported during the initialization HuaWeiRegister: getToken failed. 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
Copy the code

In my search engine programming, some said huawei mobile service was not linked, some said the BKS certificate was wrong, and I tried all kinds of methods to upgrade Huawei service on my mobile phone, but all of them had no effect.

I realized that the problem was different from most people’s. Because our project cooperated with Huawei Health, we also connected huawei login, Huawei Health and other Huawei SDK, so I started to try to solve it myself.

Attached is my SDK version

All other SDKS of Umeng are up to date, and the version pushed by Huawei is

Implementation 'com. Huawei. HMS: push: 5.1.1.301' implementation 'com. Umeng. Umsdk: huawei - umengaccs: 1.3.1'Copy the code

Location problem

  1. Separate access to vendor push

Since I logged in when UMeng quit the function of vendor push, and the process page was relatively smooth, I expect to complete the re-access within one hour. But something went wrong. Then I created a new project whose package name was the same as that of the main project. Initialization of huawei vendor push failed

  1. On the basis of the above, huawei login, Huawei health SDK is introduced. Failed to initialize huawei vendor push. Procedure

Guess :1. There is no problem with vendor push itself, but problems may occur when it is connected with other SDKS of Huawei. Guess :2. When the SDK pushed by Huawei is connected with other SDKS of Huawei, problems may occur.

So I went to UmENG and Huawei for technical consultation respectively:

  • Umeng replied: please refer to the document XXX. If it still does not work, please refer to the document XXX again. The final reply is: We have no problem, and the error reported is an exception of Huawei

We provided some logs according to Huawei’s technical requirements, and they replied after reading them

  • Huawei replied: the verification of the BKS certificate generated by the project failed, so LET me try to access the SDK of Huawei department separately
  1. Huawei vendor push is not connected to Umu, but huawei Android Documentation ends huawei push SDK. During initialization, the huawei push token is successfully obtained

Therefore, excluding the possibility of BKS certificate caused by huawei SDK, there is only one case:

If other SDKS of Huawei are also connected to the SDK of Huawei channel pushed by umU vendors during the project, the BKS certificate of the project will be faulty. As a result, huawei services cannot be connected and huawei push tokens cannot be obtained

So I set up the UmENG work order again, communicated with the technology, and got a simple reply again:

Umeng replied again: there is no problem with our Huawei channel SDK!

. My heart is really XXOO, it is ok to access Huawei alone, but it is wrong to access Umeng huawei vendors push BKS certificate, is it ok? Except that it will provide several non-document addresses for me to look at. It’s ok with us. And what’s more strange is that the official website document of Umeng is a long time ago, press the official website document access will now have a problem, but you give the customer service a problem, they immediately send another document address to you. Well, now that you know there’s a problem with the official documentation there’s a new fix. Can’t you update the documents on the official website? Well, do it yourself

To analyze problems

All right, take a deep breath, and I’ll try and figure it out on my own. The current situation is that I can get the push token according to Huawei’s push document. In fact, I can successfully push offline. However, we must think that the backend only needs to trigger push in the background of UmENG, rather than umeng sending once and Huawei sending again.

Think about:

Umeng integrates manufacturer push, we still need to register accounts in major manufacturers to obtain parameters, so we can be sure that Umeng only encapsulates a layer, so that users only need to fill in parameters on their side, trigger message push, and then trigger their own manufacturer push inside Umeng. So how does Umeng encapsulate this layer?

We can see that Huawei push requirements of UmENG rely on two libraries. One is exactly the same as the SDK pushed by Huawei.

'com. Huawei. HMS: push: 5.1.1.301'Copy the code

The other is umeng’s own SDK

'com. Umeng. Umsdk: huawei - umengaccs: 1.3.1'Copy the code

The dependency pattern for several other channels is similar. So I wonder if UmENG will first take the tokens of their respective channels and then register them in their own push. Users will trigger Umeng push, and Umeng will trigger their respective manufacturers’ push.

To test this guess, I looked at the push initialization logs of five vendors, and they had one thing in common:

First, the vendor’s push registration success log, and then the UmENG registration success log.

Then the solution to the problem comes: NOW I can get huawei token, so I don’t use umeng’s HUAWEI vendor SDK, I will register Huawei token in umeng push.

To solve the problem

Umeng Huawei channel initialization is a line of code

HuaWeiRegister.register(application)
Copy the code

Fortunately, there is no internal confusion and the logic can be clearly seen

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; The key code for huawei push 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); Report to the third party token to internal notifyManager Allies. The reportThirdPushToken (token, "HW_TOKEN"); } } catch (Exception var6) { Log.e("HuaWeiRegister", "getToken failed.", var6); }}}); }Copy the code

I won’t post the rest of the code, just look at the key method getToken

Because just had separate access huawei push SDK, so I see token = HmsInstanceId getInstance (context). GetToken (appId, “HCM”); I was very excited when I saw this code, because this code is the way to obtain Huawei’s token, and it appeared again in UMeng’s SDK, which also proved my guess. So I just need to find out how Umeng registered such token to its own internal. ReportThirdPushToken Reports a third-party push token.

So: we just need to take our existing Huawei token and call umeng’s reporting method.

Therefore, in my project, I did not refer to ‘com.umeng. umSDK :huawei-umengaccs:1.3.1’, and re-packaged a class according to HuaWeiRegister, which was responsible for registering Huawei’s push token in UMeng. At the same time we still lack a HuaweiPushMessageService class which we just need to copy from huawei push SDK of Umeng. Then remove the dependencies on ‘com.umeng.umsdk:huawei-umengaccs:1.3.1’ from the project. The structure of huawei vendor push in the project is as follows

When initializing. Use your own method HuaWeiPushManager getInstance. Register (application) to replace their Allies initialization code HuaWeiRegister. Register (application). The following code

/** * Vendor push * Register the activity in app onCreate according to the official document recommendation * receive OPPO vendor push, Buy one get two free (onePlus RealMe) */ Private Fun registerDeviceChannel(Application: Mipushregistar. register(Application, UMENG_XIAOMI_ID, UMENG_XIAOMI_KEY) / / / / HuaWeiRegister huawei push. Register (application) HuaWeiPushManager. GetInstance. Register (application) OPPO push opporegister. register(application, UMENG_OPPO_KEY, // vivoregister.register (application)}Copy the code

Then run the project again, obtain huawei token successfully, umU vendor push registration succeeds, umU background triggers offline push, huawei mobile phone can also receive push normally after closing the APP. Problem solved

After the language

Finally solved this problem, I felt relieved, and told the situation to Huawei technology and UmENG technology respectively. If there is feedback on moving bricks in the future, they can also have a little impression. Of course, we still hope that Ameng can solve this problem as soon as possible. After r communicating with Huawei and UmENG technology, I felt in my heart: Huawei is awesome, Umeng. Ha ha

Then I also read the code of HUAWEI push SDK encapsulated by UmENG. It is really simple. No wonder they have been very confident that they have no problem. There aren’t many lines of code. I don’t know what the problem is either, but I’m sure there is a problem with the SDK ‘com.umeng.umsdk:huawei-umengaccs:1.3.1’.

Wrapped code

Finally, I enclosed the class

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 : 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")}} /** * Huawei Huawei push token, register Huawei push token to Umeng */ private fun getHuaWeiToken(Application: // create a new thread object: Thread() {override fun run() {try {// Read from agconnect-service.json file appId val appId = AGConnectServicesConfig. FromContext (application). Get string (the "client/app_id") / / input token identity "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") }, // Check whether token is null 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")} /** * Check whether it is a HuaWei device */ private fun checkDevice(): Boolean { var result = false if (Build.BRAND.equals( "huawei", ignoreCase = true ) || Build.BRAND.equals("honor", ignoreCase = true) ) { result = true } return result } }Copy the code