作者微信 bishe2022

代码功能演示视频在页面下方,请先观看;如需定制开发,联系页面右侧客服
Android消息推送:手把手教你集成小米推送

Custom Tab


前言

b0.png

推送消息截图

  1. 该文档基于小米推送官方Demo进行解析,并给出简易推送Demo

  2. 看该文档前,请先阅读我写的另外两篇文章:
    史上最全解析Android消息推送解决方案
    Android推送:第三方消息推送平台详细解析


目录

648.png

目录


1. 官方Demo解析

首先,我们先对小米官方的推送Demo进行解析。

请先到官网下载官方DemoSDK说明文档

1.1 Demo概况

d9.png

Demo目录

目录说明:

接下来,我将对每个类进行详细分析

1.2 详细分析

1.2.1 DemoApplication类

继承自Application类,其作用主要是:

接下来我们通过代码来看下这两个功能如何实现:

DemoApplication.java

package com.xiaomi.mipushdemo;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.Application;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

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

import java.util.List;


public class DemoApplication extends Application {

    // 使用自己APP的ID(官网注册的)
    private static final String APP_ID = "1000270";
    // 使用自己APP的KEY(官网注册的)
    private static final String APP_KEY = "670100056270";

    // 此TAG在adb logcat中检索自己所需要的信息, 只需在命令行终端输入 adb logcat | grep
    // com.xiaomi.mipushdemo
    public static final String TAG = "com.xiaomi.mipushdemo";

    private static DemoHandler sHandler = null;
    private static MainActivity sMainActivity = null;

    //为了提高推送服务的注册率,官方Demo建议在Application的onCreate中初始化推送服务
    //你也可以根据需要,在其他地方初始化推送服务
    
    @Override
    public void onCreate() {

        super.onCreate();
        
        //判断用户是否已经打开App,详细见下面方法定义
        if (shouldInit()) {
        //注册推送服务
        //注册成功后会向DemoMessageReceiver发送广播
        // 可以从DemoMessageReceiver的onCommandResult方法中MiPushCommandMessage对象参数中获取注册信息
            MiPushClient.registerPush(this, APP_ID, APP_KEY);
         //参数说明
        //context:Android平台上app的上下文,建议传入当前app的application context
        //appID:在开发者网站上注册时生成的,MiPush推送服务颁发给app的唯一认证标识
       //appKey:在开发者网站上注册时生成的,与appID相对应,用于验证appID是否合法
        }


        //下面是与测试相关的日志设置
        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);
        if (sHandler == null) {
            sHandler = new DemoHandler(getApplicationContext());
        }
    }


//通过判断手机里的所有进程是否有这个App的进程
//从而判断该App是否有打开
    private boolean shouldInit() {
//通过ActivityManager我们可以获得系统里正在运行的activities
//包括进程(Process)等、应用程序/包、服务(Service)、任务(Task)信息。
        ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
        List<RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
        String mainProcessName = getPackageName();
        
       //获取本App的唯一标识
        int myPid = Process.myPid();
        //利用一个增强for循环取出手机里的所有进程
        for (RunningAppProcessInfo info : processInfos) {
            //通过比较进程的唯一标识和包名判断进程里是否存在该App
            if (info.pid == myPid && mainProcessName.equals(info.processName)) {
                return true;
            }
        }
        return false;
    }

    public static DemoHandler getHandler() {
        return sHandler;
    }

    public static void setMainActivity(MainActivity activity) {
        sMainActivity = activity;
    }


//通过设置Handler来设置提示文案
    public static class DemoHandler extends Handler {

        private Context context;

        public DemoHandler(Context context) {
            this.context = context;
        }

        @Override
        public void handleMessage(Message msg) {
            String s = (String) msg.obj;
            if (sMainActivity != null) {
                sMainActivity.refreshLogInfo();
            }
            if (!TextUtils.isEmpty(s)) {
                Toast.makeText(context, s, Toast.LENGTH_LONG).show();
            }
        }
    }
}


总结:

public static void registerPush(Context context, String appID, String appKey)


进行推送服务注册,详细参数如下:

40b.png

你也可以根据需要,在其他地方初始化推送服务

1.2.2 DemoMessageReceiver类

继承自PushMessageReceiver(抽象类,继承自BroadcastReceiver),其作用主要是:

DemoMessageReceiver.java

package com.xiaomi.mipushdemo;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import com.xiaomi.mipush.sdk.ErrorCode;
import com.xiaomi.mipush.sdk.MiPushClient;
import com.xiaomi.mipush.sdk.MiPushCommandMessage;
import com.xiaomi.mipush.sdk.MiPushMessage;
import com.xiaomi.mipush.sdk.PushMessageReceiver;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * 1、PushMessageReceiver 是个抽象类,该类继承了 BroadcastReceiver。
 * 2、需要将自定义的 DemoMessageReceiver 注册在 AndroidManifest.xml



public class DemoMessageReceiver extends PushMessageReceiver {

    private String mRegId;
    private String mTopic;
    private String mAlias;
    private String mAccount;
    private String mStartTime;
    private String mEndTime;


    //透传消息到达客户端时调用
    //作用:可通过参数message从而获得透传消息,具体请看官方SDK文档
    @Override
    public void onReceivePassThroughMessage(Context context, MiPushMessage message) {
        Log.v(DemoApplication.TAG,
                "onReceivePassThroughMessage is called. " + message.toString());
        String log = context.getString(R.string.recv_passthrough_message, message.getContent());
        MainActivity.logList.add(0, getSimpleDate() + " " + log);

        if (!TextUtils.isEmpty(message.getTopic())) {
            mTopic = message.getTopic();
        } else if (!TextUtils.isEmpty(message.getAlias())) {
            mAlias = message.getAlias();
        }

        Message msg = Message.obtain();
        msg.obj = log;
        DemoApplication.getHandler().sendMessage(msg);
    }


//通知消息到达客户端时调用
     //注:应用在前台时不弹出通知的通知消息到达客户端时也会回调函数
    //作用:通过参数message从而获得通知消息,具体请看官方SDK文档
   
    @Override
    public void onNotificationMessageArrived(Context context, MiPushMessage message) {
        Log.v(DemoApplication.TAG,
                "onNotificationMessageArrived is called. " + message.toString());
        String log = context.getString(R.string.arrive_notification_message, message.getContent());
        MainActivity.logList.add(0, getSimpleDate() + " " + log);

        if (!TextUtils.isEmpty(message.getTopic())) {
            mTopic = message.getTopic();
        } else if (!TextUtils.isEmpty(message.getAlias())) {
            mAlias = message.getAlias();
        }

        Message msg = Message.obtain();
        msg.obj = log;
        DemoApplication.getHandler().sendMessage(msg);
    }
    
    //用户手动点击通知栏消息时调用
     //注:应用在前台时不弹出通知的通知消息到达客户端时也会回调函数
    //作用:1. 通过参数message从而获得通知消息,具体请看官方SDK文档
    //2. 设置用户点击消息后打开应用 or 网页 or 其他页面

    @Override
    public void onNotificationMessageClicked(Context context, MiPushMessage message) {
        Log.v(DemoApplication.TAG,
                "onNotificationMessageClicked is called. " + message.toString());
        String log = context.getString(R.string.click_notification_message, message.getContent());
        MainActivity.logList.add(0, getSimpleDate() + " " + log);

        if (!TextUtils.isEmpty(message.getTopic())) {
            mTopic = message.getTopic();
        } else if (!TextUtils.isEmpty(message.getAlias())) {
            mAlias = message.getAlias();
        }

        Message msg = Message.obtain();
        if (message.isNotified()) {
            msg.obj = log;
        }
        DemoApplication.getHandler().sendMessage(msg);
    }


    
    //用来接收客户端向服务器发送命令后的响应结果。
    @Override
    public void onCommandResult(Context context, MiPushCommandMessage message) {
        Log.v(DemoApplication.TAG,
                "onCommandResult is called. " + message.toString());
        String command = message.getCommand();
        List<String> arguments = message.getCommandArguments();
        String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null);
        String cmdArg2 = ((arguments != null && arguments.size() > 1) ? arguments.get(1) : null);
        String log;
        if (MiPushClient.COMMAND_REGISTER.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                mRegId = cmdArg1;
                log = context.getString(R.string.register_success);

            } else {
                log = context.getString(R.string.register_fail);
            }
        } else if (MiPushClient.COMMAND_SET_ALIAS.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                mAlias = cmdArg1;
                log = context.getString(R.string.set_alias_success, mAlias);
            } else {
                log = context.getString(R.string.set_alias_fail, message.getReason());
            }
        } else if (MiPushClient.COMMAND_UNSET_ALIAS.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                mAlias = cmdArg1;
                log = context.getString(R.string.unset_alias_success, mAlias);
            } else {
                log = context.getString(R.string.unset_alias_fail, message.getReason());
            }
        } else if (MiPushClient.COMMAND_SET_ACCOUNT.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                mAccount = cmdArg1;
                log = context.getString(R.string.set_account_success, mAccount);
            } else {
                log = context.getString(R.string.set_account_fail, message.getReason());
            }
        } else if (MiPushClient.COMMAND_UNSET_ACCOUNT.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                mAccount = cmdArg1;
                log = context.getString(R.string.unset_account_success, mAccount);
            } else {
                log = context.getString(R.string.unset_account_fail, message.getReason());
            }
        } else if (MiPushClient.COMMAND_SUBSCRIBE_TOPIC.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                mTopic = cmdArg1;
                log = context.getString(R.string.subscribe_topic_success, mTopic);
            } else {
                log = context.getString(R.string.subscribe_topic_fail, message.getReason());
            }
        } else if (MiPushClient.COMMAND_UNSUBSCRIBE_TOPIC.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                mTopic = cmdArg1;
                log = context.getString(R.string.unsubscribe_topic_success, mTopic);
            } else {
                log = context.getString(R.string.unsubscribe_topic_fail, message.getReason());
            }
        } else if (MiPushClient.COMMAND_SET_ACCEPT_TIME.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                mStartTime = cmdArg1;
                mEndTime = cmdArg2;
                log = context.getString(R.string.set_accept_time_success, mStartTime, mEndTime);
            } else {
                log = context.getString(R.string.set_accept_time_fail, message.getReason());
            }
        } else {
            log = message.getReason();
        }
        MainActivity.logList.add(0, getSimpleDate() + "    " + log);

        Message msg = Message.obtain();
        msg.obj = log;
        DemoApplication.getHandler().sendMessage(msg);
    }


    //用于接收客户端向服务器发送注册命令后的响应结果。
    @Override
    public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {
        Log.v(DemoApplication.TAG,
                "onReceiveRegisterResult is called. " + message.toString());
        String command = message.getCommand();
        List<String> arguments = message.getCommandArguments();
        String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null);
        String log;
        if (MiPushClient.COMMAND_REGISTER.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                mRegId = cmdArg1;
                //打印日志:注册成功
                log = context.getString(R.string.register_success);
            } else {
                      //打印日志:注册失败
                log = context.getString(R.string.register_fail);
            }
        } else {
            log = message.getReason();
        }

        Message msg = Message.obtain();
        msg.obj = log;
        DemoApplication.getHandler().sendMessage(msg);
    }

    @SuppressLint("SimpleDateFormat")
    private static String getSimpleDate() {
        return new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date());
    }

}


总结

5072.png

515c.png 

1.2.3 MainActivity

用于给用户设置标识,如别名、标签、账号等等

MainActivity.java

public class MainActivity extends Activity {

    public static List<String> logList = new CopyOnWriteArrayList<String>();

    private TextView mLogView = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DemoApplication.setMainActivity(this);

        mLogView = (TextView) findViewById(R.id.log);
        
        // 设置别名
        findViewById(R.id.set_alias).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                final EditText editText = new EditText(MainActivity.this);
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle(R.string.set_alias)
                        .setView(editText)
                        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                String alias = editText.getText().toString();
//调用静态方法进行设置                                MiPushClient.setAlias(MainActivity.this, alias, null);
                            }

                        })
                        .setNegativeButton(R.string.cancel, null)
                        .show();
            }
        });
        // 撤销别名
        findViewById(R.id.unset_alias).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                final EditText editText = new EditText(MainActivity.this);
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle(R.string.unset_alias)
                        .setView(editText)
                        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                String alias = editText.getText().toString();
//调用静态方法进行设置                                  MiPushClient.unsetAlias(MainActivity.this, alias, null);
                            }

                        })
                        .setNegativeButton(R.string.cancel, null)
                        .show();

            }
        });
        // 设置帐号
        findViewById(R.id.set_account).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                final EditText editText = new EditText(MainActivity.this);
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle(R.string.set_account)
                        .setView(editText)
                        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                String account = editText.getText().toString();
//调用静态方法进行设置                                  MiPushClient.setUserAccount(MainActivity.this, account, null);
                            }

                        })
                        .setNegativeButton(R.string.cancel, null)
                        .show();

            }
        });
        // 撤销帐号
        findViewById(R.id.unset_account).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                final EditText editText = new EditText(MainActivity.this);
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle(R.string.unset_account)
                        .setView(editText)
                        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                String account = editText.getText().toString();
//调用静态方法进行设置                                  MiPushClient.unsetUserAccount(MainActivity.this, account, null);
                            }

                        })
                        .setNegativeButton(R.string.cancel, null)
                        .show();
            }
        });
        // 设置标签
        findViewById(R.id.subscribe_topic).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                final EditText editText = new EditText(MainActivity.this);
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle(R.string.subscribe_topic)
                        .setView(editText)
                        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                String topic = editText.getText().toString();
//调用静态方法进行设置                                  MiPushClient.subscribe(MainActivity.this, topic, null);
                            }

                        })
                        .setNegativeButton(R.string.cancel, null)
                        .show();
            }
        });
        // 撤销标签
        findViewById(R.id.unsubscribe_topic).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                final EditText editText = new EditText(MainActivity.this);
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle(R.string.unsubscribe_topic)
                        .setView(editText)
                        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                String topic = editText.getText().toString();
//调用静态方法进行设置                                  MiPushClient.unsubscribe(MainActivity.this, topic, null);
                            }

                        })
                        .setNegativeButton(R.string.cancel, null)
                        .show();
            }
        });
        // 设置接收消息时间
        findViewById(R.id.set_accept_time).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                new TimeIntervalDialog(MainActivity.this, new TimeIntervalInterface() {

                    @Override
                    public void apply(int startHour, int startMin, int endHour,
                                      int endMin) {
                        //调用静态方法进行设置  
                        MiPushClient.setAcceptTime(MainActivity.this, startHour, startMin, endHour, endMin, null);
                    }

                    @Override
                    public void cancel() {
                        //ignore
                    }

                })
                        .show();
            }
        });
        // 暂停推送
        findViewById(R.id.pause_push).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                MiPushClient.pausePush(MainActivity.this, null);
            }
        });

        findViewById(R.id.resume_push).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
            //调用静态方法进行设置  
                MiPushClient.resumePush(MainActivity.this, null);
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        refreshLogInfo();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        DemoApplication.setMainActivity(null);
    }

    public void refreshLogInfo() {
        String AllLog = "";
        for (String log : logList) {
            AllLog = AllLog + log + "\n\n";
        }
        mLogView.setText(AllLog);
    }
}


总结

根据需求对不同用户设置不同的推送标识,如别名、标签等等。

a. 别名(Alias)

效果等同于给RegId推送消息,Alias是除Regid(自动生成的)和UserAccount之外的第三个用户标识

//设置别名
MiPushClient.setAlias(Context context, String alias, String category);

//撤销别名
MiPushClient.unsetAlias(Context context, String alias, String category);
//参数说明
//context:Android平台上app的上下文,建议传入当前app的application context
//alias:为指定用户设置别名 / 为指定用户取消别名
//category:扩展参数,暂时没有用途,直接填null

//获取该客户端所有的别名
public static List<String> getAllAlias(final Context context)


b. 用户账号(UserAccoun)

//设置
MiPushClient.setUserAccount(final Context context, final String userAccount, String
category)

//撤销
MiPushClient.unsetUserAccount(final Context context, final String userAccount, String
category)
//参数说明
//context:Android平台上app的上下文,建议传入当前app的application context
//userAccount:为指定用户设置userAccount / 为指定用户取消userAccount
//category:扩展参数,暂时没有用途,直接填null

//获取该客户端所有设置的账号
public static List<String> getAllUserAccount(final Context context)


c. 标签(Topic)

//设置标签
MiPushClient.subscribe(Context context, String topic, String category);
//撤销标签
MiPushClient.unsubscribe(Context context, String topic, String category);
//参数说明
//context:Android平台上app的上下文,建议传入当前app的application context
//topic:为指定用户设置设置订阅的主题 / 为指定用户取消订阅的主题
//category:扩展参数,暂时没有用途,直接填null

//获取该客户端所有的标签
public static List<String> getAllTopic(final Context context);


TimeIntervalDialog

作用:用于设置推送的时间-开始时间+暂停时间

package com.xiaomi.mipushdemo;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TimePicker;
import android.widget.TimePicker.OnTimeChangedListener;

//继承OnTimeChangedListener接口
public class TimeIntervalDialog extends Dialog implements OnTimeChangedListener {

    
    private TimeIntervalInterface mTimeIntervalInterface;
    private Context mContext;
    private TimePicker mStartTimePicker, mEndTimePicker;
    private int mStartHour, mStartMinute, mEndHour, mEndMinute;

    private Button.OnClickListener clickListener = new Button.OnClickListener() {

        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.apply:
                    dismiss();
                    //设置时间参数
                    mTimeIntervalInterface.apply(mStartHour, mStartMinute, mEndHour, mEndMinute);
                    break;
                case R.id.cancel:
                    dismiss();
                    mTimeIntervalInterface.cancel();
                    break;
                default:
                    break;
            }
        }
    };

    public TimeIntervalDialog(Context context, TimeIntervalInterface timeIntervalInterface,
                              int startHour, int startMinute, int endHour, int endMinute) {
        super(context);
        mContext = context;
        this.mTimeIntervalInterface = timeIntervalInterface;
        this.mStartHour = startHour;
        this.mStartMinute = startMinute;
        this.mEndHour = endHour;
        this.mEndMinute = endMinute;
    }

    public TimeIntervalDialog(Context context, TimeIntervalInterface timeIntervalInterface) {
        this(context, timeIntervalInterface, 0, 0, 23, 59);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.set_time_dialog);
        setCancelable(true);
        setTitle(mContext.getString(R.string.set_accept_time));
        mStartTimePicker = (TimePicker) findViewById(R.id.startTimePicker);
        mStartTimePicker.setIs24HourView(true);
        mStartTimePicker.setCurrentHour(mStartHour);
        mStartTimePicker.setCurrentMinute(mStartMinute);
        mStartTimePicker.setOnTimeChangedListener(this);
        mEndTimePicker = (TimePicker) findViewById(R.id.endTimePicker);
        mEndTimePicker.setIs24HourView(true);
        mEndTimePicker.setCurrentHour(mEndHour);
        mEndTimePicker.setCurrentMinute(mEndMinute);
        mEndTimePicker.setOnTimeChangedListener(this);
        Button applyBtn = (Button) findViewById(R.id.apply);
        applyBtn.setOnClickListener(clickListener);
        Button cancelBtn = (Button) findViewById(R.id.cancel);
        cancelBtn.setOnClickListener(clickListener);
    }

    @Override
    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
        if (view == mStartTimePicker) {
            mStartHour = hourOfDay;
            mStartMinute = minute;
        } else if (view == mEndTimePicker) {
            mEndHour = hourOfDay;
            mEndMinute = minute;
        }
    }

    interface TimeIntervalInterface {
        void apply(int startHour, int startMin, int endHour, int endMin);

        void cancel();
    }
}


总结

//设置推送时间(开始 & 结束)
MiPushClient.setAcceptTime(Context context, int startHour, int startMin, int endHour,
int endMin, String category)
//设置暂停推送时间、恢复推送时间
pausePush(Context context, String category)`和`resumePush(Context context, String category)
//参数说明
//context:Android平台上app的上下文,建议传入当前app的application context
//startHour:接收时段开始时间的小时
//startMin  :接收时段开始时间的分钟
//endHour:接收时段结束时间的小时
//endMin:接收时段结束时间的分钟
//category:扩展参数,暂时没有用途,直接填null


AndroidManifest文件的配置

//小米推送支持最低的Android版本是2.2
<uses-sdk  android:minSdkVersion="8"/>

//设置一系列权限
    <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.GET_TASKS" />
    <uses-permission android:name="android.permission.VIBRATE" />

//这里com.xiaomi.mipushdemo改成自身app的包名
    <permission android:name="com.xiaomi.mipushdemo.permission.MIPUSH_RECEIVE" android:protectionLevel="signature" />

//这里com.xiaomi.mipushdemo改成自身app的包名
    <uses-permission android:name="com.xiaomi.mipushdemo.permission.MIPUSH_RECEIVE" />


//注册广播BroadcastReceiver & Service
//都是静态注册,因为要长期处在后台运行
//注:共是3个广播接收器和4个服务,其中包括继承了PushMessageReceiver的DemoMessageReceiver
                
        //4个后台服务
        <service
          android:enabled="true"
          android:process=":pushservice"
          android:name="com.xiaomi.push.service.XMPushService"/>

        //此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必须在2.2.5版本以后(包括2.2.5版本)加入
        <service
          android:enabled="true"
          android:exported="true"
          android:name="com.xiaomi.mipush.sdk.PushMessageHandler" /> 

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

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

        <receiver
          android:exported="false"
          android:process=":pushservice"
          android:name="com.xiaomi.push.service.receivers.PingReceiver" >
          <intent-filter>
            <action android:name="com.xiaomi.push.PING_TIMER" />
          </intent-filter>
        </receiver>

//继承了PushMessageReceiver的DemoMessageReceiver的广播注册
        <receiver
            android:name="com.xiaomi.mipushdemo.DemoMessageReceiver"
            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>


2. 集成小米推送步骤汇总

在Android6.0里面的权限需要动态获取

接下来,我们来按照上面的步骤,一步步来实现一个简易的小米推送Demo

3. 实例解析

步骤1:在小米推送平台进行相关注册开发者账号,并进行应用的注册:应用包名,AppID和AppKey

注意,填入的包名要跟你的应用App的包名是一致的

c1f.png

创建应用

8ab1.png

AppID和Key

步骤2:将小米推送的SDK包加入到你应用的库里

放入到app/libs文件夹下,然后右键点击add as Library,最后点击Model就导入成功了
点击此处进行下载

e8b.png

小米推送SDK

62bb5294096c.png

导入包

步骤3:在应用内初始化小米推送服务

为了提高推送服务的注册率,我选择在Application的onCreate中初始化推送服务

BaseActivity.java

package scut.carson_ho.demo_mipush;

import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.os.Process;

import com.xiaomi.mipush.sdk.MiPushClient;

import java.util.List;

/**
 * Created by Carson_Ho on 16/10/26.
 */

    //主要要继承Application
public class BaseActivity extends Application {
    // 使用自己APP的ID(官网注册的)
    private static final String APP_ID = "2882303761517520369";
    // 使用自己APP的Key(官网注册的)
    private static final String APP_KEY = "5401752085369";


    //为了提高推送服务的注册率,我建议在Application的onCreate中初始化推送服务
    //你也可以根据需要,在其他地方初始化推送服务
    @Override
    public void onCreate() {
        super.onCreate();


        if (shouldInit()) {
            //注册推送服务
            //注册成功后会向DemoMessageReceiver发送广播
            // 可以从DemoMessageReceiver的onCommandResult方法中MiPushCommandMessage对象参数中获取注册信息
            MiPushClient.registerPush(this, APP_ID, APP_KEY);
        }
    }

    //通过判断手机里的所有进程是否有这个App的进程
    //从而判断该App是否有打开
    private boolean shouldInit() {

    //通过ActivityManager我们可以获得系统里正在运行的activities
    //包括进程(Process)等、应用程序/包、服务(Service)、任务(Task)信息。
        ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
        List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
        String mainProcessName = getPackageName();

        //获取本App的唯一标识
        int myPid = Process.myPid();
        //利用一个增强for循环取出手机里的所有进程
        for (ActivityManager.RunningAppProcessInfo info : processInfos) {
            //通过比较进程的唯一标识和包名判断进程里是否存在该App
            if (info.pid == myPid && mainProcessName.equals(info.processName)) {
                return true;
            }
        }
        return false;
    }
}


注意要在Android.manifest.xml里的application里加入

android:name=".BaseActivity"


这样在应用初始化时是第一个加载BaseActivity.java类文件的
如下图:

fb875d22516fe.png

示意图

步骤4:设置子类继承PushMessageReceiver,并复写相关推送消息的方法

Mipush_Broadcast.java

package scut.carson_ho.demo_mipush;

import android.content.Context;

import com.xiaomi.mipush.sdk.ErrorCode;
import com.xiaomi.mipush.sdk.MiPushClient;
import com.xiaomi.mipush.sdk.MiPushCommandMessage;
import com.xiaomi.mipush.sdk.MiPushMessage;
import com.xiaomi.mipush.sdk.PushMessageReceiver;

/**
 * Created by Carson_Ho on 16/10/26.
 */

public class Mipush_Broadcast extends PushMessageReceiver {

    //透传消息到达客户端时调用
    //作用:可通过参数message从而获得透传消息,具体请看官方SDK文档
    @Override
    public void onReceivePassThroughMessage(Context context, MiPushMessage message) {

        //打印消息方便测试
        System.out.println("透传消息到达了");
        System.out.println("透传消息是"+message.toString());

    }


//通知消息到达客户端时调用
    //注:应用在前台时不弹出通知的通知消息到达客户端时也会回调函数
    //作用:通过参数message从而获得通知消息,具体请看官方SDK文档

    @Override
    public void onNotificationMessageArrived(Context context, MiPushMessage message) {
        //打印消息方便测试
        System.out.println("通知消息到达了");
        System.out.println("通知消息是"+message.toString());
    }

    //用户手动点击通知栏消息时调用
    //注:应用在前台时不弹出通知的通知消息到达客户端时也会回调函数
    //作用:1. 通过参数message从而获得通知消息,具体请看官方SDK文档
    //2. 设置用户点击消息后打开应用 or 网页 or 其他页面

    @Override
    public void onNotificationMessageClicked(Context context, MiPushMessage message) {

        //打印消息方便测试
        System.out.println("用户点击了通知消息");
        System.out.println("通知消息是" + message.toString());
        System.out.println("点击后,会进入应用" );

    }

    //用来接收客户端向服务器发送命令后的响应结果。
    @Override
    public void onCommandResult(Context context, MiPushCommandMessage message) {

        String command = message.getCommand();
        System.out.println(command );
        

        if (MiPushClient.COMMAND_REGISTER.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                
                //打印信息便于测试注册成功与否
                System.out.println("注册成功");

            } else {
                System.out.println("注册失败");
            }
        }
    }

    //用于接收客户端向服务器发送注册命令后的响应结果。
    @Override
    public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {

        String command = message.getCommand();
        System.out.println(command );
    
        if (MiPushClient.COMMAND_REGISTER.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                
                //打印日志:注册成功
                System.out.println("注册成功");
            } else {
                //打印日志:注册失败
                System.out.println("注册失败");
            }
        } else {
            System.out.println("其他情况"+message.getReason());
        }
    }

}

具体设置请看官方SDK文档,这里只给出最简单Demo,不作过多描述

步骤5:在AndroidManifest文件里面配置好权限、注册Service和BroadcastReceiver

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="scut.carson_ho.demo_mipush">

    //相关权限
    <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.GET_TASKS" />
    <uses-permission android:name="android.permission.VIBRATE" />


    //注意这里.permission.MIPUSH_RECEIVE是自身app的包名
    <permission android:name="scut.carson_ho.demo_mipush.permission.MIPUSH_RECEIVE" android:protectionLevel="signature" />

    //注意这里.permission.MIPUSH_RECEIVE是自身app的包名
    <uses-permission android:name="scut.carson_ho.demo_mipush.permission.MIPUSH_RECEIVE" />

//注意要初始化BaseActivity.java类
    <application
        android:name=".BaseActivity"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>



    //注册广播BroadcastReceiver和Service
    //都是静态注册,因为要长期处在后台运行
    //注:共是3个广播接收器和4个服务,其中包括继承了PushMessageReceiver的DemoMessageReceiver

    //4个后台服务
    <service
        android:enabled="true"
        android:process=":pushservice"
        android:name="com.xiaomi.push.service.XMPushService"/>

    //此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必须在2.2.5版本以后(包括2.2.5版本)加入
    <service
        android:enabled="true"
        android:exported="true"
        android:name="com.xiaomi.mipush.sdk.PushMessageHandler" />

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


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

    <receiver
        android:exported="false"
        android:process=":pushservice"
        android:name="com.xiaomi.push.service.receivers.PingReceiver" >
        <intent-filter>
            <action android:name="com.xiaomi.push.PING_TIMER" />
        </intent-filter>
    </receiver>

    //继承了PushMessageReceiver的DemoMessageReceiver的广播注册
    <receiver
        android:name=".Mipush_Broadcast"
        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>


    </application>
</manifest>



步骤6:根据需要设置一系列的推送设置,如用户别名、标签等等

运行结果

5f99d.png

测试成功结果

好了,客户端的代码写好后,可以去小米官网测试一下消息推送了

步骤1:在小米官网的消息推送里选择你创建的应用,然后点击“推送工具”

845c.png

点击推送工具

步骤2:设置推送消息的相关信息

可进行的配置非常全面,基本上能满足推送的需求

b4cd7.png

设置推送消息


bcd6.png

设置推送消息

推送的结果

8da71.png

消息到达客户端

3.png

测试结果


076.png

测试结果:收到的信息

6cb.png

点击通知栏消息后

4. Demo下载地址

Carson的Github:Demo_MiPush

5. 关于对小米推送的思考(问题)

上述说的小米推送看似简单:初始化推送服务 + 相关推送设置。但是,好的代码不仅能在正常情况下工作,还应该充分考虑失败情况。那么,有什么样的失败情况需要我们考虑呢?

小米推送的Demo里并没有相关措施解决这个问题

932.png

解决逻辑

  1. 知识点涵盖:网络数据的检测 & 广播接收器

  2. 具体请看我写的另外两篇文章:
    Android:BroadcastReceiver广播接收器最全面解析
    Android:检测网络状态&监听网络变化

总结

全面考虑到所有异常问题并恰当地进行处理才能真正体现程序猿的功力,希望大家做撸代码的时候不要只做代码的搬运工,纯粹写代码并不会让你成长,关键在于思考

6. 总结



转载自:https://www.jianshu.com/p/b1134bebc2d4

Home