說到 APP 推播,早期真的比較麻煩,不管是對 APP 端還是後台都是很複雜的工作
由於 APP 端,iOS 和 Android 各走各的路,後台要針對 iOS 和 Android 做設置,還要保存管理載具的 Token
才能做到對所有載具廣播訊息,也可以針對會員載具發送私人訊息
Android 部分早期用 GCM,說實在,改用 FCM (Firebase Cloud Messaging) 真的方便多了
而且 iOS 也可以用 FCM ,麻煩事都交給 Firebase,對後台而言真是個好消息
在 Android 這邊超簡單,以下幾個的步驟就搞定了
1. 下載 google-services.json 檔案移到 Android 應用程式的模組根目錄中(就是 app 資料夾下面)
a) 建立一個 Firebase 專案,新增 Android 應用程式,註冊完成後,就可以下載 google-services.json
b) 已有專案和Android 應用程式,就到 [專案設定] 找 Android 應用程式的 [下載最新的設定檔],就可以下載 google-services.json
2. 在模組根目錄中 app/build.gradle 加
apply plugin: 'com.android.application'
android {
// ...
}
dependencies {
// ...
implementation 'com.google.firebase:firebase-messaging:19.0.1'
}
3. 在 app/src/main/AndroidManifest.xml 加
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<!-- Set custom default icon. -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. -->
<!-- 不同的Android版本以不同的方式使用此設置:Android < N 使用此作為圖標的背景顏色。 Android >= N 使用它來為圖標和應用程序名稱著色。 -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent" />
<!-- Set default channel -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id" />
4. 建立 MyFirebaseMessagingService.java
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
//收到 FCM 訊息分為 Notification 和 Data 兩種,取得方式如下
//Data messages
String title = remoteMessage.getData().get("title");
String body = remoteMessage.getData().get("body");
String badge = remoteMessage.getData().get("badge");
int badgeCount = 0;
if (badge.length() > 0 && TextUtils.isDigitsOnly(badge)) {
badgeCount = Integer.parseInt(badge);
}
//Notification messages
//String title = remoteMessage.getNotification().getTitle();
//String body = remoteMessage.getNotification().getBody();
//根據收到 FCM 訊息生成自己的通知
sendNotification(title, body, badgeCount);
}
/**
* Create and show a simple notification containing the received FCM message.
*
* @param messageTitle FCM message Title received.
* @param messageBody FCM message body received.
* @param badgeCount
*/
private void sendNotification(String messageTitle, String messageBody, String badgeCount) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
String channelId = getString(R.string.default_notification_channel_id);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_stat_ic_notification)
.setContentTitle(messageTitle)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)//效果:按下訊息,打開APP
.setNumber(badgeCount);
//設置訊息數量(ShortcutBadger 會在部分廠牌手機的圖示上顯示數字)
ShortcutBadger.applyCount(context, badgeCount); //for 1.1.4+
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//Android 8.0 Oreo 一定要實作 通知頻道(Notification channels)
//Android 7.1或之前的舊版本Android手機中執行,它會以舊的通知方式展示,也就是沒有通知頻道的效果。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
Firebase 官方文件: https://firebase.google.com/docs/cloud-messaging/android/client?authuser=0
完成以上步驟,基本上已經可以收到推播訊息了
值得注意的是
訊息發送端(後台)使用的推播訊息類型分為 Data messages 和 Notification messages 兩種
1. Data messages :
a) 無論 APP 處於 [前台執行] 還是 [背景執行],都會呼叫 onMessageReceived()
b) 傳統的 GCM 就是用這種
2. Notification messages :
a) 若 APP 處於 [前台執行] 才會呼叫 onMessageReceived()
b) 若 APP 處於 [背景執行] 會顯示自動生成的通知。按下訊息,就會打開應用程式(真貼心!)
所以訊息發送端(後台)使用 Notification messages 時,APP 是處於 [背景執行] 還是 [前台執行] 狀態,通知是由不同對象處理的
這時記得去 AndroidManifest.xml 設定 FCM 用的 default icon , color , channel id ,就是跟 onMessageReceived() 設置的一樣就可以囉~
但是問題來了,如果在 onMessageReceived() 自訂訊息顯示樣式不只是 icon , color , channel id 和按下訊息就會打開應用程式這些呢!
例如: 按下訊息後,跳去某個指定畫面或是需要設置 Badge Count ...
這時,訊息發送端(後台)需強迫使用 Data messages,也就是不管 APP 是處於什麼狀態,保證呼叫 onMessageReceived() 生成自訂的通知樣式