推送通知的跳轉(zhuǎn)處理和消息提醒

推送通知的跳轉(zhuǎn)處理和消息提醒

??消息推送功能在App開發(fā)中經(jīng)常用到,用于及時(shí)通知用戶,推送用戶訂閱的相關(guān)的信息。本篇文章并非詳細(xì)介紹如何集成和使用推送,關(guān)于推送相關(guān)知識的介紹,郭神已經(jīng)在慕課網(wǎng)中有相關(guān)的教程,大家如果想要深入研究,可以去觀看郭神的相關(guān)視頻。

效果演示

一、App處于運(yùn)行狀態(tài)下:

1.接收到通知,點(diǎn)擊通知打開對應(yīng)activity的演示:

2.接收到通知,點(diǎn)擊通知傳值并打開對應(yīng)的activity的演示:

二、App進(jìn)程處于銷毀狀態(tài),但是后臺依舊運(yùn)行著推送常駐的service:

1.接收到通知,點(diǎn)擊通知打開對應(yīng)的activity, activity啟動(dòng)流程,SplashActivity -> MainActivity - > 對應(yīng)的activity

2.接收到通知,點(diǎn)擊通知傳值并打開對應(yīng)的activity, activity啟動(dòng)流程,SplashActivity -> MainActivity - > 對應(yīng)的activity

接收到透傳消息后的處理

??目前第三方推送平臺也支持推送自定義消息,也有相應(yīng)的回調(diào)方法,我這里使用的是個(gè)推推送,自己定義一個(gè)類繼承 GTIntentService,并在清單文件中注冊,當(dāng)收到透傳消息時(shí),onReceiveMessageData()方法會進(jìn)行回調(diào),如果你喜歡使用其他的第三方推送平臺,思路也是一樣的,也是在對應(yīng)的回調(diào)方法中進(jìn)行以下處理。這里通過在透傳消息中設(shè)置一個(gè)標(biāo)識,如果是通知類消息,獲取到消息后,自己創(chuàng)建對應(yīng)的通知進(jìn)行顯示。

@Override
public void onReceiveMessageData(Context context, GTTransmitMessage msg) {
    byte[] payload = msg.getPayload();

    String message = new String(payload);
    Log.i(TAG, "onReceiveMessageData: " + message);
    try {
        JSONObject jsonObject = new JSONObject(message);
        int isNotification = jsonObject.optInt(PushConstants.IS_NOTIFICATION);
        if (isNotification == 1) {
            //屬于通知類的透傳消息
            showNotification(context, jsonObject);
        } else {
            //提醒消息
            dealNotifyMessage(context, jsonObject);
        }
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

showNotification()方法是對通知類的透傳消息的處理:

/**
 * 根據(jù)消息內(nèi)容彈出通知框
 *
 * @param context
 * @param jsonObject
 */
private void showNotification(Context context, JSONObject jsonObject) {
    String title = jsonObject.optString(PushConstants.TITLE);
    String content = jsonObject.optString(PushConstants.CONTENT);

    if (TextUtils.isEmpty(title) || TextUtils.isEmpty(content)) {
        return;
    }

    int pageNum = jsonObject.optInt(PushConstants.PAGE_NUMBER);
    String contentId = jsonObject.optString(PushConstants.CONTENT_ID);

    //設(shè)置點(diǎn)擊通知后是發(fā)送廣播,傳遞對應(yīng)的數(shù)據(jù)
    Intent broadcastIntent = new Intent(context, NotificationReceiver.class);
    Bundle bundle = new Bundle();
    bundle.putInt(PushConstants.PAGE_NUMBER, pageNum);
    bundle.putString(PushConstants.CONTENT_ID, contentId);
    broadcastIntent.putExtras(bundle);

    PendingIntent pendingIntent = PendingIntent.
            getBroadcast(context, NotificationUtils.getRandowReqCode(), broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    NotificationUtils.showIntentNotification(context, title, content, title, pendingIntent, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
}

dealNotifyMessage()方法是對提醒類的透傳消息的處理:

/**
 * 處理提醒消息
 *
 * @param context
 * @param jsonObject
 */
private void dealNotifyMessage(final Context context, JSONObject jsonObject) {
    int notifyType = jsonObject.optInt(PushConstants.NOTIFY_TYPE, PushConstants.MESSAGE_CENTER_NOTIFY);
    //判斷提醒信息的類型,做相應(yīng)的UI操作,由于此處處于IntentService中,做UI操作需要進(jìn)行線程的切換,這里使用了handler的post()方法切換
    switch (notifyType) {
        case PushConstants.MESSAGE_CENTER_NOTIFY:
            //消息中心的提醒
            handler.post(new Runnable() {
                public void run() {
                   /* if (MainActivity.instance != null){
                        MainActivity.instance.showTabNotify(2);//底部我的tab顯示提示點(diǎn)
                    }
                    if (MineFragment.ivMessage != null){
                        MineFragment.ivMessage.setImageResource(R.mipmap.img_message_unread);//設(shè)置消息中心圖標(biāo)為未讀的
                    }
                    //更新消息表的未讀數(shù)
                    UnReadDao.saveOrUpdate(UnReadDao.getUnreadCount() + 1);*/

                   Log.i(TAG,"收到消息提醒,顯示小紅點(diǎn)");
                }
            });
            break;
    }
}

通知的點(diǎn)擊處理

??關(guān)于通知的點(diǎn)擊處理,showNotification()在創(chuàng)建通知的時(shí)候,需要設(shè)置PendingIntent:

  //設(shè)置點(diǎn)擊通知后是發(fā)送廣播,傳遞對應(yīng)的數(shù)據(jù)
    Intent broadcastIntent = new Intent(context, NotificationReceiver.class);
    Bundle bundle = new Bundle();
    bundle.putInt(PushConstants.PAGE_NUMBER, pageNum);//所要打開的頁面的編號
    bundle.putString(PushConstants.CONTENT_ID, contentId);//id
    broadcastIntent.putExtras(bundle);

    PendingIntent pendingIntent = PendingIntent.
            getBroadcast(context, NotificationUtils.getRandowReqCode(), broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);

??我們通過PendingIntent.getBroadcast()方法創(chuàng)建PendingIntent,需要傳遞的數(shù)據(jù):pageNum屬于頁面的編號,定義在PushConstants中,用于判斷跳轉(zhuǎn)哪個(gè)頁面,如果是訂單的通知,則contentId則是對應(yīng)訂單的id,用于訂單詳情頁獲取訂單數(shù)據(jù)。

??當(dāng)點(diǎn)擊通知的時(shí)候,將會發(fā)送廣播并傳值給NotificationReceiver,具體的跳轉(zhuǎn)操作交由它進(jìn)行處理,接下來介紹最重要的內(nèi)容。

??NotificationReceiver接收到點(diǎn)擊通知后發(fā)出的廣播,在onReceive()方法中回調(diào),獲取傳過來的數(shù)據(jù)并進(jìn)行相應(yīng)的處理。

@Override
public void onReceive(Context context, Intent intent) {
    Bundle bundle = intent.getExtras();
    int pageNum = bundle.getInt(PushConstants.PAGE_NUMBER, 0);
    String contentId = bundle.getString(PushConstants.CONTENT_ID, "");

    Intent destinationIntent = null;//目標(biāo)intent
    switch (pageNum) {
        case PushConstants.PAGE_ORDER_DETAIL:
            //訂單詳情頁
            destinationIntent = new Intent(context, OrderDetailActivity.class);
            destinationIntent.putExtra(OrderDetailActivity.ORDER_ID, contentId);//傳訂單的id
            break;
        case PushConstants.PAGE_MESSAGE_CENTER:
            //消息中心
            destinationIntent = new Intent(context, MessageCenterActivity.class);
            break;
    }

    if (SystemUtils.isAppAlive(context, context.getPackageName())) {
        //如果存活的話,就直接啟動(dòng)目標(biāo)Activity,但要考慮一種情況,就是app的進(jìn)程雖然仍然在
        //但Task棧已經(jīng)空了,比如用戶點(diǎn)擊Back鍵退出應(yīng)用,但進(jìn)程還沒有被系統(tǒng)回收,如果直接啟動(dòng)
        //目標(biāo)Activity,再按Back鍵就不會返回MainActivity了。所以在啟動(dòng) 目標(biāo)Activity前,要先啟動(dòng)MainActivity。
        //將MainAtivity的launchMode設(shè)置成SingleTask, 或者在下面flag中加上Intent.FLAG_CLEAR_TOP,
        //如果Task棧中有MainActivity的實(shí)例,就會把它移到棧頂,把在它之上的Activity都清理出棧,
        //如果Task棧不存在MainActivity實(shí)例,則在棧頂創(chuàng)建

        Log.i(TAG, "the app process is alive");
        Intent mainIntent = new Intent(context, MainActivity.class);
        mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        if (intentList == null){
            intentList = new ArrayList<Intent>();
        }
        intentList.add(mainIntent);
        //如果目標(biāo)intent不為空,一起打開
        if (destinationIntent != null){
            intentList.add(destinationIntent);
        }
        context.startActivities(intentList.toArray(new Intent[intentList.size()]));
    } else {
        //如果app進(jìn)程已經(jīng)被殺死,先重新啟動(dòng)app,將目標(biāo)Activity的啟動(dòng)參數(shù)傳入Intent中,參數(shù)經(jīng)過
        //SplashActivity傳入MainActivity,此時(shí)app的初始化已經(jīng)完成,在MainActivity中就可以根據(jù)傳入
        // 參數(shù)跳轉(zhuǎn)到目標(biāo)Activity中去了
        Log.i(TAG, "the app process is dead");
        Intent launchIntent = context.getPackageManager().
                getLaunchIntentForPackage(context.getPackageName());
        launchIntent.setFlags(
                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        launchIntent.putExtras(bundle);
        context.startActivity(launchIntent);
    }
}

??獲取到傳過來的數(shù)據(jù),通過pageNum(頁面編號)判斷要打開哪個(gè)activity,如果是訂單詳情頁的activity則需要傳遞一個(gè)contentId(此時(shí)則為訂單的id),作為詳情頁獲取數(shù)據(jù)的一個(gè)參數(shù)。

主要分為兩種情況考慮:

App進(jìn)程存在和App進(jìn)程不存在兩種情況。判斷App進(jìn)程是否存在,可以通過遍歷當(dāng)前手機(jī)系統(tǒng)中的所有運(yùn)行的進(jìn)程,通過判斷運(yùn)行的進(jìn)程的包名是否與當(dāng)前App的包名一致從而知道App進(jìn)程是否存在。

`/**
 * 判斷應(yīng)用是否已經(jīng)啟動(dòng)
 * @param context 一個(gè)context
 * @param packageName 要判斷應(yīng)用的包名
 * @return boolean
 */
public static boolean isAppAlive(Context context, String packageName){
    ActivityManager activityManager =
            (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> processInfos
            = activityManager.getRunningAppProcesses();
    for(int i = 0; i < processInfos.size(); i++){
        if(processInfos.get(i).processName.equals(packageName)){
            Log.i("NotificationLaunch",
                    String.format("the %s is running, isAppAlive return true", packageName));
            return true;
        }
    }
    Log.i("NotificationLaunch",
            String.format("the %s is not running, isAppAlive return false", packageName));
    return false;
}`

??一、當(dāng)APP進(jìn)程存在的時(shí)候,在這種情況下,進(jìn)程雖然存在,但是任務(wù)??赡芤呀?jīng)為空,所在無論MainActivity是否已經(jīng)在棧內(nèi),都要打開MainActivity和目標(biāo)activity,必須注意的是,要將MainActivity的啟動(dòng)模式設(shè)置為SingleTask,即棧內(nèi)復(fù)用并且會清除位于其頂部的所有已經(jīng)開啟的activity,只留下MainActivity(一般App中MainActivity位于棧低)和目標(biāo)activity。

??二、當(dāng)App進(jìn)程已經(jīng)被殺死,點(diǎn)擊通知后啟動(dòng)App,將要傳遞的數(shù)據(jù)通過SplashActivity傳入MainActivity,在MainActivity根據(jù)數(shù)據(jù)判斷要打開的目標(biāo)activity,從而進(jìn)行跳轉(zhuǎn),SplashActivity中,通過判斷getIntent().getExtras()是否為空,如果不為空,則傳遞給MainActivity。

handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            Intent intent = null;
            if (PreUtils.getBoolean(SplashActivity.this, Constants.IS_LOGIN,false)){
                //如果已經(jīng)處于登錄狀態(tài),直接進(jìn)入主界面
                intent = new Intent(SplashActivity.this, MainActivity.class);
                Bundle bundle = getIntent().getExtras();
                if (bundle != null){
                    //如果是App沒開啟,點(diǎn)擊通知打開App,傳遞的bundle就可以到達(dá)MainActivity
                    intent.putExtras(bundle);
                }
            }else{
                //未登錄,跳轉(zhuǎn)登錄界面
                intent = new Intent(SplashActivity.this,LoginActivity.class);
            }
            startActivity(intent);
        }
    },3000);

MainActivity中,做了以下處理:

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

    ...

    jumpToOtherPage();//做相應(yīng)的跳轉(zhuǎn)
}



 /**
 * 如果有接收到傳遞過來的消息,則是點(diǎn)擊通知打開的,做相應(yīng)的跳轉(zhuǎn)
 */
private void jumpToOtherPage() {
    Bundle bundle = getIntent().getExtras();
    if (bundle != null) {
        //如果bundle不為空,則是點(diǎn)擊通知欄打開App進(jìn)來的,獲取傳過來的數(shù)據(jù)
        int pageNum = bundle.getInt(PushConstants.PAGE_NUMBER, 0);
        String id = bundle.getString(PushConstants.CONTENT_ID, "");

        Intent destinationIntent = null;//目標(biāo)intent
        switch (pageNum) {
            case PushConstants.PAGE_ORDER_DETAIL:
                //訂單詳情頁
                destinationIntent = new Intent(this, OrderDetailActivity.class);
                destinationIntent.putExtra(OrderDetailActivity.ORDER_ID, id);//傳對應(yīng)訂單的id
                break;
            case PushConstants.MESSAGE_CENTER_NOTIFY:
                //消息中心頁面
                destinationIntent = new Intent(this, MessageCenterActivity.class);
                break;
        }
        if (destinationIntent != null) {
            startActivity(destinationIntent);
        }
    }
}

??到此為止,關(guān)于App推送通知的處理介紹就結(jié)束了,至于數(shù)據(jù)的定義和相關(guān)頁面跳轉(zhuǎn)的判斷,每個(gè)人有各自的規(guī)則,我這里是通過在PushConstant中定義json對應(yīng)的key的常量以及頁面編號的常量,后臺和App端都定義了相同的常量,同時(shí)封裝好了對應(yīng)的推送工具類,適用于安卓和IOS端,需要提醒的是,IOS需要在個(gè)推管理后臺中配置推送證書。關(guān)于演示的App的demo和后臺的推送demo,大家可以通過下面的github地址進(jìn)行clone,希望可以幫助到大家。

https://github.com/chaychan/GTPushDemo.git(android端)

https://github.com/chaychan/GTPushDemoJava.git(后臺java代碼)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,665評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內(nèi)容