前言
在Android开发中,消息推送功能的使用非常常见。
推送消息截图
为了降低开发成本,使用第三方推送是现今较为流行的解决方案。
今天,我将手把手教大家如何在你的应用里集成小米推送
该文档基于小米推送官方Demo进行解析,并给出简易推送Demo
看该文档前,请先阅读我写的另外两篇文章:
目录
目录
1. 官方Demo解析
首先,我们先对小米官方的推送Demo进行解析。
1.1 Demo概况
need-to-insert-img
Demo目录
目录说明:
DemoApplication类
继承自Application类,其作用主要是:设置App的ID & Key、注册推送服务
DemoMessageReceiver类
继承自BroadcastReceiver,用于接收推送消息并对这些消息进行处理
MainActivity
实现界面按钮处理 & 设置本地推送方案
TimeIntervalDialog
设置推送的时间间段
接下来,我将对每个类进行详细分析
1.2 详细分析
1.2.1 DemoApplication类
继承自Application类,其作用主要是:
设置App的ID & Key
注册推送服务
接下来我们通过代码来看下这两个功能如何实现:
DemoApplication.java
packagecom.xiaomi.mipushdemo;importandroid.app.ActivityManager;importandroid.app.ActivityManager.RunningAppProcessInfo;importandroid.app.Application;importandroid.content.Context;importandroid.os.Handler;importandroid.os.Message;importandroid.os.Process;importandroid.text.TextUtils;importandroid.util.Log;importandroid.widget.Toast;importcom.xiaomi.channel.commonutils.logger.LoggerInterface;importcom.xiaomi.mipush.sdk.Logger;importcom.xiaomi.mipush.sdk.MiPushClient;importjava.util.List;publicclassDemoApplicationextendsApplication{// 使用自己APP的ID(官网注册的)privatestaticfinalString APP_ID ="1000270";// 使用自己APP的KEY(官网注册的)privatestaticfinalString APP_KEY ="670100056270";// 此TAG在adb logcat中检索自己所需要的信息, 只需在命令行终端输入 adb logcat | grep// com.xiaomi.mipushdemopublicstaticfinalString TAG ="com.xiaomi.mipushdemo";privatestaticDemoHandler sHandler =null;privatestaticMainActivity sMainActivity =null;//为了提高推送服务的注册率,官方Demo建议在Application的onCreate中初始化推送服务//你也可以根据需要,在其他地方初始化推送服务@OverridepublicvoidonCreate(){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 =newLoggerInterface() {@OverridepublicvoidsetTag(String tag){// ignore}@Overridepublicvoidlog(String content, Throwable t){ Log.d(TAG, content, t); }@Overridepublicvoidlog(String content){ Log.d(TAG, content); } }; Logger.setLogger(this, newLogger);if(sHandler ==null) { sHandler =newDemoHandler(getApplicationContext()); } }//通过判断手机里的所有进程是否有这个App的进程//从而判断该App是否有打开privatebooleanshouldInit(){//通过ActivityManager我们可以获得系统里正在运行的activities//包括进程(Process)等、应用程序/包、服务(Service)、任务(Task)信息。ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)); List processInfos = am.getRunningAppProcesses(); String mainProcessName = getPackageName();//获取本App的唯一标识intmyPid = Process.myPid();//利用一个增强for循环取出手机里的所有进程for(RunningAppProcessInfo info : processInfos) {//通过比较进程的唯一标识和包名判断进程里是否存在该Appif(info.pid == myPid && mainProcessName.equals(info.processName)) {returntrue; } }returnfalse; }publicstaticDemoHandlergetHandler(){returnsHandler; }publicstaticvoidsetMainActivity(MainActivity activity){ sMainActivity = activity; }//通过设置Handler来设置提示文案publicstaticclassDemoHandlerextendsHandler{privateContext context;publicDemoHandler(Context context){this.context = context; }@OverridepublicvoidhandleMessage(Message msg){ String s = (String) msg.obj;if(sMainActivity !=null) { sMainActivity.refreshLogInfo(); }if(!TextUtils.isEmpty(s)) { Toast.makeText(context, s, Toast.LENGTH_LONG).show(); } } }}
总结:
步骤1:先判断应用App是否已开启 - 通过判断系统里的进程
通过静态方法
publicstaticvoidregisterPush(Context context,StringappID,StringappKey)
进行推送服务注册,详细参数如下:
need-to-insert-img
为了提高注册率,最好在Application的onCreate中初始化推送服务
你也可以根据需要,在其他地方初始化推送服务
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.xmlpublic 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()); Stringlog= context.getString(R.string.recv_passthrough_message, message.getContent()); MainActivity.logList.add(0, getSimpleDate() +" "+log);if(!TextUtils.isEmpty(message.getTopic())) { mTopic = message.getTopic(); }elseif(!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()); Stringlog= context.getString(R.string.arrive_notification_message, message.getContent()); MainActivity.logList.add(0, getSimpleDate() +" "+log);if(!TextUtils.isEmpty(message.getTopic())) { mTopic = message.getTopic(); }elseif(!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()); Stringlog= context.getString(R.string.click_notification_message, message.getContent()); MainActivity.logList.add(0, getSimpleDate() +" "+log);if(!TextUtils.isEmpty(message.getTopic())) { mTopic = message.getTopic(); }elseif(!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()); Stringcommand= message.getCommand(); List 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); Stringlog;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); } }elseif(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()); } }elseif(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()); } }elseif(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()); } }elseif(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()); } }elseif(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()); } }elseif(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()); } }elseif(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()); Stringcommand= message.getCommand(); List arguments = message.getCommandArguments(); String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null); Stringlog;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 StringgetSimpleDate() {returnnew SimpleDateFormat("MM-dd hh:mm:ss").format(new Date()); }}
总结
根据需要复写PushMessageReceiver里对消息的相关处理方法,以下是相关方法的详情:
need-to-insert-img
相关方法详情
关于onCommandResult(Context context,MiPushCommandMessage message)
a. 作用:当客户端向服务器发送注册push、设置alias、取消注册alias、订阅topic、取消订阅topic等等命令后,从服务器返回结果。
b. 参数说明:
need-to-insert-img
参数说明
1.2.3 MainActivity
用于给用户设置标识,如别名、标签、账号等等
MainActivity.java
publicclassMainActivityextendsActivity{publicstaticList logList =newCopyOnWriteArrayList();privateTextView mLogView =null;@OverrideprotectedvoidonCreate(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(newOnClickListener() {@OverridepublicvoidonClick(View v){finalEditText editText =newEditText(MainActivity.this);newAlertDialog.Builder(MainActivity.this) .setTitle(R.string.set_alias) .setView(editText) .setPositiveButton(R.string.ok,newDialogInterface.OnClickListener() {@OverridepublicvoidonClick(DialogInterface dialog,intwhich){ String alias = editText.getText().toString();//调用静态方法进行设置 MiPushClient.setAlias(MainActivity.this, alias, null);} }) .setNegativeButton(R.string.cancel,null) .show(); } });// 撤销别名findViewById(R.id.unset_alias).setOnClickListener(newOnClickListener() {@OverridepublicvoidonClick(View v){finalEditText editText =newEditText(MainActivity.this);newAlertDialog.Builder(MainActivity.this) .setTitle(R.string.unset_alias) .setView(editText) .setPositiveButton(R.string.ok,newDialogInterface.OnClickListener() {@OverridepublicvoidonClick(DialogInterface dialog,intwhich){ String alias = editText.getText().toString();//调用静态方法进行设置 MiPushClient.unsetAlias(MainActivity.this, alias, null);} }) .setNegativeButton(R.string.cancel,null) .show(); } });// 设置帐号findViewById(R.id.set_account).setOnClickListener(newOnClickListener() {@OverridepublicvoidonClick(View v){finalEditText editText =newEditText(MainActivity.this);newAlertDialog.Builder(MainActivity.this) .setTitle(R.string.set_account) .setView(editText) .setPositiveButton(R.string.ok,newDialogInterface.OnClickListener() {@OverridepublicvoidonClick(DialogInterface dialog,intwhich){ String account = editText.getText().toString();//调用静态方法进行设置 MiPushClient.setUserAccount(MainActivity.this, account, null);} }) .setNegativeButton(R.string.cancel,null) .show(); } });// 撤销帐号findViewById(R.id.unset_account).setOnClickListener(newOnClickListener() {@OverridepublicvoidonClick(View v){finalEditText editText =newEditText(MainActivity.this);newAlertDialog.Builder(MainActivity.this) .setTitle(R.string.unset_account) .setView(editText) .setPositiveButton(R.string.ok,newDialogInterface.OnClickListener() {@OverridepublicvoidonClick(DialogInterface dialog,intwhich){ String account = editText.getText().toString();//调用静态方法进行设置 MiPushClient.unsetUserAccount(MainActivity.this, account, null);} }) .setNegativeButton(R.string.cancel,null) .show(); } });// 设置标签findViewById(R.id.subscribe_topic).setOnClickListener(newOnClickListener() {@OverridepublicvoidonClick(View v){finalEditText editText =newEditText(MainActivity.this);newAlertDialog.Builder(MainActivity.this) .setTitle(R.string.subscribe_topic) .setView(editText) .setPositiveButton(R.string.ok,newDialogInterface.OnClickListener() {@OverridepublicvoidonClick(DialogInterface dialog,intwhich){ String topic = editText.getText().toString();//调用静态方法进行设置 MiPushClient.subscribe(MainActivity.this, topic, null);} }) .setNegativeButton(R.string.cancel,null) .show(); } });// 撤销标签findViewById(R.id.unsubscribe_topic).setOnClickListener(newOnClickListener() {@OverridepublicvoidonClick(View v){finalEditText editText =newEditText(MainActivity.this);newAlertDialog.Builder(MainActivity.this) .setTitle(R.string.unsubscribe_topic) .setView(editText) .setPositiveButton(R.string.ok,newDialogInterface.OnClickListener() {@OverridepublicvoidonClick(DialogInterface dialog,intwhich){ String topic = editText.getText().toString();//调用静态方法进行设置 MiPushClient.unsubscribe(MainActivity.this, topic, null);} }) .setNegativeButton(R.string.cancel,null) .show(); } });// 设置接收消息时间findViewById(R.id.set_accept_time).setOnClickListener(newOnClickListener() {@OverridepublicvoidonClick(View v){newTimeIntervalDialog(MainActivity.this,newTimeIntervalInterface() {@Overridepublicvoidapply(intstartHour,intstartMin,intendHour,intendMin){//调用静态方法进行设置 MiPushClient.setAcceptTime(MainActivity.this, startHour, startMin, endHour, endMin,null); }@Overridepublicvoidcancel(){//ignore} }) .show(); } });// 暂停推送findViewById(R.id.pause_push).setOnClickListener(newOnClickListener() {@OverridepublicvoidonClick(View v){ MiPushClient.pausePush(MainActivity.this,null); } }); findViewById(R.id.resume_push).setOnClickListener(newOnClickListener() {@OverridepublicvoidonClick(View v){//调用静态方法进行设置 MiPushClient.resumePush(MainActivity.this,null); } }); }@OverrideprotectedvoidonResume(){super.onResume(); refreshLogInfo(); }@OverrideprotectedvoidonDestroy(){super.onDestroy(); DemoApplication.setMainActivity(null); }publicvoidrefreshLogInfo(){ String AllLog ="";for(String log : logList) { AllLog = AllLog + log +"\n\n"; } mLogView.setText(AllLog); }}
总结
根据需求对不同用户设置不同的推送标识,如别名、标签等等。
a. 别名(Alias)
开发者可以为指定用户设置别名,然后给这个别名推送消息,
效果等同于给RegId推送消息,Alias是除Regid(自动生成的)和UserAccount之外的第三个用户标识
开发者可以取消指定用户的某个别名,服务器就不会给这个别名推送消息了。
//设置别名MiPushClient.setAlias(Context context,Stringalias,Stringcategory);//撤销别名MiPushClient.unsetAlias(Context context,Stringalias,Stringcategory);//参数说明//context:Android平台上app的上下文,建议传入当前app的application context//alias:为指定用户设置别名 / 为指定用户取消别名//category:扩展参数,暂时没有用途,直接填null//获取该客户端所有的别名publicstaticList getAllAlias(final Context context)
b. 用户账号(UserAccoun)
开发者可以为指定用户设置userAccount
开发者可以取消指定用户的某个userAccount,服务器就不会给这个userAccount推送消息了
//设置MiPushClient.setUserAccount(finalContext context,finalString userAccount, Stringcategory)//撤销MiPushClient.unsetUserAccount(finalContext context,finalString userAccount, Stringcategory)//参数说明//context:Android平台上app的上下文,建议传入当前app的application context//userAccount:为指定用户设置userAccount / 为指定用户取消userAccount//category:扩展参数,暂时没有用途,直接填null//获取该客户端所有设置的账号publicstaticList getAllUserAccount(finalContext context)
c. 标签(Topic)
开发者可以结合自己的业务特征,给用户打上不同的标签。
消息推送时,开发者可以结合每条消息的内容和目标用户,为每条消息选择对应的标签,为开发者可以根据订阅的主题实现分组群发,从而进行消息的精准推送
//设置标签MiPushClient.subscribe(Context context,Stringtopic,Stringcategory);//撤销标签MiPushClient.unsubscribe(Context context,Stringtopic,Stringcategory);//参数说明//context:Android平台上app的上下文,建议传入当前app的application context//topic:为指定用户设置设置订阅的主题 / 为指定用户取消订阅的主题//category:扩展参数,暂时没有用途,直接填null//获取该客户端所有的标签publicstaticList getAllTopic(final Context context);
TimeIntervalDialog
作用:用于设置推送的时间-开始时间+暂停时间
packagecom.xiaomi.mipushdemo;importandroid.app.Dialog;importandroid.content.Context;importandroid.os.Bundle;importandroid.view.View;importandroid.widget.Button;importandroid.widget.TimePicker;importandroid.widget.TimePicker.OnTimeChangedListener;//继承OnTimeChangedListener接口publicclassTimeIntervalDialogextendsDialogimplementsOnTimeChangedListener{privateTimeIntervalInterface mTimeIntervalInterface;privateContext mContext;privateTimePicker mStartTimePicker, mEndTimePicker;privateintmStartHour, mStartMinute, mEndHour, mEndMinute;privateButton.OnClickListener clickListener =newButton.OnClickListener() {@OverridepublicvoidonClick(View v){switch(v.getId()) {caseR.id.apply: dismiss();//设置时间参数mTimeIntervalInterface.apply(mStartHour, mStartMinute, mEndHour, mEndMinute);break;caseR.id.cancel: dismiss(); mTimeIntervalInterface.cancel();break;default:break; } } };publicTimeIntervalDialog(Context context, TimeIntervalInterface timeIntervalInterface,intstartHour,intstartMinute,intendHour,intendMinute){super(context); mContext = context;this.mTimeIntervalInterface = timeIntervalInterface;this.mStartHour = startHour;this.mStartMinute = startMinute;this.mEndHour = endHour;this.mEndMinute = endMinute; }publicTimeIntervalDialog(Context context, TimeIntervalInterface timeIntervalInterface){this(context, timeIntervalInterface,0,0,23,59); }@OverrideprotectedvoidonCreate(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); }@OverridepublicvoidonTimeChanged(TimePicker view,inthourOfDay,intminute){if(view == mStartTimePicker) { mStartHour = hourOfDay; mStartMinute = minute; }elseif(view == mEndTimePicker) { mEndHour = hourOfDay; mEndMinute = minute; } }interfaceTimeIntervalInterface{voidapply(intstartHour,intstartMin,intendHour,intendMin);voidcancel(); }}
总结
使用一个继承了Dialog类的TimeIntervalDialog类进行推送时间的配置
可进行的配置:设置推送时间(开始 & 结束)、暂停推送时间、恢复推送时间
//设置推送时间(开始 & 结束)MiPushClient.setAcceptTime(Context context,intstartHour,intstartMin,intendHour,intendMin, 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//设置一系列权限//这里com.xiaomi.mipushdemo改成自身app的包名//这里com.xiaomi.mipushdemo改成自身app的包名//注册广播BroadcastReceiver & Service//都是静态注册,因为要长期处在后台运行//注:共是3个广播接收器和4个服务,其中包括继承了PushMessageReceiver的DemoMessageReceiver //4个后台服务//此service必须在3.0.1版本以后(包括3.0.1版本)加入//此service必须在2.2.5版本以后(包括2.2.5版本)加入//3个广播//继承了PushMessageReceiver的DemoMessageReceiver的广播注册
2. 集成小米推送步骤汇总
步骤1:在小米推送平台进行相关注册开发者账号,并进行应用的注册:应用包名,AppID和AppKey
步骤2:将小米推送的SDK包加入库
步骤3:在应用内初始化小米推送服务
步骤4:继承PushMessageReceiver,并复写相关推送消息的方法
步骤5:在AndroidManifest文件里面配置好权限、注册Service和BroadcastReceiver
在Android6.0里面的权限需要动态获取
步骤6:根据需要设置一系列的推送设置,如用户别名、标签等等
接下来,我们来按照上面的步骤,一步步来实现一个简易的小米推送Demo
3. 实例解析
步骤1:在小米推送平台进行相关注册开发者账号,并进行应用的注册:应用包名,AppID和AppKey
注意,填入的包名要跟你的应用App的包名是一致的
创建应用
AppID和Key
步骤2:将小米推送的SDK包加入到你应用的库里
放入到app/libs文件夹下,然后右键点击add as Library,最后点击Model就导入成功了
小米推送SDK
导入包
步骤3:在应用内初始化小米推送服务
为了提高推送服务的注册率,我选择在Application的onCreate中初始化推送服务
BaseActivity.java
packagescut.carson_ho.demo_mipush;importandroid.app.ActivityManager;importandroid.app.Application;importandroid.content.Context;importandroid.os.Process;importcom.xiaomi.mipush.sdk.MiPushClient;importjava.util.List;/**
* Created by Carson_Ho on 16/10/26.
*///主要要继承ApplicationpublicclassBaseActivityextendsApplication{// 使用自己APP的ID(官网注册的)privatestaticfinalString APP_ID ="2882303761517520369";// 使用自己APP的Key(官网注册的)privatestaticfinalString APP_KEY ="5401752085369";//为了提高推送服务的注册率,我建议在Application的onCreate中初始化推送服务//你也可以根据需要,在其他地方初始化推送服务@OverridepublicvoidonCreate(){super.onCreate();if(shouldInit()) {//注册推送服务//注册成功后会向DemoMessageReceiver发送广播// 可以从DemoMessageReceiver的onCommandResult方法中MiPushCommandMessage对象参数中获取注册信息MiPushClient.registerPush(this, APP_ID, APP_KEY); } }//通过判断手机里的所有进程是否有这个App的进程//从而判断该App是否有打开privatebooleanshouldInit(){//通过ActivityManager我们可以获得系统里正在运行的activities//包括进程(Process)等、应用程序/包、服务(Service)、任务(Task)信息。ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)); List processInfos = am.getRunningAppProcesses(); String mainProcessName = getPackageName();//获取本App的唯一标识intmyPid = Process.myPid();//利用一个增强for循环取出手机里的所有进程for(ActivityManager.RunningAppProcessInfo info : processInfos) {//通过比较进程的唯一标识和包名判断进程里是否存在该Appif(info.pid == myPid && mainProcessName.equals(info.processName)) {returntrue; } }returnfalse; }}
注意要在Android.manifest.xml里的application里加入
android:name=".BaseActivity"
这样在应用初始化时是第一个加载BaseActivity.java类文件的
如下图:
示意图
步骤4:设置子类继承PushMessageReceiver,并复写相关推送消息的方法
Mipush_Broadcast.java
packagescut.carson_ho.demo_mipush;importandroid.content.Context;importcom.xiaomi.mipush.sdk.ErrorCode;importcom.xiaomi.mipush.sdk.MiPushClient;importcom.xiaomi.mipush.sdk.MiPushCommandMessage;importcom.xiaomi.mipush.sdk.MiPushMessage;importcom.xiaomi.mipush.sdk.PushMessageReceiver;/**
* Created by Carson_Ho on 16/10/26.
*/publicclassMipush_BroadcastextendsPushMessageReceiver{//透传消息到达客户端时调用//作用:可通过参数message从而获得透传消息,具体请看官方SDK文档@OverridepublicvoidonReceivePassThroughMessage(Context context, MiPushMessage message){//打印消息方便测试System.out.println("透传消息到达了"); System.out.println("透传消息是"+message.toString()); }//通知消息到达客户端时调用//注:应用在前台时不弹出通知的通知消息到达客户端时也会回调函数//作用:通过参数message从而获得通知消息,具体请看官方SDK文档@OverridepublicvoidonNotificationMessageArrived(Context context, MiPushMessage message){//打印消息方便测试System.out.println("通知消息到达了"); System.out.println("通知消息是"+message.toString()); }//用户手动点击通知栏消息时调用//注:应用在前台时不弹出通知的通知消息到达客户端时也会回调函数//作用:1. 通过参数message从而获得通知消息,具体请看官方SDK文档//2. 设置用户点击消息后打开应用 or 网页 or 其他页面@OverridepublicvoidonNotificationMessageClicked(Context context, MiPushMessage message){//打印消息方便测试System.out.println("用户点击了通知消息"); System.out.println("通知消息是"+ message.toString()); System.out.println("点击后,会进入应用"); }//用来接收客户端向服务器发送命令后的响应结果。@OverridepublicvoidonCommandResult(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("注册失败"); } } }//用于接收客户端向服务器发送注册命令后的响应结果。@OverridepublicvoidonReceiveRegisterResult(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
//相关权限//注意这里.permission.MIPUSH_RECEIVE是自身app的包名//注意这里.permission.MIPUSH_RECEIVE是自身app的包名//注意要初始化BaseActivity.java类//注册广播BroadcastReceiver和Service //都是静态注册,因为要长期处在后台运行 //注:共是3个广播接收器和4个服务,其中包括继承了PushMessageReceiver的DemoMessageReceiver //4个后台服务//此service必须在3.0.1版本以后(包括3.0.1版本)加入//此service必须在2.2.5版本以后(包括2.2.5版本)加入//3个广播//继承了PushMessageReceiver的DemoMessageReceiver的广播注册
步骤6:根据需要设置一系列的推送设置,如用户别名、标签等等
此处是简单Demo,所以不作过多的设置
更多设置请回看上方官方Demo解析
运行结果
测试成功结果
好了,客户端的代码写好后,可以去小米官网测试一下消息推送了
步骤1:在小米官网的消息推送里选择你创建的应用,然后点击“推送工具”
点击推送工具
步骤2:设置推送消息的相关信息
可进行的配置非常全面,基本上能满足推送的需求
设置推送消息
设置推送消息
推送的结果
消息到达客户端
测试结果
测试结果:收到的信息
点击通知栏消息后
4. Demo下载地址
Carson的Github:Demo_MiPush
5. 关于对小米推送的思考(问题)
上述说的小米推送看似简单:初始化推送服务 + 相关推送设置。但是,好的代码不仅能在正常情况下工作,还应该充分考虑失败情况。那么,有什么样的失败情况需要我们考虑呢?
背景:在这个初始化推送服务的过程中,是需要联系小米推送的服务器来申请reg id(即推送token)。
冲突:初始化过程可能失败:网络问题(没网or网络信号弱)、服务器问题导致初始化失败。那么,当失败以后,该什么时候再次进行初始化呢?
小米推送的Demo里并没有相关措施解决这个问题
解决方案:在初始化失败的情况下提供重试机制,直到初始化成功(可以通过检测是否已经拿到推送token来确定),问题解决的逻辑如下:
解决逻辑
具体代码在这里就不作过多描述,如果你希望获得含注册重试机制的小米推送源代码,请在评论留下你的邮箱,我将亲自发送到你的邮箱
知识点涵盖:网络数据的检测 & 广播接收器
具体请看我写的另外两篇文章:
Android:BroadcastReceiver广播接收器最全面解析
总结
全面考虑到所有异常问题并恰当地进行处理才能真正体现程序猿的功力,希望大家做撸代码的时候不要只做代码的搬运工,纯粹写代码并不会让你成长,关键在于思考。
6. 总结
相信大家已经非常了解如何在你的Android应用中集成小米推送
接下来,我会继续介绍具体如何在Android中关于推送的消息,请看
接下来,我会继续介绍具体如何在Android应用中集成相应的第三方推送功能(华为推送、极光推送、个推等等),有兴趣可以继续关注Carson_Ho的安卓开发笔记
请点赞!因为你的鼓励是我写作的最大动力!
相关文章阅读
Android开发:最全面、最易懂的Android屏幕适配解决方案
Android开发:Handler异步通信机制全面解析(包含Looper、Message Queue)
Android开发:顶部Tab导航栏实现(TabLayout+ViewPager+Fragment)
Android开发:底部Tab菜单栏实现(FragmentTabHost+ViewPager)
Android开发:XML简介及DOM、SAX、PULL解析对比
作者:Carson_Ho
链接://www.greatytc.com/p/b1134bebc2d4
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。