1. 程式人生 > >是時候來了解android7了:通知直接回復

是時候來了解android7了:通知直接回復

本文已授權微信公眾號:鴻洋(hongyangAndroid)在微信公眾號平臺原創首發。

這是<是時候來了解android7>系列的第三篇文章了, 前面兩篇分別介紹了多視窗模式shortcut功能, 今天我們來點簡單的, 說一說通知直接回復功能. 可能很多朋友還沒有機會接觸到android7的新特性, 所以在開始之前,先來介紹一下什麼是通知直接回復, 拿簡訊應用來說吧, 在之前我們接收到一條新簡訊是會有一個通知提醒的, 不過假如我們想要回復該簡訊就要點選簡訊應用或者點選通知進入到簡訊內容裡才可以, 甚是麻煩. 從android7開始, 我們不用這麼麻煩了, 可以直接在通知裡進行回覆了!好像iOS和一些國產的ROM早就有了這項功能, 不過在原生Android裡這是第一次, 這個特性既方便了使用者, 同時也方便了我們開發者. 來張圖感受一下.

這就是我們今天要完成的一個小demo, 先來說一下這個demo的流程, 首先, 我們點選”發通知”會模擬發出一個簡訊通知, 然後當我們編輯完回覆內容點擊發送的時候, 會啟動一個service來模擬傳送簡訊傳送過程, 這個模擬過程首先會有一個延遲, 延遲後繼續傳送一個”傳送成功”的通知, 最後將通知取消掉.

流程很簡單, 整個都是模擬的過程, 最主要的是要學習一個直接回復這項新功能.

那重點來了? 如何傳送一個帶有直接回復功能的通知呢? 下面再來整理一下發送這樣的一個通知的流程:

  1. 第一步, 我們需要建立一個RemoteInput
  2. 第二步, 建立一個PendingIntent, 這個PendingIntent指當我們點選”傳送”的時候呼叫什麼
  3. 第三步, 建立一個直接回復的Action
  4. 第四步, 建立notification
  5. 第五步, 傳送通知

一共5個步驟我們就可以建立一個帶有”直接回復”功能的通知了, 而且這5步裡2,4,5應該是我們熟悉的程式碼, 下面我們就來一步步的完成程式碼.

首先, 建立RemoteInput

RemoteInput remoteInput = new RemoteInput.Builder(RESULT_KEY)
        .setLabel("回覆這條訊息")
        .build();

很簡單的一個builder, 首先Builder的構造我們需要一個String型別的key, 這個key是幹嘛用的? 其實就是我們方便在處理回覆的時候拿內容的. 其次一個setLabel

方法, 可以對照著上面的圖來看看這是哪一部分的內容, 說白了, 這其實就是一個EditTextHint值.

接下來繼續第二步, 建立一個PendingIntent, 這個PendingIntent在這裡的作用是啟動一個service,所以程式碼是這樣的:

Intent intent = new Intent(this, SendMsgService.class);
PendingIntent pi = PendingIntent.getService(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

都是大家熟悉的程式碼, 我們接著來看第三步, 建立一個直接回復的Action

NotificationCompat.Action act = new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, "回覆", pi)
        .addRemoteInput(remoteInput).build();

又是一個Builder, 這個Builder的構造中有三個引數, 第一個引數是一個logo, 搞過通知的朋友肯定對通知的logo都很熟悉了, 第二個引數是這個Action的標籤, 對應上面demo中我們要點選的那個按鈕, 第三個引數是當我們點選”回覆”的時候要幹嘛. 接下來一個addRemoteInput方法將上面我們建立的RemoteInput傳遞進來.

第四步, 建立一個notification, 這個過程中大家都知道也是一個builder, 不過這個builder中肯定有我們不熟悉的方法, 要們上面的Action怎麼設定呢?

NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
        .setSmallIcon(R.mipmap.ic_launcher)
        .setContentTitle("請問是否需要信用卡?")
        .setContentText("您好,我是XX銀行的XX經理, 請問你需要辦理信用卡嗎?")
        .setColor(Color.CYAN)
        .addAction(act)
        .setCategory(Notification.CATEGORY_MESSAGE);

從上往下一個個的來, 略…略…略…, setColor方法的作用是設定一個accent顏色, 對應上面的demo就是那個”回覆”和點選”回覆”後輸入框的背景顏色. addAction方法就是將我們上面建立的Action設定進來, setCategory是指定通知的型別, 這裡我們指定為訊息型別.

最後一步, 傳送通知

NotificationManager nm = getSystemService(NotificationManager.class);
nm.notify(NOTIFICATION_ID, builder.build());

沒撒好說的, 就這樣簡單的幾步, 一個具有”直接回復”功能的通知就發出來了, 不過還沒完, 雖然通知出來了, 但是使用者回覆的內容我們還沒處理. 這些邏輯的處理我們放到上面提到的那個service裡執行.

那這個處理流程是怎樣的呢? 還是先來羅列下流程.

  1. 拿到使用者輸入的內容
  2. 模擬傳送的延遲
  3. 模擬傳送成功, 取消通知

再次一步步的跟程式碼, 首先我們要拿到使用者輸入的內容, 我們可以通過RemoteInput的一個靜態方法getResultsFromIntent直接拿到一個Bundle, 然後我們就可以根據上面構建RemoteInput的時候使用的key來拿到內容了.

Bundle replyBundle = RemoteInput.getResultsFromIntent(intent);
if (replyBundle != null) {
    // 根據key拿到回覆的內容
    String reply = replyBundle.getString(MainActivity.RESULT_KEY);
    reply(reply);
}

拿到內容後, 我們就來模擬回覆了, 這個操作是在reply方法中完成的.

private void reply(final String reply) {
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            Log.d("reply", "reply: " + reply);
            onReply();
        }
    }, 1000);
}
}

這裡我們延遲1000ms後表示回覆成功, 然後呼叫onReply方法.

private void onReply() {
    final NotificationManager nm = getSystemService(NotificationManager.class);
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            // 更新通知為“回覆成功”
            Notification notification = new NotificationCompat.Builder(SendMsgService.this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentText("回覆成功")
                    .build();
            nm.notify(MainActivity.NOTIFICATION_ID, notification);
        }
    });

    // 最後將通知取消
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            nm.cancel(MainActivity.NOTIFICATION_ID);
        }
    }, 2000);
}

onReply裡我們就來幹剩下的事了, 包括髮送一個”傳送成功”的訊息,然後延遲取消通知.

程式碼很簡單, 主要的是建立直接回復的通知如何拿到使用者輸入的內容, 如果大家的APP中有這樣的需求, 可以考慮在適配Android7的時候加入直接回復的功能.

最後來一個題外話, 從Android5開始, 其實Android還提供了一個懸浮式通知的功能, 這個懸浮式通知其實也很簡單, 只需要在構建Notification的時候使用setFullScreenIntent(PendingIntent pi, boolean highPriority)即可實現, 現在Android7最新的簡訊應用就是結合了懸浮式通知直接回復的功能, 不過我自己在實現的時候還是遇到了一些問題, 例如: 如何控制懸浮式通知的消失, 如何控制懸浮式通知消失後發出一個普通通知, 這兩個問題我的做法是發出一個懸浮式通知後, 使用Handler延遲傳送一個普通通知, 但這樣還是有一個問題, 在懸浮式通知進行直接回復時, 通知可能就已經被取消了, 這裡我還沒有找到google簡訊原始碼看它是怎麼處理的, 如果大家有知道原生訊息是怎麼處理的或者從哪可以找到google原生簡訊應用的原始碼可以在下面給我留言, 謝謝~

最近給出我的demo原始碼: https://github.com/qibin0506/N_notification_quick_reply