使用Firebase云消息傳遞FCM和PHP的Android推送通知2018-08-15

使用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è)名為activityappserviceutils的包。以下是此項(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ù)MyFirebaseMessagingServiceMyFirebaseInstanceIDService

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目錄并在htdocswww中創(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è)面中。

DEMO

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