Android manufacturers push conflicts. . .

About vendor push

Push has become an indispensable function for most of the current apps. I believe you will receive news, chat messages, and activities of ordinary apps every day. In order to increase the arrival rate of push, you have also made various optimizations. The initial application After the process is killed, you can't receive the push, so in the past few years, there have been various methods of keeping the application alive, and the "coupon" of applying the keep alive after Android 8.0 is difficult to take effect.

In order to improve the arrival rate of push, when the application is killed, everyone will choose to take the manufacturer's push channel. Major manufacturers will have a long link at the system level to handle push messages uniformly, so as to ensure that you can also receive smoothly after the application is killed. To push, the following figure describes Xiaomi's manufacturer push process.

Notification bar messages and pass-through messages

Notification bar message: It's easy to understand that it is automatically displayed in the notification bar when you receive a push.

Transparent transmission of messages: as the name implies, the content of the message is directly transmitted to the client, which is transparent to the user. Whether the display and display form are received after the message is received is controlled by the client, and it is more flexible to use. Many third-party SDKs call it Custom message. Generally, custom messages in the App are also transparent messages. After the App receives the notification, the type of message notification that the App can get and the page that needs to be visited are processed accordingly.

## Origin of the problem

At first, we used NetEase Yunxin in our App to support the chat service; Aurora Push was used to process business push messages. Due to the limitations of the above Android version, it is difficult to keep the process alive, which is also not recommended. This also led to the failure to receive messages after the application was killed, so Aurora and Yunxin have successively provided their own access solutions for vendor push. Since the business requires that we first access the Aurora vendor push, Aurora encapsulates the vendor push SDK provided by different vendors , you only need to introduce the corresponding packaged package, as follows:

dependencies {
    ...
    implementation 'cn.jiguang.sdk:jpush:3.3.9'
    implementation 'cn.jiguang.sdk:jcore:2.1.6'
    implementation 'cn.jiguang.sdk.plugin:xiaomi:3.3.9'
    implementation 'cn.jiguang.sdk.plugin:huawei:3.3.9'
    implementation 'cn.jiguang.sdk.plugin:oppo:3.3.9'
    ...
} 

Taking Xiaomi as an example, let's see how the cn.jiguang.sdk.plugin: xiaomi: 3.3.9 arr package introduced by Aurora works:

It can be seen that the arr package provided by Aurora directly includes the MiPush_SDK_Client_3_6_18.jar (handling the SDK pushed by Xiaomi manufacturers) provided by Xiaomi, and provides a PluginXiaomiPlatformsReceiver class, which is inherited from the PushMessageReceiver package in the above Xiaomi jar package PluginXiaomiPlatformsReceiver will be added to the Manifest file. When the system receives the push, it will forward the message to the class that inherits PushMessageReceiver, so PluginXiaomiPlatformsReceiver will receive the message and pass the message to Aurora ’s own SDK for processing. It is the same as the push process of the App in the foreground. A brief summary of this Plugin class: ** Plugin class will be registered to the Manifest to receive system messages, and forward the message to the Aurora SDK in the corresponding callback method. ** All this works well before the NetEase Yunxin compatible vendor push. After the application process is killed, push push can be received normally. The problem starts from Yunxin message push compatible vendor push:

Question one

According to the access method provided by NetEase Yunxin, it is necessary to access the push SDK of Xiaomi. Because the Aurora has been introduced, it will conflict if it is introduced again. Here, it will not be directly introduced. Use Aurora, and then follow the access process to access, After the access process, we noticed that the following content will be inserted in the AndroidManifest.xml file:

<receiver
    android:name="com.netease.nimlib.mixpush.mi.MiPushReceiver"
    android:exported="true">
    <intent-filter android:priority="0x7fffffff"> //这里设置了优先级
        <action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE" />
        <action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED" />
        <action android:name="com.xiaomi.mipush.ERROR" />
    </intent-filter>
</receiver> 

Looking at the source code of this MiPushReceiver, we will find that it mainly processes and forwards various events pushed by Xiaomi manufacturers. MiPushReceiver is also inherited from the PushMessageReceiver in the Xiaomi push sdk. The MiPushReceiver code is as follows:

At this point, the official document says that the push message can be tested, so the mobile phone process is killed and a message is sent to the mobile phone, which can indeed be received. But after the process was killed, the normal Aurora push was originally received, but now it can't be received. Some models of other manufacturers can receive it, but click the push message to open the App. Let's look at the following figure to analyze the reason:

Regardless of the news of Aurora or Yunxin, the message will first be pushed to Xiaomi ’s push cloud service, and then Xiaomi ’s mobile phone system will maintain a long link with Xiaomi ’s push cloud service. After receiving the MiPush SDK, it will first find the inherited PushMessageReceiver And register to the Receiver of Manifest and pass the message to this Receiver. Because Aurora and Yunxin have registered PushMessageReceiver in Manifest, there is uncertainty about who can receive it at this time. If priority is configured, the one with higher priority will be received. Returning to the above, we noticed that NetEase Yunxin ’s MiPushReceiver has a priority set, so to explain why the Aurora message cannot be received, I quickly checked the Aurora PluginXiaomiPlatformsReceiver in the Manifest after packaging as follows:

<receiver
    android:name="cn.jpush.android.service.PluginXiaomiPlatformsReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.xiaomi.mipush.ERROR" />
    </intent-filter>
</receiver> 

Sure enough, Aurora has not set a priority, which can explain why Aurora's push is not received after NetEase Yunxin access vendor push. Different vendors have different ways to access the vendor push, and the performance of the above conflict is also different. Messages like Xiaomi ’s mobile phone Yunxin always take precedence over Aurora ’s push. Oppo and vivo will display messages but click the notification bar message. No response (the message did not reach the corresponding Receiver), and some of Huawei's mobile phones can be distinguished normally. ** In short, two Receivers go to receive the push from the manufacturer at the same time, there will be conflicts. ** Then we continue to search for solutions to this conflict in the integrated documentation of NetEase Yunxin and Aurora, and finally we found it behind the NetEase Yunxin document, and then we encountered the second problem.

Question two

NetEase Yunxin ’s push documentation provides a solution for Xiaomi ’s push compatibility. Yunxin provides a MiPushMessageReceiver to allow other Receivers that have access to vendor push and handle push forwarding logic to inherit this MiPushMessageReceiver and then process it in the corresponding callback method. Processing the corresponding logic, MiPushMessageReceiver is as follows:

public class MiPushMessageReceiver extends BroadcastReceiver{
    @Override
    public final void onReceive(Context context, Intent intent) {}
    public void onReceivePassThroughMessage(Context context, MiPushMessage message) {}
    public void onNotificationMessageClicked(Context context, MiPushMessage message) {}
    public void onNotificationMessageArrived(Context context, MiPushMessage message) {}
    public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {}
    public void onCommandResult(Context context, MiPushCommandMessage message) {}
} 

Then add your Receiver to the Manifest without setting the priority:

<receiver android:name="xxx.YourSelfReceiver">
    <intent-filter>
        <action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE"/>
        <action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED"/>
        <action android:name="com.xiaomi.mipush.ERROR"/>
    </intent-filter>
</receiver> 

In this way, we can ensure that the push is received by NetEase Yunxin ’s MiPushReceiver, and then it is processed directly by its own push message. If it is not its own, it is handed over to the Receiver that inherits from MiPushMessageReceiver. The source code found is indeed like this:

public final class MiPushReceiver extends PushMessageReceiver {
    public MiPushReceiver() {}

    public final void onNotificationMessageClicked(Context var1, MiPushMessage var2) {
        if (g.a(var2.getExtra())) {
            c.a(5).onNotificationClick(var1, var2); //自己处理
        } else {
            MiPushMessageReceiver var3;
            if ((var3 = a.a(var1)) != null) {
                var3.onNotificationMessageClicked(var1, var2);//交给MiPushMessageReceiver处理
            }
        }
    }
    ...
} 

If you follow the method recommended by Yunxin, the process after processing is this:

Ok, here the processing method and principle are clear, we now only need to change the PluginXiaomiPlatformsReceiver pushed by Aurora processing to inherit MiPushMessageReceiver, and then add it to the Manifest according to the above method, it looks very simple, and then Let's take another look at Aurora's PluginXiaomiPlatformsReceiver:

Uh ... Then the question is coming, this class is packaged in arr pushed by aurora. ** How to modify the inheritance of the class in the arr package? ** This problem doesn't seem to be easy to solve ~

## Solve the problem

Seek help from Yunxin and Aurora

The first thing that comes to mind is that this solution to deal with simultaneous monitoring of vendor push conflicts is provided by Yunxin. Then first ask Yunxin if there is a solution. Yunxin's reply is as follows:

Yunxin means that they only provide this inheritance compatible solution. If it is encapsulated by a third party, they do n’t have a very good way. Then we recommend that we go to the Aurora technical staff to discuss the removal of the corresponding class. What's more, if Aurora can provide source code, we just modify the inheritance relationship, so we quickly found Aurora technology to communicate:

Aurora ’s technology says that they only provide a unified package version, and it does not consider the conflicts caused by accessing the SDK with other third parties at the same time, and recommends that we only integrate one vendor channel ... well! The people of Yunxin asked us to discuss with Aurora. Not only did Aurora not provide solutions, but also let us not integrate multiple vendor channels. Without integration, business needs cannot be met. But at the same time, it can also be understood that when different third parties consider to access the vendor channel, they should also give priority to whether they can implement the vendor channel by themselves, whether it will affect other third parties, how other third parties are implemented, and how to go Compatible, they can't control that much, but like Yunxin also provides a compatible solution, it's really good! It was later found that the Aurora SDK was confused, so it is normal to not provide the source code. It seems that the source code of the Aurora PluginXiaomiPlatformsReceiver is not available, and neither Yunxin nor Aurora can provide powerful help, and the problem can only be solved by ourselves.

Analyze the principle of the problem and find a solution

  • Analysis function

Looking back and thinking about the role of the PluginXiaomiPlatformsReceiver class, in the Aurora SDK, this class inherits Xiaomi ’s official PushMessageReceiver, and then it is added to the Manifest file after being packaged, so that there is a monitoring Xiaomi system to push and forward messages to Aurora The SDK's ability to process, while the PluginXiaomiPlatformsReceiver class has not been called elsewhere.

  • Use inheritance?

Since we cannot modify the source code, the first thought is whether it can be achieved by inheriting this class? But java is single inheritance, inheriting Aurora, there is no way to inherit Yunxin's compatible class, it seems that inheritance does not work.

  • Starting from demand

In fact, we only need one class now. The internal implementation logic is the same as that of Yunxin's PluginXiaomiPlatformsReceiver. It can forward the received messages to the Yunxin SDK, and this class can modify the inheritance relationship arbitrarily. Well, I do n’t know if you think of it. We can write an identical class in our own code. The internal code directly copies the PluginXiaomiPlatformsReceiver and then modify the inheritance relationship. Yes, let's take a look at Yunxin's PluginXiaomiPlatformsReceiver:

Seeing that although this class is confusing, it does not matter. The source code is in the SDK and can be called externally. We can directly copy the code to our newly created class PluginXiaomiPlatformsReceiverYx:

import cn.jpush.android.thirdpush.xiaomi.a;//引入极光被混淆的包
...

public class PluginXiaomiPlatformsReceiverYx extends MiPushMessageReceiver {

    private static final String TAG = "XMPlatformsReceiver";
    public PluginXiaomiPlatformsReceiverYx() {}

    public void onReceivePassThroughMessage(Context var1, MiPushMessage var2) {
        Logger.dd("XMPlatformsReceiver", "onReceivePassThroughMessage is called. " + var2);
    }

    public void onNotificationMessageClicked(Context var1, MiPushMessage var2) {
        Logger.dd("XMPlatformsReceiver", "onNotificationMessageClicked is called. " + var2);
        if (var2 == null) {
            Logger.v("XMPlatformsReceiver", "message was null");
        } else {
            //虽然混淆了,但是用的都是极光sdk中的方法一样可以正常工作。
            a.a(var1, var2, "action_notification_clicked");
        }
    }
    ...
} 

It can be seen that this class inherits the MiPushMessageReceiver provided by Yunxin. Each callback implementation is exactly the same as the previous Aurora, so that the received message can be passed to Aurora for processing, and then the class is added to the Manifest according to Yunxin's documentation:

It should be noted here that in order to only allow Yunxin to monitor the manufacturer's push, it is also necessary to automatically add the Aurora SDK to the PluginXiaomiPlatformsReceiver in the Manifest when it is compiled and manually remove it. About the merge rule of Manifest, we can view the Android document and merge multiple manifest files. After this modification, it is equivalent to "overhead" the Aurora PluginXiaomiPlatformsReceiver, and the message push of Yunxin and Aurora will be uniformly received by Yunxin. Messages that are not Yunxin will be handed over to PluginXiaomiPlatformsReceiverYx and then processed by Aurora, the process and above The same is mentioned:

Here is just an example of conflicts pushed by Xiaomi vendors. Others like Huawei, Meizu, OPPO, VIVO, etc. can be handled in the same way. Through the above solution, Yunxin and Aurora's manufacturer push compatibility can be successfully completed. When upgrading the Aurora SDK version, if there is a change in the internal implementation of the Receiver starting with "Plugin", the Aurora SDK directly copies the corresponding content to the custom Receiver. This needs to be noted.

to sum up

Although the current conflict problem can be solved in the above way, there is one point that the SDKs pushed by the manufacturers are all packaged in the Aurora SDK. Yunxin does not have a separate integration (if separate integration will conflict). This may lead to different versions of SDKs pushed by the two compatible manufacturers when Yunxin and Aurora SDKs are upgraded later. For example, Huawei ’s push SDK is updated and Aurora is compatible, but NetEase Yunxin is not compatible. At this time, there will still be some problems. So when upgrading, you also need to check the compatibility status of each manufacturer and then upgrade. If you have a better solution to the conflicts of the above manufacturer channels, please leave a message!

Published 488 original articles · praised 85 · 230,000 views +

Guess you like

Origin blog.csdn.net/Coo123_/article/details/105441926