使用Firebase云消息傳遞FCM和PHP的Android推送通知
最近,谷歌從谷歌云消息傳遞(GCM)遷移到Firebase云消息傳遞(FCM)。就像GCM一樣,F(xiàn)CM是一種跨平臺(tái)的消息傳遞解決方案,允許您發(fā)送消息。FCM是完全免費(fèi)的,沒(méi)有任何限制。
如果您已按照我之前關(guān)于GCM的任何教程進(jìn)行操作,我強(qiáng)烈建議您立即遷移到Firebase。在本文中,我們通過(guò)構(gòu)建一個(gè)簡(jiǎn)單的應(yīng)用程序來(lái)了解firebase云消息的功能。我們還將學(xué)習(xí)如何將firebase集成到您的后端,以便您可以從服務(wù)器發(fā)送消息。
1. Firebase消息類型
使用Firebase Cloud Messaging,您可以發(fā)送三種類型的消息,即通知消息,數(shù)據(jù)消息和包含通知和數(shù)據(jù)有效負(fù)載的消息。
1.1通知消息:
通知消息由firebase SDK本身處理。通常,通知消息包含標(biāo)題,消息,圖標(biāo)等。這些消息可以從firebase控制臺(tái)UI?發(fā)送。通過(guò)發(fā)送此類消息,您將無(wú)法控制通知。當(dāng)應(yīng)用程序處于后臺(tái)時(shí),通知將自動(dòng)顯示。
要發(fā)送通知消息,您需要在json數(shù)據(jù)中使用通知密鑰。下面給出了通知消息的示例。
{
????"to": "e1w6hEbZn-8:APA91bEUIb2JewYCIiApsMu5JfI5Ak...",
????"notification": {
????????"body": "Cool offers. Get them before expiring!",
????????"title": "Flat 80% discount",
????????"icon": "appicon"
????}
}
1.2數(shù)據(jù)信息:
數(shù)據(jù)消息必須由Android應(yīng)用程序處理。如果要與通知一起發(fā)送一些其他數(shù)據(jù),可以添加此類消息。但是無(wú)法通過(guò)firebase控制臺(tái)發(fā)送這些消息。您需要具有服務(wù)器端邏輯才能使用Firebase API發(fā)送通知。發(fā)送此消息時(shí)需要使用數(shù)據(jù)密鑰。
下面給出了數(shù)據(jù)消息json的示例。
{
???"to": "e1w6hEbZn-8:APA91bEUIb2JewYCIiApsMu5JfI5Ak...",
???"data": {
?????"name": "LG LED TV S15",
?????"product_id": "123",
?????"final_price": "2500"
???}
?}
1.3包含通知和數(shù)據(jù)有效負(fù)載的消息:
消息還可以包含通知和數(shù)據(jù)有效負(fù)載。發(fā)送這些消息時(shí),將根據(jù)應(yīng)用程序狀態(tài)(后臺(tái)/前臺(tái))在兩種情況下處理。對(duì)于這些消息,我們可以使用通知和數(shù)據(jù)密鑰。
在后臺(tái)- 應(yīng)用程序在通知托盤中接收通知有效負(fù)載,并僅在用戶點(diǎn)擊通知時(shí)處理數(shù)據(jù)有效負(fù)載。
在前臺(tái)時(shí)- 應(yīng)用程序收到兩個(gè)有效負(fù)載可用的消息對(duì)象。
通知和數(shù)據(jù)有效負(fù)載消息的示例將是
{
????"to": "e1w6hEbZn-8:APA91bEUIb2JewYCIiApsMu5JfI5Ak...",
????"notification": {
????????"body": "Cool offers. Get them before expiring!",
????????"title": "Flat 80% discount",
????????"icon": "appicon"
????},
????"data": {
?????"name": "LG LED TV S15",
?????"product_id": "123",
?????"final_price": "2500"
???}
}
2.消息定位
使用firebase發(fā)送消息時(shí),您可以選擇目標(biāo)受眾。您可以使用主題名稱向單個(gè)用戶或用戶組發(fā)送。
2.1發(fā)送給單個(gè)用戶
當(dāng)單個(gè)用戶定位時(shí),firebase注冊(cè)ID用于標(biāo)識(shí)設(shè)備。該REG ID在被提及到申請(qǐng)JSON的。
{
??"to": "e1w6hEbZn-8:APA91bEUIb2JewYCIiApsMu5JfI5Ak...",
??"data": {
????"message": "This is a Firebase Cloud Messaging Topic Message!",
???}
}
2.2主題消息
當(dāng)針對(duì)消息傳遞的用戶部分時(shí),主題消息傳遞非常有用。為此,所有用戶都必須訂閱firebase主題。例如:當(dāng)您要向所有參與新聞的用戶發(fā)送消息時(shí),您可以創(chuàng)建一個(gè)名為news的主題并向新聞主題發(fā)送通知。
主題消息的請(qǐng)求格式如下。在對(duì)申請(qǐng)你需要提及的主題名稱。
{
??"to": "/topics/news",
??"data": {
????"message": "This is a Firebase Cloud Messaging Topic Message!",
???}
}
3.集成Firebase云消息傳遞
我希望上面的信息能夠很好地概述firebase功能及其提供的選項(xiàng)。現(xiàn)在我們將創(chuàng)建一個(gè)簡(jiǎn)單的應(yīng)用程序,它從firebase控制臺(tái)和PHP代碼接收f(shuō)irebase消息。
1。您需要做的第一件事是訪問(wèn)https://firebase.google.com/并創(chuàng)建一個(gè)帳戶以訪問(wèn)其控制臺(tái)。獲得對(duì)控制臺(tái)的訪問(wèn)權(quán)限后,您可以先創(chuàng)建第一個(gè)項(xiàng)目。
2。提供項(xiàng)目的包名稱(我的是info.androidhive.firebasenotifications),您將在其中集成Firebase。在您按添加應(yīng)用按鈕時(shí),將下載google-services.json文件。
3。從File?NewProject在Android Studio中創(chuàng)建一個(gè)新項(xiàng)目。在填寫(xiě)項(xiàng)目詳細(xì)信息時(shí),請(qǐng)使用您在firebase控制臺(tái)中提供的相同包名稱。在我的情況下,我使用相同的info.androidhive.firebasenotifications。
4。將google-services.json文件粘貼到項(xiàng)目的app文件夾中。此步驟非常重要,因?yàn)闆](méi)有此文件,您的項(xiàng)目將無(wú)法構(gòu)建。
5。現(xiàn)在打開(kāi)位于項(xiàng)目主目錄中的build.gradle并添加firebase依賴項(xiàng)。
的build.gradle
dependencies {
????????classpath 'com.android.tools.build:gradle:2.2.0-rc1'
????????classpath 'com.google.gms:google-services:3.0.0'
????????// NOTE: Do not place your application dependencies here; they belong
????????// in the individual module build.gradle files
????}
6。打開(kāi)app / build.gradle并添加firebase?消息傳遞依賴項(xiàng)。在文件的最底部,添加apply plugin:'com.google.gms.google-services'
應(yīng)用程序/的build.gradle
dependencies {
????compile 'com.google.firebase:firebase-messaging:9.6.0'
}
apply plugin: 'com.google.gms.google-services'
7。在項(xiàng)目文件夾下創(chuàng)建三個(gè)名為activity,app,service和utils的包。以下是此項(xiàng)目所需的結(jié)構(gòu)和文件。
8。下載notification.mp3并將其放在res?原始文件夾中。此步驟是可選的,但是如果您希望在收到通知時(shí)播放自定義通知聲音。
9。在apppackage?下創(chuàng)建一個(gè)名為Config.java的類。此類包含我們?cè)谡麄€(gè)應(yīng)用中使用的所有常量值。
Config.java
packageinfo.androidhive.firebasenotifications.app;
publicclassConfig {
????// global topic to receive app wide push notifications
????publicstaticfinalString TOPIC_GLOBAL = "global";
????// broadcast receiver intent filters
????publicstaticfinalString REGISTRATION_COMPLETE = "registrationComplete";
????publicstaticfinalString PUSH_NOTIFICATION = "pushNotification";
????// id to handle the notification in the notification tray
????publicstaticfinalintNOTIFICATION_ID = 100;
????publicstaticfinalintNOTIFICATION_ID_BIG_IMAGE = 101;
????publicstaticfinalString SHARED_PREF = "ah_firebase";
}
10。在utils包下創(chuàng)建一個(gè)名為NotificationUtils.java的類。此類包含在通知欄中顯示消息(帶有標(biāo)題,消息,圖像和時(shí)間戳)所需的必要功能。
NotificationUtils.java
packageinfo.androidhive.firebasenotifications.util;
importandroid.app.ActivityManager;
importandroid.app.Notification;
importandroid.app.NotificationManager;
importandroid.app.PendingIntent;
importandroid.content.ComponentName;
importandroid.content.ContentResolver;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.graphics.Bitmap;
importandroid.graphics.BitmapFactory;
importandroid.media.Ringtone;
importandroid.media.RingtoneManager;
importandroid.net.Uri;
importandroid.os.Build;
importandroid.support.v4.app.NotificationCompat;
importandroid.text.Html;
importandroid.text.TextUtils;
importandroid.util.Patterns;
importjava.io.IOException;
importjava.io.InputStream;
importjava.net.HttpURLConnection;
importjava.net.URL;
importjava.text.ParseException;
importjava.text.SimpleDateFormat;
importjava.util.Date;
importjava.util.List;
importinfo.androidhive.firebasenotifications.R;
importinfo.androidhive.firebasenotifications.app.Config;
/**
?* Created by Ravi on 31/03/15.
?*/
publicclassNotificationUtils {
????privatestaticString TAG = NotificationUtils.class.getSimpleName();
????privateContext mContext;
????publicNotificationUtils(Context mContext) {
????????this.mContext = mContext;
????}
????publicvoidshowNotificationMessage(String title, String message, String timeStamp, Intent intent) {
????????showNotificationMessage(title, message, timeStamp, intent, null);
????}
????publicvoidshowNotificationMessage(finalString title, finalString message, finalString timeStamp, Intent intent, String imageUrl) {
????????// Check for empty push message
????????if(TextUtils.isEmpty(message))
????????????return;
????????// notification icon
????????finalinticon = R.mipmap.ic_launcher;
????????intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
????????finalPendingIntent resultPendingIntent =
????????????????PendingIntent.getActivity(
????????????????????????mContext,
????????????????????????0,
????????????????????????intent,
????????????????????????PendingIntent.FLAG_CANCEL_CURRENT
????????????????);
????????finalNotificationCompat.Builder mBuilder = newNotificationCompat.Builder(
????????????????mContext);
????????finalUri alarmSound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE
????????????????+ "://"+ mContext.getPackageName() + "/raw/notification");
????????if(!TextUtils.isEmpty(imageUrl)) {
????????????if(imageUrl != null&& imageUrl.length() > 4&& Patterns.WEB_URL.matcher(imageUrl).matches()) {
????????????????Bitmap bitmap = getBitmapFromURL(imageUrl);
????????????????if(bitmap != null) {
????????????????????showBigNotification(bitmap, mBuilder, icon, title, message, timeStamp, resultPendingIntent, alarmSound);
????????????????} else{
????????????????????showSmallNotification(mBuilder, icon, title, message, timeStamp, resultPendingIntent, alarmSound);
????????????????}
????????????}
????????} else{
????????????showSmallNotification(mBuilder, icon, title, message, timeStamp, resultPendingIntent, alarmSound);
????????????playNotificationSound();
????????}
????}
????privatevoidshowSmallNotification(NotificationCompat.Builder mBuilder, inticon, String title, String message, String timeStamp, PendingIntent resultPendingIntent, Uri alarmSound) {
????????NotificationCompat.InboxStyle inboxStyle = newNotificationCompat.InboxStyle();
????????inboxStyle.addLine(message);
????????Notification notification;
????????notification = mBuilder.setSmallIcon(icon).setTicker(title).setWhen(0)
????????????????.setAutoCancel(true)
????????????????.setContentTitle(title)
????????????????.setContentIntent(resultPendingIntent)
????????????????.setSound(alarmSound)
????????????????.setStyle(inboxStyle)
????????????????.setWhen(getTimeMilliSec(timeStamp))
????????????????.setSmallIcon(R.mipmap.ic_launcher)
????????????????.setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), icon))
????????????????.setContentText(message)
????????????????.build();
????????NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
????????notificationManager.notify(Config.NOTIFICATION_ID, notification);
????}
????privatevoidshowBigNotification(Bitmap bitmap, NotificationCompat.Builder mBuilder, inticon, String title, String message, String timeStamp, PendingIntent resultPendingIntent, Uri alarmSound) {
????????NotificationCompat.BigPictureStyle bigPictureStyle = newNotificationCompat.BigPictureStyle();
????????bigPictureStyle.setBigContentTitle(title);
????????bigPictureStyle.setSummaryText(Html.fromHtml(message).toString());
????????bigPictureStyle.bigPicture(bitmap);
????????Notification notification;
????????notification = mBuilder.setSmallIcon(icon).setTicker(title).setWhen(0)
????????????????.setAutoCancel(true)
????????????????.setContentTitle(title)
????????????????.setContentIntent(resultPendingIntent)
????????????????.setSound(alarmSound)
????????????????.setStyle(bigPictureStyle)
????????????????.setWhen(getTimeMilliSec(timeStamp))
????????????????.setSmallIcon(R.mipmap.ic_launcher)
????????????????.setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), icon))
????????????????.setContentText(message)
????????????????.build();
????????NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
????????notificationManager.notify(Config.NOTIFICATION_ID_BIG_IMAGE, notification);
????}
????/**
?????* Downloading push notification image before displaying it in
?????* the notification tray
?????*/
????publicBitmap getBitmapFromURL(String strURL) {
????????try{
????????????URL url = newURL(strURL);
????????????HttpURLConnection connection = (HttpURLConnection) url.openConnection();
????????????connection.setDoInput(true);
????????????connection.connect();
????????????InputStream input = connection.getInputStream();
????????????Bitmap myBitmap = BitmapFactory.decodeStream(input);
????????????returnmyBitmap;
????????} catch(IOException e) {
????????????e.printStackTrace();
????????????returnnull;
????????}
????}
????// Playing notification sound
????publicvoidplayNotificationSound() {
????????try{
????????????Uri alarmSound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE
????????????????????+ "://"+ mContext.getPackageName() + "/raw/notification");
????????????Ringtone r = RingtoneManager.getRingtone(mContext, alarmSound);
????????????r.play();
????????} catch(Exception e) {
????????????e.printStackTrace();
????????}
????}
????/**
?????* Method checks if the app is in background or not
?????*/
????publicstaticbooleanisAppIsInBackground(Context context) {
????????booleanisInBackground = true;
????????ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
????????if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
????????????List runningProcesses = am.getRunningAppProcesses();
????????????for(ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
????????????????if(processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
????????????????????for(String activeProcess : processInfo.pkgList) {
????????????????????????if(activeProcess.equals(context.getPackageName())) {
????????????????????????????isInBackground = false;
????????????????????????}
????????????????????}
????????????????}
????????????}
????????} else{
????????????List taskInfo = am.getRunningTasks(1);
????????????ComponentName componentInfo = taskInfo.get(0).topActivity;
????????????if(componentInfo.getPackageName().equals(context.getPackageName())) {
????????????????isInBackground = false;
????????????}
????????}
????????returnisInBackground;
????}
????// Clears notification tray messages
????publicstaticvoidclearNotifications(Context context) {
????????NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
????????notificationManager.cancelAll();
????}
????publicstaticlonggetTimeMilliSec(String timeStamp) {
????????SimpleDateFormat format = newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");
????????try{
????????????Date date = format.parse(timeStamp);
????????????returndate.getTime();
????????} catch(ParseException e) {
????????????e.printStackTrace();
????????}
????????return0;
????}
}
11。在服務(wù)包下創(chuàng)建一個(gè)名為MyFirebaseInstanceIDService.java的類。此類接收f(shuō)irebase注冊(cè)ID,該ID對(duì)于每個(gè)應(yīng)用程序都是唯一的。要將消息發(fā)送到單個(gè)設(shè)備時(shí),需要此注冊(cè)ID。您可以將此令牌發(fā)送到您的服務(wù)器應(yīng)用程序,以便稍后向設(shè)備發(fā)送通知。
只要firebase注冊(cè)ID發(fā)生更改,就會(huì)調(diào)用onTokenRefresh()方法。
storeRegIdInPref()將注冊(cè)ID存儲(chǔ)在共享首選項(xiàng)中。
LocalBroadcastManager- 廣播管理器將reg id廣播到正在偵聽(tīng)的所有活動(dòng)。
MyFirebaseInstanceIDService.java
packageinfo.androidhive.firebasenotifications.service;
importandroid.content.Intent;
importandroid.content.SharedPreferences;
importandroid.support.v4.content.LocalBroadcastManager;
importandroid.util.Log;
importcom.google.firebase.iid.FirebaseInstanceId;
importcom.google.firebase.iid.FirebaseInstanceIdService;
importinfo.androidhive.firebasenotifications.app.Config;
/**
?* Created by Ravi Tamada on 08/08/16.
?* www.androidhive.info
?*/
publicclassMyFirebaseInstanceIDService extendsFirebaseInstanceIdService {
????privatestaticfinalString TAG = MyFirebaseInstanceIDService.class.getSimpleName();
????@Override
????publicvoidonTokenRefresh() {
????????super.onTokenRefresh();
????????String refreshedToken = FirebaseInstanceId.getInstance().getToken();
????????// Saving reg id to shared preferences
????????storeRegIdInPref(refreshedToken);
????????// sending reg id to your server
????????sendRegistrationToServer(refreshedToken);
????????// Notify UI that registration has completed, so the progress indicator can be hidden.
????????Intent registrationComplete = newIntent(Config.REGISTRATION_COMPLETE);
????????registrationComplete.putExtra("token", refreshedToken);
????????LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
????}
????privatevoidsendRegistrationToServer(finalString token) {
????????// sending gcm token to server
????????Log.e(TAG, "sendRegistrationToServer: "+ token);
????}
????privatevoidstoreRegIdInPref(String token) {
????????SharedPreferences pref = getApplicationContext().getSharedPreferences(Config.SHARED_PREF, 0);
????????SharedPreferences.Editor editor = pref.edit();
????????editor.putString("regId", token);
????????editor.commit();
????}
}
12。在servicepackage?下創(chuàng)建另一個(gè)名為MyFirebaseMessagingService.java的類。此類將firebase消息接收到onMessageReceived()方法中。
>當(dāng)通知被發(fā)送的消息類型,火力自動(dòng)顯示該通知時(shí),應(yīng)用程序在背景。如果應(yīng)用程序位于前臺(tái),handleNotification()方法將處理通知消息。
>當(dāng)數(shù)據(jù)被發(fā)送的消息類型,handleDataMessage()方法用于不論應(yīng)用程式狀態(tài)(前景/背景)的處理的有效載荷。
>LocalBroadcastManager用于將消息廣播到為廣播接收器注冊(cè)的所有活動(dòng)。
MyFirebaseMessagingService.java
packageinfo.androidhive.firebasenotifications.service;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.support.v4.content.LocalBroadcastManager;
importandroid.text.TextUtils;
importandroid.util.Log;
importcom.google.firebase.messaging.FirebaseMessagingService;
importcom.google.firebase.messaging.RemoteMessage;
importorg.json.JSONException;
importorg.json.JSONObject;
importinfo.androidhive.firebasenotifications.activity.MainActivity;
importinfo.androidhive.firebasenotifications.app.Config;
importinfo.androidhive.firebasenotifications.util.NotificationUtils;
/**
?* Created by Ravi Tamada on 08/08/16.
?* www.androidhive.info
?*/
publicclassMyFirebaseMessagingService extendsFirebaseMessagingService {
????privatestaticfinalString TAG = MyFirebaseMessagingService.class.getSimpleName();
????privateNotificationUtils notificationUtils;
????@Override
????publicvoidonMessageReceived(RemoteMessage remoteMessage) {
????????Log.e(TAG, "From: "+ remoteMessage.getFrom());
????????if(remoteMessage == null)
????????????return;
????????// Check if message contains a notification payload.
????????if(remoteMessage.getNotification() != null) {
????????????Log.e(TAG, "Notification Body: "+ remoteMessage.getNotification().getBody());
????????????handleNotification(remoteMessage.getNotification().getBody());
????????}
????????// Check if message contains a data payload.
????????if(remoteMessage.getData().size() > 0) {
????????????Log.e(TAG, "Data Payload: "+ remoteMessage.getData().toString());
????????????try{
????????????????JSONObject json = newJSONObject(remoteMessage.getData().toString());
????????????????handleDataMessage(json);
????????????} catch(Exception e) {
????????????????Log.e(TAG, "Exception: "+ e.getMessage());
????????????}
????????}
????}
????privatevoidhandleNotification(String message) {
????????if(!NotificationUtils.isAppIsInBackground(getApplicationContext())) {
????????????// app is in foreground, broadcast the push message
????????????Intent pushNotification = newIntent(Config.PUSH_NOTIFICATION);
????????????pushNotification.putExtra("message", message);
????????????LocalBroadcastManager.getInstance(this).sendBroadcast(pushNotification);
????????????// play notification sound
????????????NotificationUtils notificationUtils = newNotificationUtils(getApplicationContext());
????????????notificationUtils.playNotificationSound();
????????}else{
????????????// If the app is in background, firebase itself handles the notification
????????}
????}
????privatevoidhandleDataMessage(JSONObject json) {
????????Log.e(TAG, "push json: "+ json.toString());
????????try{
????????????JSONObject data = json.getJSONObject("data");
????????????String title = data.getString("title");
????????????String message = data.getString("message");
????????????booleanisBackground = data.getBoolean("is_background");
????????????String imageUrl = data.getString("image");
????????????String timestamp = data.getString("timestamp");
????????????JSONObject payload = data.getJSONObject("payload");
????????????Log.e(TAG, "title: "+ title);
????????????Log.e(TAG, "message: "+ message);
????????????Log.e(TAG, "isBackground: "+ isBackground);
????????????Log.e(TAG, "payload: "+ payload.toString());
????????????Log.e(TAG, "imageUrl: "+ imageUrl);
????????????Log.e(TAG, "timestamp: "+ timestamp);
????????????if(!NotificationUtils.isAppIsInBackground(getApplicationContext())) {
????????????????// app is in foreground, broadcast the push message
????????????????Intent pushNotification = newIntent(Config.PUSH_NOTIFICATION);
????????????????pushNotification.putExtra("message", message);
????????????????LocalBroadcastManager.getInstance(this).sendBroadcast(pushNotification);
????????????????// play notification sound
????????????????NotificationUtils notificationUtils = newNotificationUtils(getApplicationContext());
????????????????notificationUtils.playNotificationSound();
????????????} else{
????????????????// app is in background, show the notification in notification tray
????????????????Intent resultIntent = newIntent(getApplicationContext(), MainActivity.class);
????????????????resultIntent.putExtra("message", message);
????????????????// check for image attachment
????????????????if(TextUtils.isEmpty(imageUrl)) {
????????????????????showNotificationMessage(getApplicationContext(), title, message, timestamp, resultIntent);
????????????????} else{
????????????????????// image is present, show notification with image
????????????????????showNotificationMessageWithBigImage(getApplicationContext(), title, message, timestamp, resultIntent, imageUrl);
????????????????}
????????????}
????????} catch(JSONException e) {
????????????Log.e(TAG, "Json Exception: "+ e.getMessage());
????????} catch(Exception e) {
????????????Log.e(TAG, "Exception: "+ e.getMessage());
????????}
????}
????/**
?????* Showing notification with text only
?????*/
????privatevoidshowNotificationMessage(Context context, String title, String message, String timeStamp, Intent intent) {
????????notificationUtils = newNotificationUtils(context);
????????intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
????????notificationUtils.showNotificationMessage(title, message, timeStamp, intent);
????}
????/**
?????* Showing notification with text and image
?????*/
????privatevoidshowNotificationMessageWithBigImage(Context context, String title, String message, String timeStamp, Intent intent, String imageUrl) {
????????notificationUtils = newNotificationUtils(context);
????????intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
????????notificationUtils.showNotificationMessage(title, message, timeStamp, intent, imageUrl);
????}
}
13。打開(kāi)AndroidManifest.xml并添加兩個(gè)firebase服務(wù)MyFirebaseMessagingService和MyFirebaseInstanceIDService。
AndroidManifest.xml中
http://schemas.android.com/apk/res/android"
????package="info.androidhive.firebasenotifications">
????????android:allowBackup="true"
????????android:icon="@mipmap/ic_launcher"
????????android:label="@string/app_name"
????????android:supportsRtl="true"
????????android:theme="@style/AppTheme">
????????????android:name=".activity.MainActivity"
????????????android:label="@string/title_main_activity">
14。最后,我們需要修改我們的主要活動(dòng),以在屏幕上顯示傳入的消息。打開(kāi)主活動(dòng)activity_main.xml的布局文件,修改布局如下。
activity_main.xml中
http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
????android:id="@+id/activity_main"
????android:layout_width="match_parent"
????android:layout_height="match_parent"
????android:paddingBottom="@dimen/activity_vertical_margin"
????android:paddingLeft="@dimen/activity_horizontal_margin"
????android:paddingRight="@dimen/activity_horizontal_margin"
????android:paddingTop="@dimen/activity_vertical_margin"
????tools:context="info.androidhive.firebasenotifications.activity.MainActivity">
????????android:id="@+id/txt_push_message"
????????android:layout_width="wrap_content"
????????android:layout_height="wrap_content"
????????android:layout_alignParentTop="true"
????????android:layout_centerHorizontal="true"
????????android:layout_marginTop="40dp"
????????android:gravity="center_horizontal"
????????android:textColor="@color/colorPrimary"
????????android:textSize="26dp"/>
????????android:id="@+id/txt_reg_id"
????????android:layout_width="wrap_content"
????????android:layout_height="wrap_content"
????????android:layout_alignParentBottom="true"/>
15。打開(kāi)MainActivity.java并執(zhí)行以下必要的更改。在onResume()方法中,我們正在注冊(cè)廣播接收器。這樣活動(dòng)就會(huì)獲得推送消息和注冊(cè)ID。
displayFirebaseRegId()從共享首選項(xiàng)中獲取firebase注冊(cè)ID并將其顯示在屏幕上。這僅供您參考,我們不會(huì)在應(yīng)用程序的任何位置使用reg id。
訂閱主題
如果要訂閱任何主題,可以使用subscribeToTopic()函數(shù)。當(dāng)客戶端應(yīng)用程序訂閱新主題名稱(Firebase項(xiàng)目尚不存在)時(shí),將在FCM中創(chuàng)建該名稱的新主題,并且任何客戶端隨后都可以訂閱該主題。
FirebaseMessaging.getInstance().subscribeToTopic('news');
取消訂閱主題
類似地,客戶端可以通過(guò)調(diào)用unsubscribeFromTopic()方法取消訂閱主題。
FirebaseMessaging.getInstance().unsubscribeFromTopic('news');
MainActivity.java
packageinfo.androidhive.firebasenotifications.activity;
importandroid.content.BroadcastReceiver;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.IntentFilter;
importandroid.content.SharedPreferences;
importandroid.os.Bundle;
importandroid.support.v4.content.LocalBroadcastManager;
importandroid.support.v7.app.AppCompatActivity;
importandroid.text.TextUtils;
importandroid.util.Log;
importandroid.widget.TextView;
importandroid.widget.Toast;
importcom.google.firebase.messaging.FirebaseMessaging;
importinfo.androidhive.firebasenotifications.R;
importinfo.androidhive.firebasenotifications.app.Config;
importinfo.androidhive.firebasenotifications.util.NotificationUtils;
publicclassMainActivity extendsAppCompatActivity {
????privatestaticfinalString TAG = MainActivity.class.getSimpleName();
????privateBroadcastReceiver mRegistrationBroadcastReceiver;
????privateTextView txtRegId, txtMessage;
????@Override
????protectedvoidonCreate(Bundle savedInstanceState) {
????????super.onCreate(savedInstanceState);
????????setContentView(R.layout.activity_main);
????????txtRegId = (TextView) findViewById(R.id.txt_reg_id);
????????txtMessage = (TextView) findViewById(R.id.txt_push_message);
????????mRegistrationBroadcastReceiver = newBroadcastReceiver() {
????????????@Override
????????????publicvoidonReceive(Context context, Intent intent) {
????????????????// checking for type intent filter
????????????????if(intent.getAction().equals(Config.REGISTRATION_COMPLETE)) {
????????????????????// gcm successfully registered
????????????????????// now subscribe to `global` topic to receive app wide notifications
????????????????????FirebaseMessaging.getInstance().subscribeToTopic(Config.TOPIC_GLOBAL);
????????????????????displayFirebaseRegId();
????????????????} elseif(intent.getAction().equals(Config.PUSH_NOTIFICATION)) {
????????????????????// new push notification is received
????????????????????String message = intent.getStringExtra("message");
????????????????????Toast.makeText(getApplicationContext(), "Push notification: "+ message, Toast.LENGTH_LONG).show();
????????????????????txtMessage.setText(message);
????????????????}
????????????}
????????};
????????displayFirebaseRegId();
????}
????// Fetches reg id from shared preferences
????// and displays on the screen
????privatevoiddisplayFirebaseRegId() {
????????SharedPreferences pref = getApplicationContext().getSharedPreferences(Config.SHARED_PREF, 0);
????????String regId = pref.getString("regId", null);
????????Log.e(TAG, "Firebase reg id: "+ regId);
????????if(!TextUtils.isEmpty(regId))
????????????txtRegId.setText("Firebase Reg Id: "+ regId);
????????else
????????????txtRegId.setText("Firebase Reg Id is not received yet!");
????}
????@Override
????protectedvoidonResume() {
????????super.onResume();
????????// register GCM registration complete receiver
????????LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
????????????????newIntentFilter(Config.REGISTRATION_COMPLETE));
????????// register new push message receiver
????????// by doing this, the activity will be notified each time a new message arrives
????????LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
????????????????newIntentFilter(Config.PUSH_NOTIFICATION));
????????// clear the notification area when the app is opened
????????NotificationUtils.clearNotifications(getApplicationContext());
????}
????@Override
????protectedvoidonPause() {
????????LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver);
????????super.onPause();
????}
}
現(xiàn)在我們已經(jīng)完成了firebase云消息的集成。為了驗(yàn)證它,運(yùn)行項(xiàng)目,您應(yīng)該在屏幕上看到firebase reg id。您還可以在LogCat中找到reg id。
4.從Firebase控制臺(tái)發(fā)送消息
現(xiàn)在我們將從firebase控制臺(tái)發(fā)送第一條消息。轉(zhuǎn)到firebase控制臺(tái),然后單擊左側(cè)菜單中的通知。您將獲得一個(gè)界面,您可以在其中鍵入消息,選擇定位并發(fā)送消息。
5.從PHP后端發(fā)送消息
從firebase控制臺(tái)發(fā)送消息并不總是許多應(yīng)用程序的最佳解決方案。大量應(yīng)用程序需要在發(fā)生事件時(shí)自動(dòng)通知用戶,這是使用firebase控制臺(tái)無(wú)法實(shí)現(xiàn)的。要解決此問(wèn)題,您需要從后端服務(wù)器集成firebase API。
讓我們創(chuàng)建一個(gè)簡(jiǎn)單的PHP項(xiàng)目來(lái)從后端發(fā)送消息。我假設(shè)您具有PHP和WAMP的基本知識(shí)。如果您是新手,可以從本文獲得幫助。
5.1獲取Firebase服務(wù)器API密鑰
Firebase提供Server API密鑰以識(shí)別您的firebase應(yīng)用。要獲取服務(wù)器API密鑰,請(qǐng)轉(zhuǎn)到firebase控制臺(tái),選擇項(xiàng)目和轉(zhuǎn)到設(shè)置,選擇“云消息傳遞”選項(xiàng)卡并復(fù)制服務(wù)器密鑰。
1。轉(zhuǎn)到您的WAMP目錄并在htdocs或www中創(chuàng)建名為firebase的新文件夾。
2。創(chuàng)建一個(gè)名為config.php的文件并添加以下代碼。在這里,我們定義了firebase Server API Key,以便向firebase端點(diǎn)發(fā)送請(qǐng)求。
config.php文件
// Firebase API Key
define('FIREBASE_API_KEY', 'AAAA4qJeE5A:APA91bGct--6lGrYwgBC8iz5reyx4qPUB7ByXX8MwC7Vcs8u...');
3。創(chuàng)建一個(gè)名為push.php的文件這個(gè)類準(zhǔn)備和需要發(fā)送到firebase的推送通知json。
push.php
/**
?* @author Ravi Tamada
?* @link URL Tutorial link
?*/
classPush {
????// push message title
????private$title;
????private$message;
????private$image;
????// push message payload
????private$data;
????// flag indicating whether to show the push
????// notification or not
????// this flag will be useful when perform some opertation
????// in background when push is recevied
????private$is_background;
????function__construct() {
????}
????publicfunctionsetTitle($title) {
????????$this->title = $title;
????}
????publicfunctionsetMessage($message) {
????????$this->message = $message;
????}
????publicfunctionsetImage($imageUrl) {
????????$this->image = $imageUrl;
????}
????publicfunctionsetPayload($data) {
????????$this->data = $data;
????}
????publicfunctionsetIsBackground($is_background) {
????????$this->is_background = $is_background;
????}
????publicfunctiongetPush() {
????????$res= array();
????????$res['data']['title'] = $this->title;
????????$res['data']['is_background'] = $this->is_background;
????????$res['data']['message'] = $this->message;
????????$res['data']['image'] = $this->image;
????????$res['data']['payload'] = $this->data;
????????$res['data']['timestamp'] = date('Y-m-d G:i:s');
????????return$res;
????}
}
4。創(chuàng)建一個(gè)名為firebase.php的文件并添加以下代碼。此類包含通過(guò)發(fā)出CURL請(qǐng)求將消息發(fā)送到firebase api的必要函數(shù)。
/**
?* @author Ravi Tamada
?* @link URL Tutorial link
?*/
classFirebase {
????// sending push message to single user by firebase reg id
????publicfunctionsend($to, $message) {
????????$fields= array(
????????????'to'=> $to,
????????????'data'=> $message,
????????);
????????return$this->sendPushNotification($fields);
????}
????// Sending message to a topic by topic name
????publicfunctionsendToTopic($to, $message) {
????????$fields= array(
????????????'to'=> '/topics/'. $to,
????????????'data'=> $message,
????????);
????????return$this->sendPushNotification($fields);
????}
????// sending push message to multiple users by firebase registration ids
????publicfunctionsendMultiple($registration_ids, $message) {
????????$fields= array(
????????????'to'=> $registration_ids,
????????????'data'=> $message,
????????);
????????return$this->sendPushNotification($fields);
????}
????// function makes curl request to firebase servers
????privatefunctionsendPushNotification($fields) {
????????require_once__DIR__ . '/config.php';
????????// Set POST variables
$url= 'https://fcm.googleapis.com/fcm/send';
????????$headers= array(
????????????'Authorization: key='. FIREBASE_API_KEY,
????????????'Content-Type: application/json'
????????);
????????// Open connection
????????$ch= curl_init();
????????// Set the url, number of POST vars, POST data
????????curl_setopt($ch, CURLOPT_URL, $url);
????????curl_setopt($ch, CURLOPT_POST, true);
????????curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
????????curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
????????// Disabling SSL Certificate support temporarly
????????curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
????????curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
????????// Execute post
????????$result= curl_exec($ch);
????????if($result=== FALSE) {
????????????die('Curl failed: '. curl_error($ch));
????????}
????????// Close connection
????????curl_close($ch);
????????return$result;
????}
}
?>
5。最后創(chuàng)建一個(gè)index.php并添加以下代碼。這里我們創(chuàng)建一個(gè)簡(jiǎn)單的UI,它接受輸入并將通知發(fā)送到Android設(shè)備。
的index.php
????????AndroidHive | Firebase Cloud Messaging
????????http://yui.yahooapis.com/pure/0.6.0/pure-min.css">
????????????body{
????????????}
????????????div.container{
????????????????width: 1000px;
????????????????margin: 0 auto;
????????????????position: relative;
????????????}
????????????legend{
????????????????font-size: 30px;
????????????????color: #555;
????????????}
????????????.btn_send{
????????????????background: #00bcd4;
????????????}
????????????label{
????????????????margin:10px 0px !important;
????????????}
????????????textarea{
????????????????resize: none !important;
????????????}
????????????.fl_window{
????????????????width: 400px;
????????????????position: absolute;
????????????????right: 0;
????????????????top:100px;
????????????}
????????????pre, code {
????????????????padding:10px 0px;
????????????????box-sizing:border-box;
????????????????-moz-box-sizing:border-box;
????????????????webkit-box-sizing:border-box;
????????????????display:block;
????????????????white-space: pre-wrap;?
????????????????white-space: -moz-pre-wrap;
????????????????white-space: -pre-wrap;
????????????????white-space: -o-pre-wrap;
????????????????word-wrap: break-word;
????????????????width:100%; overflow-x:auto;
????????????}
????????// Enabling error reporting
????????error_reporting(-1);
????????ini_set('display_errors', 'On');
????????require_once__DIR__ . '/firebase.php';
????????require_once__DIR__ . '/push.php';
????????$firebase= newFirebase();
????????$push= newPush();
????????// optional payload
????????$payload= array();
????????$payload['team'] = 'India';
????????$payload['score'] = '5.6';
????????// notification title
????????$title= isset($_GET['title']) ? $_GET['title'] : '';
????????// notification message
????????$message= isset($_GET['message']) ? $_GET['message'] : '';
????????// push type - single user / topic
????????$push_type= isset($_GET['push_type']) ? $_GET['push_type'] : '';
????????// whether to include to image or not
????????$include_image= isset($_GET['include_image']) ? TRUE : FALSE;
????????$push->setTitle($title);
????????$push->setMessage($message);
????????if($include_image) {
$push->setImage('https://api.androidhive.info/images/minion.jpg');
????????} else{
????????????$push->setImage('');
????????}
????????$push->setIsBackground(FALSE);
????????$push->setPayload($payload);
????????$json= '';
????????$response= '';
????????if($push_type== 'topic') {
????????????$json= $push->getPush();
????????????$response= $firebase->sendToTopic('global', $json);
????????} elseif($push_type== 'individual') {
????????????$json= $push->getPush();
????????????$regId= isset($_GET['regId']) ? $_GET['regId'] : '';
????????????$response= $firebase->send($regId, $json);
????????}
?????????>
Request:
Response:
????????????????????Send to Single Device
????????????????????Firebase Reg Id
????????????????????Title
????????????????????Message
???????????????????????? Include image
????????????????????Send
????????????????????Send to Topic `global`
????????????????????Title
????????????????????Message
???????????????????????? Include image
????????????????????Send to Topic
6。從http:// localhost / firebaseurl?訪問(wèn)項(xiàng)目。(如果您的apache在端口上運(yùn)行,請(qǐng)使用端口號(hào)訪問(wèn)該URL)
6.演示
如果您是PHP新手并且在運(yùn)行上述PHP項(xiàng)目時(shí)遇到任何問(wèn)題,您可以在此處訪問(wèn)同一項(xiàng)目。除了少量更改之外,UI與上面解釋的相同。您需要提供自己的firebase服務(wù)器API密鑰來(lái)測(cè)試您的應(yīng)用程序。查看視頻以了解如何使用演示頁(yè)面。不要擔(dān)心暴露您的服務(wù)器API密鑰,您的數(shù)據(jù)不會(huì)以任何方式存儲(chǔ)在演示頁(yè)面中。