Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android消息推送:手把手教你集成小米推送(附demo)

Android消息推送:手把手教你集成小米推送(附demo)

編輯:關於Android編程

前言

在Android開發中,消息推送功能的使用非常常見。

推送消息截圖

為了降低開發成本,使用第三方推送是現今較為流行的解決方案。

今天,我將手把手教大家如何在你的應用裡集成小米推送

目錄

目錄

1. 官方Demo解析

首先,我們先對小米官方的推送Demo進行解析。

請先到官網下載官方Demo和SDK說明文檔

1.1 Demo概況

Demo目錄

目錄說明:

DemoApplication類

繼承自Application類,其作用主要是:設置App的ID & Key、注冊推送服務

DemoMessageReceiver類

繼承自BroadcastReceiver,用於接收推送消息並對這些消息進行處理

MainActivity

實現界面按鈕處理 & 設置本地推送方案

TimeIntervalDialog

設置推送的時間間段

接下來,我將對每個類進行詳細分析

1.2 詳細分析

1.2.1 DemoApplication類

繼承自Application類,其作用主要是:

  • 設置App的ID & Key
  • 注冊推送服務

接下來我們通過代碼來看下這兩個功能如何實現:

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();
      }
    }
  }
}

總結:

步驟1:先判斷應用App是否已開啟 - 通過判斷系統裡的進程

通過靜態方法

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

進行推送服務注冊,詳細參數如下:

為了提高注冊率,最好在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.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());
  }

}

總結

根據需要復寫PushMessageReceiver裡對消息的相關處理方法,以下是相關方法的詳情:

相關方法詳情

關於onCommandResult(Context context,MiPushCommandMessage message)

a. 作用:當客戶端向服務器發送注冊push、設置alias、取消注冊alias、訂閱topic、取消訂閱topic等等命令後,從服務器返回結果。

b. 參數說明:

參數說明

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)

1、開發者可以為指定用戶設置別名,然後給這個別名推送消息, 

效果等同於給RegId推送消息,Alias是除Regid(自動生成的)和UserAccount之外的第三個用戶標識

2、開發者可以取消指定用戶的某個別名,服務器就不會給這個別名推送消息了。

//設置別名
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)

  • 開發者可以為指定用戶設置userAccount
  • 開發者可以取消指定用戶的某個userAccount,服務器就不會給這個userAccount推送消息了
//設置
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();
  }
}

總結

  • 使用一個繼承了Dialog類的TimeIntervalDialog類進行推送時間的配置
  • 可進行的配置:設置推送時間(開始 & 結束)、暫停推送時間、恢復推送時間
//設置推送時間(開始 & 結束)
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. 集成小米推送步驟匯總

  • 步驟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包加入到你應用的庫裡

點擊此處進行下載

小米推送SDK

步驟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類文件的

如下圖:

示意圖

步驟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());
    }
  }

}

步驟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:根據需要設置一系列的推送設置,如用戶別名、標簽等等

  • 此處是簡單Demo,所以不作過多的設置
  • 更多設置請回看上方官方Demo解析

運行結果

測試成功結果

好了,客戶端的代碼寫好後,可以去小米官網測試一下消息推送了

步驟1:在小米官網的消息推送裡選擇你創建的應用,然後點擊“推送工具”

點擊推送工具

步驟2:設置推送消息的相關信息

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

設置推送消息 

設置推送消息

推送的結果

消息到達客戶端

測試結果
測試結果:收到的信息

點擊通知欄消息後

4. Demo下載地址  demo

5. 關於對小米推送的思考(問題)

上述說的小米推送看似簡單:初始化推送服務 + 相關推送設置。但是,好的代碼不僅能在正常情況下工作,還應該充分考慮失敗情況。那麼,有什麼樣的失敗情況需要我們考慮呢?

  • 背景:在這個初始化推送服務的過程中,是需要聯系小米推送的服務器來申請reg id(即推送token)。
  • 沖突:初始化過程可能失敗:網絡問題(沒網or網絡信號弱)、服務器問題導致初始化失敗。那麼,當失敗以後,該什麼時候再次進行初始化呢?
  • 解決方案:在初始化失敗的情況下提供重試機制,直到初始化成功(可以通過檢測是否已經拿到推送token來確定),問題解決的邏輯如下:

解決邏輯

總結

全面考慮到所有異常問題並恰當地進行處理才能真正體現程序猿的功力,希望大家做撸代碼的時候不要只做代碼的搬運工,純粹寫代碼並不會讓你成長,關鍵在於思考。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved