Flutter Android Xiaomi push integration

How many talented losers in the world, there are many highly educated unemployed travelers in the world

Flutter Xiaomi push integration

Recently, the Flutter project needs to integrate push. Fortunately for IOS, Android needs to access the push channels of various manufacturers. It can be said that one step at a time, sometimes it is really cursing while looking at the document. Fortunately, after tears filled the pit, Huawei, Xiaomi, Vivo, Oppo, Aurora, etc. were finally integrated.

It happened that last night a netizen also informed me about the problem of the integration of my Xiaomi push, and I feel that the Xiaomi set is indeed a little different, so it is a tutorial to record the steps of Flutter and Xiaomi push integration.

Flutter integrates Xiaomi Push and has a plug-in called: xiao_mi_push_plugin: ^1.0.0. I have read the source code and usage, and they are quite simple. But it cannot be connected with the back-end push API when used. My phenomenon is:

If the back-end call interface carries parameters, clicking on the notification can receive the NotificationMessageClicked type of monitoring. However, if the program is killed, the application cannot be re-run. When the background definition opens the application homepage, click on the notification but cannot receive the NotificationMessageClicked type listener.

Later, I integrated Xiaomi Push directly into my own application. Here I will open a new application to summarize: Create application package name: com.jumanyi.merchant

Start

Step0 Import Xiaomi's integrated Jar package

Create a new libs folder under the android/app path, the location is as shown in the figure below, and move into the jar package, and add at the end of the build.gradle file:

dependencies {
    api fileTree(include: ['*.jar'], dir: 'libs')

   // implementation files('app/libs/MiPush_SDK_Client_3_8_2.jar')
}

New constant class BaseConstants

public class BaseConstants {


    //小米后台的App_ID
    public static final String APP_ID="";
    //小米后台的App_KEY
    public static final String APP_KEY="";


    //Flutter 和Android  互相通信的通道
    public static final String PUSH_MSG_METHOD_CHANEL="com.push.xiaomi.msg.method";
    public static final String PUSH_MSG_EVENT_CHANEL="com.push.xiaomi.msg.event";


    //共享参数RegId存储的TAG
    public static final String DATA_Reg="XiaoMi_RegId";
    public static final String DATA_Push="XiaoMi_Push";

    //RegIdTag
    public static final String RegIdTag="regid";
    //PushTag
    public static final String PushTag="push";
    //Intent 存值的键
    public static final String Extras="extras";

}

Step1 Initialize Xiaomi push

Create a new base package under the package name, and then create a new BaseApp class to inherit FlutterApplication and override the onCreate method.

package com.jumanyi.merchant.base;



import android.app.ActivityManager;
import android.content.Context;
import android.os.Build;
import android.os.Process;
import android.util.Log;

import com.jumanyi.merchant.BaseConstants;
import com.xiaomi.channel.commonutils.logger.LoggerInterface;
import com.xiaomi.mipush.sdk.Logger;
import com.xiaomi.mipush.sdk.MiPushClient;

import java.util.List;

import io.flutter.app.FlutterApplication;

public class BaseApp extends FlutterApplication {
    public static final String TAG = "com.jumanyi.merchant";

    @Override
    public void onCreate() {
        super.onCreate();

        //Step 1. 调用注册接口
        if (isMiUI()&&shouldInit()){
            MiPushClient.registerPush(this, BaseConstants.APP_ID,BaseConstants.APP_KEY);
        }


        //打开Log
        LoggerInterface newLogger = new LoggerInterface() {

            @Override
            public void setTag(String tag) {
                // ignore
            }

            @Override
            public void log(String content, Throwable t) {
                Log.d(TAG, content, t);
            }

            @Override
            public void log(String content) {
                Log.d(TAG, content);
            }
        };
        Logger.setLogger(this, newLogger);

    }


    //判断是否是小米手机
    private boolean isMiUI(){

        return Build.MANUFACTURER.equalsIgnoreCase("xiaomi");
    }



    //因为推送服务XMPushService在AndroidManifest.xml中设置为运行在另外一个进程,
    //这导致本Application会被实例化两次,所以我们需要让应用的主进程初始化
    private boolean shouldInit() {
        //通过ActivityManager我们可以获得系统里正在运行的activities
        //包括进程(Process)等、应用程序/包、服务(Service)、任务(Task)信息。
        ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
        List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
        String mainProcessName = getApplicationInfo().processName;

        int myPid = Process.myPid();
        for (ActivityManager.RunningAppProcessInfo info : processInfos) {
            //通过比较进程的唯一标识和包名判断进程里是否存在该App
            if (info.pid == myPid && mainProcessName.equals(info.processName)) {
                return true;
            }
        }
        return false;
    }
}


Step2 Rewrite PushMessageReceiver

Here is mainly the behavior of monitoring some messages. Let me briefly talk about my logic here.

After receiving the callback of the registration monitor, store the RegisterId in the shared parameter. When Flutter needs the RegisterId, it can be obtained through MethodChanel.

Override the notification's click event

When the application is in the foreground, the onNewIntent method will be used when MainActiv is opened again. At this time, the data is sent to Flutter directly through EventChanel, and then flutter can jump to the interface according to the parameters.

When the application is in a killed state, the onCreate method will be used when MainActiv is opened again, and the received parameters will be written into the shared parameter storage. When Flutter selects, it gets the parameters and jumps to the interface according to the parameters.

package com.jumanyi.merchant.miMsg;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;

import com.jumanyi.merchant.BaseConstants;
import com.xiaomi.mipush.sdk.MiPushCommandMessage;
import com.xiaomi.mipush.sdk.MiPushMessage;
import com.xiaomi.mipush.sdk.PushMessageReceiver;


// Step 2.  重写PushMessageReceiver

public class XiaoMiMessageReceiver extends PushMessageReceiver {


    //日志标签
    public static final String TAG=XiaoMiMessageReceiver.class.getCanonicalName();


    //通知点击事件
    @Override
    public void onNotificationMessageClicked(Context context, MiPushMessage miPushMessage) {
        super.onNotificationMessageClicked(context, miPushMessage);

        Log.i(TAG, "=============onNotificationMessageClicked:"+miPushMessage.toString());

        //此处的data 可能是服务端传过来的参数
        String data = miPushMessage.getExtra().toString();

        //点击通知 拉起应用首页,此处能解决我遇到的问题
        try{

            ComponentName componentName = new ComponentName(context.getPackageName(),"com.jumanyi.merchant.MainActivity");
            Intent intent=new Intent();
            //新开一个任务栈,这样当应用处于前台,再次打开MainActivity会走 NewIntent 方法
            //当应用处于杀死状态,会走onCreate方法
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setComponent(componentName);
            if(data!=null){
                intent.putExtra(BaseConstants.Extras,data);//存入参数
            }
            context.startActivity(intent);

        }catch (Exception e){
            Log.i(TAG, "=============Exception:"+e.toString());
        }
    }



    //注册结果监听
    @Override
    public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {
        super.onReceiveRegisterResult(context, message);

        Log.i(TAG, "=============onReceiveRegisterResult:"+message.toString());

        //当注册结果到来的时候,我把它存入共享参数
        if(message!=null&&message.getCommandArguments()!=null&&message.getCommandArguments().size()>0){

            //保存RegisId
            saveRegisterId(context,message.getCommandArguments().get(0));
        }
    }




    //保存参数
    private void saveRegisterId(Context context,String regId){
         if(null==context||regId.isEmpty())return;
         //覆盖模式
        SharedPreferences preferences = context.getSharedPreferences(BaseConstants.DATA_Reg,Context.MODE_PRIVATE);
        SharedPreferences.Editor editor= preferences.edit();
        editor.putString(BaseConstants.RegIdTag,regId);
        editor.commit();

    }

    ///华丽的分割线

    //通知到来监听
    //应用在前台时不弹出通知的通知消息到达客户端时也会回调函数
    @Override
    public void onNotificationMessageArrived(Context context, MiPushMessage miPushMessage) {
        super.onNotificationMessageArrived(context, miPushMessage);

        Log.i(TAG, "=============onNotificationMessageArrived:"+miPushMessage.toString());

    }

    @Override
    public void onRequirePermissions(Context context, String[] strings) {
        super.onRequirePermissions(context, strings);
        Log.i(TAG, "=============onRequirePermissions:"+strings.toString());
    }


    //透传消息
    @Override
    public void onReceivePassThroughMessage(Context context, MiPushMessage miPushMessage) {
        super.onReceivePassThroughMessage(context, miPushMessage);
        Log.i(TAG, "=============onReceivePassThroughMessage:"+miPushMessage.toString());
    }
    @Override
    public void onCommandResult(Context context, MiPushCommandMessage miPushCommandMessage) {
        super.onCommandResult(context, miPushCommandMessage);

        Log.i(TAG, "=============onCommandResult:"+miPushCommandMessage.toString());

    }
}


Step3 Configure manifest file and service

Authority

    <!--小米推送-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.VIBRATE"/>
    <!--前缀用包名-->
    <permission android:name="com.jumanyi.merchant.permission.MIPUSH_RECEIVE"
        android:protectionLevel="signature"/>
    <uses-permission android:name="com.jumanyi.merchant.permission.MIPUSH_RECEIVE"/>
    <!--小米推送-->

Replace the previous application in the AndroidManifest.xml file with: io.flutter.app.FlutterApplication

android:name="com.jumanyi.merchant.base.BaseApp"

service



        <!-- xiao mi service  -->
        <service
            android:name="com.xiaomi.push.service.XMPushService"
            android:enabled="true"
            android:process=":pushservice" />

        <!--注:此service必须在3.0.1版本以后(包括3.0.1版本)加入-->
        <service
            android:name="com.xiaomi.push.service.XMJobService"
            android:enabled="true"
            android:exported="false"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:process=":pushservice" />

        <service
            android:name="com.xiaomi.mipush.sdk.PushMessageHandler"
            android:enabled="true"
            android:exported="true" />

        <!--注:此service必须在2.2.5版本以后(包括2.2.5版本)加入-->
        <service
            android:name="com.xiaomi.mipush.sdk.MessageHandleService"
            android:enabled="true" />

        <receiver
            android:name="com.xiaomi.push.service.receivers.NetworkStatusReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

        <receiver
            android:name="com.xiaomi.push.service.receivers.PingReceiver"
            android:exported="false"
            android:process=":pushservice">
            <intent-filter>
                <action android:name="com.xiaomi.push.PING_TIMER" />
            </intent-filter>
        </receiver>
        <!--自己写的,继承了PushMessageReceiver的DemoMessageReceiver的广播注册-->
        <receiver
            android:name="com.jumanyi.merchant.miMsg.XiaoMiMessageReceiver"
            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>

        <!-- xiao mi service  -->

Step4 MainActivity logic

Initialize the communication channel

Initialized in the onCreate method. When getIntent has a value, store the value in the shared parameter.

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //注册通信通道
        //注册事件通道
        new EventChannel(getFlutterEngine().getDartExecutor().getBinaryMessenger(), BaseConstants.PUSH_MSG_EVENT_CHANEL).setStreamHandler(
                new EventChannel.StreamHandler() {
                    @Override
                    public void onListen(Object arguments, EventChannel.EventSink events) {
                        //初始化
                        eventSink = events;
                    }

                    @Override
                    public void onCancel(Object arguments) {

                    }
                }
        );
        //注册方法通道
        new MethodChannel(
                getFlutterEngine().getDartExecutor().getBinaryMessenger(), BaseConstants.PUSH_MSG_METHOD_CHANEL
        ).setMethodCallHandler(
                new MethodChannel.MethodCallHandler() {
                    @Override
                    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {

                        if (call.method.equals("getReciveData")) {
                            String content = getPushRecevieMsg();
                            result.success(content);
                        } else if (call.method.equals("getXiaoMiRegId")) {
                            String regId = getRegId();
                            if (!regId.isEmpty()) {
                                result.success(regId);
                            }else {
                                result.success("没有获取到RegId");
                            }
                        } else {
                            result.notImplemented();
                        }
                    }
                }
        );

        //存贮 从被杀死的应用点击通知,传进来的参数
        saveIntentData(getIntent());

    }



   //存储消息的逻辑
    private void saveIntentData(Intent intent) {
        if (null != intent && intent.getExtras() != null && intent.getStringExtra(BaseConstants.Extras) != null) {

            String content = intent.getStringExtra(BaseConstants.Extras);
            Log.i(TAG, "save receive data from push, data = " + content);
            SharedPreferences preferences = getSharedPreferences(BaseConstants.DATA_Push, Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = preferences.edit();
            editor.putString(BaseConstants.PushTag, content);
            editor.commit();

        } else {

            Log.i(TAG, "存储消息错误");
        }

    }


Override the onNewIntent method

The application is in the foreground. After clicking the notification, this method will be used. After the parameters are obtained, the data will be sent to Flutter through EventChannel.

   @Override
    protected void onNewIntent(@NonNull Intent intent) {
        super.onNewIntent(intent);
        Log.i(TAG, intent.toString());
        //应用处于前台时,直接通过eventChanel 通知flutter

        //获取intentData
        getIntentData(intent);
    }

        //获取intentData
    private void getIntentData(Intent intent) {
        if (null != intent && intent.getExtras() != null && intent.getStringExtra(BaseConstants.Extras) != null) {

            String content = intent.getStringExtra(BaseConstants.Extras);
            Log.i(TAG, "save receive data from push, data = " + content);

            pushMsgEvent(content);
        } else {
            Log.i(TAG, "intent is null");
        }

    }

   //发送消息至flutter
    private void pushMsgEvent(String content) {

        new Handler().postDelayed(
                new Runnable() {
                    @Override
                    public void run() {
                        if (eventSink != null) {
                            eventSink.success(content);
                        }
                    }
                }
                , 500);
    }

Implementation of Flutter calling Android method

Get RegisterId and push parameters.

    ///获取消息逻辑
    private String getPushRecevieMsg() {
        SharedPreferences preferences = getSharedPreferences(BaseConstants.DATA_Push, Context.MODE_PRIVATE);
        String data = preferences.getString(BaseConstants.PushTag, "");
        SharedPreferences.Editor editor = preferences.edit();

        //清理数据
        if (!data.isEmpty()) {
            editor.remove(BaseConstants.PushTag);
            editor.commit();
        }
        return data;

    }



    //获取注册Id
    private String getRegId(){
        SharedPreferences preferences = getSharedPreferences(BaseConstants.DATA_Reg, Context.MODE_PRIVATE);
        String data = preferences.getString(BaseConstants.RegIdTag, "");
        Log.i(TAG, "getReciveData"+data);
        return data;
    }

Step5 MainActivity logic

The logic of main.dart in flutter



  //通信通道保持和Android 定义的一至
  String PUSH_MSG_METHOD_CHANEL = "com.push.xiaomi.msg.method";
  String PUSH_MSG_EVENT_CHANEL = "com.push.xiaomi.msg.event";

  MethodChannel methodChannel;


  //初始化通道
  Future<void> initChanel() async {
    methodChannel = MethodChannel(PUSH_MSG_METHOD_CHANEL);

    EventChannel XiaoMiEventChannel = EventChannel(PUSH_MSG_EVENT_CHANEL);

    //注册监听
    XiaoMiEventChannel.receiveBroadcastStream().listen((dynamic msgData) async {
      print("XiaoMiDataChannel ---->" + msgData.toString());
      //跳转自己的页面逻辑
      doSomeThing();
    }, onError: (Object error) {
      print("XiaoMiDataChannel---->" + error.toString());
    });
  }


  //方法名也和Android定义的一至
  String regId =await methodChannel.invokeMethod("getXiaoMiRegId");

  String getReciveData = await methodChannel.invokeMethod("getReciveData");


to sum up

  • If something goes wrong, you still have to calm down and take a good look at the document.
  • Be careful and then careful.
  • Thinking should diverge.

If you encounter problems, you can contact the exchange.

 

Guess you like

Origin blog.csdn.net/u013491829/article/details/109330207