نمایش نوتیفیکیشن در اندروید با فایربیس ، در این مقاله از تجاری اپ میخواهیم نحوه نمایش نوتیفیکیشن در اندروید را با استفاده از فایربیس آموزش دهیم.در انتهای پروژه شما میتوانید هم از طریق فایل های php که در آموزش پیاده خواهیم کرد و هم از طریق پنل خود فایربیس نوتیفیکیشن به اپلیکیشن اندروید خود ارسال کنید 🙂
خب طبیعتا اولین کاری که برای این پروژه باید انجام بدیم اینه که یک اکانت فایربیس بسازیم.پس از ساخت اکانت فایربیس (برای ساخت اکانت فایربیس به این آدرس https://firebase.google.com مراجعه کنید ) از پنل سمت چپ گزینه Cloude Messanging را انتخاب کنید:
و در صفحه ای که باز خواهد شد آیکن اندروید را انتخاب کنید
حالا در صفحه ای که باز خواهد شد از شما میخواهد که اپلیکیشن اندروید خود را برای ارسال نوتیفیکیشن در فایربیس ثبت کنید
نام پکیج و یک نام اختیاری برای اپلیکیشن و مقدار SHA-1 که اختیاری ست را وارد کنید و دکمه Register app را بزنید.
در مرحله دوم یک فایل json با نام google-service.json تولید میکند که برای کانکت شدن اپلیکیشن به فایربیس باید درون پروژه قرار گیرد ، پس آنرا دانلود میکنیم و درون مسیری که خود فایربیس هم نشان داده و درادامه هم خواهیم گفت ایمپورت میکنیم
مرحله سوم هم وابستگی هایی که لازم است را گفته تا پیاده کنیم
در مرحله آخر هم فایربیس منتظر میماند تا اپلیکیشنی با نام پکیج مشخص شده و فایل json تولید شده اپلیکیشن را نصب کند و به فایربیس متصل شود تا اولین نصب موفق را ثبت کند.
همچنین بخوانید: عملیات Real Time CRUD با استفاده از فایربیس گوگل در لاراول
خب طبق مراحل ثبت پروژه در فایربیس که در بالا توضیح دادیم تنظیمات زیر در پروژه اعمال شد که بدلیل اهمیت زیاد مجددا تکرار خواهیم کرد.پس از دانلود فایل json مورد نیاز باید یک پروژه اندروید ایجاد میکنیم و اولین قدمی که باید برداریم ایمپورت کردن فایل json درون پروژه در project mode در مسیر:
Project name / app
حالا میتوان وابستگی ها یا dependency های مورد نیاز برای استفاده از FCM یا Firebase Cloud Messanging را اضافه کرد.
در فایل build.gradle(project)
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath 'com.google.gms:google-services:4.2.0'
}
در فایل build.gradle(app)
dependencies {
...
implementation 'com.google.firebase:firebase-core:17.0.1'
implementation 'com.google.firebase:firebase-messaging:19.0.1'
}
apply plugin: 'com.google.gms.google-services'
پس از sync کردن یک کلاس برای پیاده کردن رسیور فایربیس نیاز داریم پس یک کلاس کاتلین یا جاوا با نام MyFirebaseMessagingService ایجاد میکنیم و دستورات زیر را پیاده میکنیم
جاوا
package com.tejariapp.firebasenotificationapp.server;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import com.tejariapp.firebasenotificationapp.MainActivity;
import com.tejariapp.firebasenotificationapp.R;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
@Override
public void onNewToken(String s) {
super.onNewToken(s);
MySharedPref sharedPref = new MySharedPref(this);
sharedPref.saveToken(s);
}
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.e(TAG, "From: " + remoteMessage.getFrom() + " Message : " + remoteMessage + " Data : " + remoteMessage.getData());
if (remoteMessage.getData() != null) {
String status = remoteMessage.getData().get("status") != null ? remoteMessage.getData().get("status") : "";
if (status.equals("new_pm"))
sendNotification();
}
}
private void sendNotification() {
PendingIntent pendingIntent;
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder nb = new NotificationCompat.Builder(this, getString(R.string.app_name));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel mChannel = new NotificationChannel(getString(R.string.app_name),
getString(R.string.app_name),
NotificationManager.IMPORTANCE_HIGH);
mChannel.setDescription("this is message");
mChannel.enableLights(true);
mChannel.enableVibration(true);
mNotificationManager.createNotificationChannel(mChannel);
nb.setChannelId(getString(R.string.app_name) + getString(R.string.app_name));
}
nb.setSmallIcon(R.mipmap.ic_launcher_round);
nb.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher_round));
nb.setContentTitle("پیام جدید");
nb.setContentText("شما یک پیام جدید دارید");
nb.setAutoCancel(true);
nb.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000, 1000, 1000});
nb.setPriority(Notification.PRIORITY_MAX);
nb.setContentIntent(pendingIntent);
nb.setChannelId(getString(R.string.app_name) );
mNotificationManager.notify(0, nb.build());
}
}
کاتلین
package com.tejariapp.firebasenotificationapp.server
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Build
import android.util.Log
import androidx.core.app.NotificationCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.tejariapp.firebasenotificationapp.MainActivity
import com.tejariapp.firebasenotificationapp.R
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onNewToken(s: String?) {
super.onNewToken(s)
val sharedPref = MySharedPref(this)
sharedPref.saveToken(s)
}
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
Log.e(TAG, "From: " + remoteMessage!!.from + " Message : " + remoteMessage + " Data : " + remoteMessage.data)
if (remoteMessage.data != null) {
val status = if (remoteMessage.data["status"] != null) remoteMessage.data["status"] else ""
if (status == "new_pm")
sendNotification()
}
}
private fun sendNotification() {
val pendingIntent: PendingIntent
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)
val mNotificationManager = this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val nb = NotificationCompat.Builder(this, getString(R.string.app_name))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val mChannel = NotificationChannel(getString(R.string.app_name),
getString(R.string.app_name),
NotificationManager.IMPORTANCE_HIGH)
mChannel.description = "this is message"
mChannel.enableLights(true)
mChannel.enableVibration(true)
mNotificationManager.createNotificationChannel(mChannel)
nb.setChannelId(getString(R.string.app_name) + getString(R.string.app_name))
}
nb.setSmallIcon(R.mipmap.ic_launcher_round)
nb.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher_round))
nb.setContentTitle("پیام جدید")
nb.setContentText("شما یک پیام جدید دارید")
nb.setAutoCancel(true)
nb.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000, 1000, 1000))
nb.priority = Notification.PRIORITY_MAX
nb.setContentIntent(pendingIntent)
nb.setChannelId(getString(R.string.app_name))
mNotificationManager.notify(0, nb.build())
}
companion object {
private val TAG = "MyFirebaseMsgService"
}
}
در کلاس فوق ما از کلاس FirebaseMessagingService ارث بری کردیم که دو متد مهم برای override شدن دارد.
یک متد onNewToken داریم که در صورتی که توکن جدیدی به دستگاه داده شود آن را درون دیتابیس داخلی خود ذخیره میکند.این توکن برای ما خیلی اهمیت دارد چون در واقع آدرس دستگاه ما است و برای ارسال یک نوتفیکیشن به یک دیوایس خاص باید توکن آنرا داشته باشیم به همین دلیل باید توکن را علاوه بر دیتابیس داخلی درون دیتابیس سرور هم برای ارسال نوتیفیکیشن به یک دیوایس خاص ذخیره کرد.
@Override
public void onNewToken(String s) {
super.onNewToken(s);
MySharedPref sharedPref = new MySharedPref(this);
sharedPref.saveToken(s);
}
همچنین درون متد دیگری که override شده با عنوان onMessageReceived درواقع پیامی که در قالب جیسون برای ما ارسال شده رو مدیریت میکنیم.با استفاده از متد زیر میتوان دریافت پیام از کجا ارسال شده
remoteMessage.getFrom()
با استفاده از متد زیر میتوان دیتا (داده های جیسونی که همراه نونیتفای ارسال شده) را واکشی کرد
remoteMessage.getData()
ما میخواهیم که یک جیسون ارسال کنیم و براساس آن یک نوتیفیکیشن با اندروید ایجاد کنیم ، پس در دستورات چک کردیم که در جیسون های دریافتی مقداری که با کلید status ارسال شده را بررسی کن و اگر value آن new_pm بود سپس نوتیفیکیشن را ایجاد میکنیم.
String status = remoteMessage.getData().get("status") != null ? remoteMessage.getData().get("status") : "";
if (status.equals("new_pm"))
sendNotification();
در ادامه در دستورات php این جیسون را ارسال خواهیم کرد که قالبی مانند قالب زیر خواهد داشت
{
"status":"new_pm"
}
و در متد sendNotification هم یک نوتیفیکیشن ایجاد شده که با کلیک برروی آن به صفحه MainActivity هدایت شود و همچنین در بلاک زیر نوتیفیکیشن برای ورژن اندروید های بالای ۸ را تنظیم کردیم تا بتوان هر ویژگی که بخواهیم به آن بدهیم برای مثال ویبره ، صدا و…
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel mChannel = new NotificationChannel(getString(R.string.app_name),
getString(R.string.app_name),
NotificationManager.IMPORTANCE_HIGH);
mChannel.setDescription("this is message");
mChannel.enableLights(true);
mChannel.enableVibration(true);
mNotificationManager.createNotificationChannel(mChannel);
nb.setChannelId(getString(R.string.app_name) + getString(R.string.app_name));
}
طبق تنظیمات اندروید از ورژن اندروید ۸ به بالا نمیتوان بصورت ساده نوتیفیکیشن ساخت و سفارشی سازی یا کاستومایز کرد بلکه باید برای نوتیفیکیشن کانال بسازیم و تنظیمات را به کانال اعمال کنیم و کانال را به نوتیفیشن اختصاص دهیم.
خب ما رسیور فایربیس را پیاده کردیم تا زمان دریافت نوتیفیکشن از سرویس فایربیس اپلیکیشن ران شود و دستوراتی که نوشتیم انجام شود پس آن را به عنوان رسیور دائم در مانیفست پروژه مشخص میکنیم.
<service
android:name=".MyFirebaseMessagingService"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
خب همانطور که گفتیم ما توکن رو درون دیتابیس داخلی نوتیفیکیشن ذخیره میکنیم پس باید از کلاس sharedprefrence استفاده کنیم.بنابراین یک کلاس ایجاد میکنیم و درون آن دستورات مورد نیاز را مینویسیم
جاوا
package com.tejariapp.firebasenotificationapp.server;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import static android.content.Context.MODE_PRIVATE;
public class MySharedPref {
private Context context;
private SharedPreferences.Editor editor;
private SharedPreferences prefs;
public MySharedPref(Context context) {
this.context = context;
prefs = context.getSharedPreferences("PUSH_DB", MODE_PRIVATE);
editor = context.getSharedPreferences("PUSH_DB", MODE_PRIVATE).edit();
}
public void saveToken(String token) {
editor.putString("TOKEN", token);
editor.apply();
}
public String getToken() {
return prefs.getString("TOKEN", "-");
}
}
کاتلین
package com.tejariapp.firebasenotificationapp.server
import android.content.Context
import android.content.SharedPreferences
import android.content.Context.MODE_PRIVATE
class MySharedPref(private val context: Context) {
private val editor: SharedPreferences.Editor
private val prefs: SharedPreferences
val token: String?
get() = prefs.getString("TOKEN", "-")
init {
prefs = context.getSharedPreferences("PUSH_DB", MODE_PRIVATE)
editor = context.getSharedPreferences("PUSH_DB", MODE_PRIVATE).edit()
}
fun saveToken(token: String) {
editor.putString("TOKEN", token)
editor.apply()
}
}
فراموش نکنید که در مانیفست پروژه مجوز دسترسی به اینترنت هم قرار دهید
<uses-permission android:name="android.permission.INTERNET"/>
کلاس MainActivity هم که بدون هیچ عملیات خاصی به عنوان کلاس لانچر پیاده شده
جاوا
package com.tejariapp.firebasenotificationapp;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
کاتلین
package com.tejariapp.firebasenotificationapp
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
در نهایت فایل های php برای ارسال نوتیفیکیشن هم بصورت زیر خواهد بود
کلاس notif.php
<?php
class SendNotification {
private static $API_SERVER_KEY = 'AAAACzTpr1A:APA91bEujUifrFrdLaYtXYckfEXj3r-56RGorat_T2duFcR7TULvurBT4_0nieI8kxToSk3N2bHlpRi_hWScV90Gdj9FXwx-lerRmevL5..........';
private static $is_background = "TRUE";
public function __construct() {
}
public function sendPushNotificationToFCMSever($token) {
$path_to_firebase_cm = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'to' => $token,
'priority' => 10,
'data'=>array(
"status"=>"new_pm"
)
);
$headers = array(
'Authorization:key=' . self::$API_SERVER_KEY,
'Content-Type:application/json'
);
// Open connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $path_to_firebase_cm);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
// Execute post
$result = curl_exec($ch);
// Close connection
curl_close($ch);
return $result;
}
}
?>
مقدار API_SERVER_KEY را باید از پنل فایربس در مسیر زیر بیاوریم ، از پنل سمت راست برروی چرخ دنده کنار Project Overview کلیک کرده و Project settings رو انتخاب میکنیم
سپس تب cloud messaging را انتخاب میکنیم و مقدار server key رو کپی و در کلاس php که برای ارسال نوتیفیکیشن نوشتیم برای فیلد API_SERVER_KEY قرار میدهیم.
همچنین دستور زیر نیز درواقع همان مقدار جیسونی که ما در رسیور اندروید نوشتیم را تنظیم و ارسال میکنیم
$fields = array(
'to' => $token,
'priority' => 10,
'data'=>array(
"status"=>"new_pm"
)
);
حالا یک کلاس php دیگر ایجاد میکنیم برای ارسال نوتیفیکیشن با استفاده از کلاس notif.php با نام sendNotif.php ایجاد میکنیم و دستورات زیر را پیاده میکنیم:
<?php
include("connection.php");
include "SendNotification.php";
$id = $_POST['id'];
$con = connection::getConnection();
//send push code
$user_token = "";
$sql2 = "SELECT user_token FROM `tbl_user` WHERE `user_id`= $id";
$result2 = $con->query($sql2);
if ($result2->num_rows > 0){
while ($row = $result2->fetch_assoc()){
$user_token = $row['user_token'];
}
}
$serverObject = new SendNotification();
$jsonString = $serverObject->sendPushNotificationToFCMSever( $user_token );
?>
توجه کنید که دستورات فوق درصورتی ست که شما توکن های کاربران را ذخیره میکنید و میخواهید براساس آی دی کاربر توکن موبایل آنرا واکشی و نوتیفیکیشن برای او ارسال کنید ، اما درصورتی که میخواهید نوتیفیکیشن را به یک توکن استاتیک ارسال کنید میتوان دستورات را چنین تغییر داد.
<?php
include("connection.php");
include "SendNotification.php";
$con = connection::getConnection();
$serverObject = new SendNotification();
$jsonString = $serverObject->sendPushNotificationToFCMSever( 'user token' );
?>
بجای عبارت user token باید توکن موبایل مقصد را وارد کنید.
از طریق پنل فایربیس نیز میتوان با کلیک برروی گزینه Cloud Messaging از پنل سمت راست و سپس کلیک کردن دکمه New Notification در پنجره باز شده
میتوان یک نوتیفیکیشن جدید ایجاد و ارسال کرد.مطابق تصویر زیر مقادیر Notificaiton Title و Notification Text را وارد کنید سپس برروی دکمه Send test Message کلیک کنید
در پنجره باز شده توکن موبایل مقصد را وارد میکنیم و آیکن + را کلیک میکنیم ، سپس با فشردن دکمه Test نوتیفیکیشن برای توکن وارد شده ارسال خواهد.
امیدواریم که این آموزش برای شما مفید بوده باشد 🙂
5 Comments
وقت بخیر
من یک وب ویو ساختم و هیچ اطلاعاتی از کاربر توسط برنامه گرفته نمیشه و همه اطلاعات مثل شماره تلفن توسط سایت گرفته میشه ( از طریق وی وب ویو که ساختم ) ،
الان اگر بخوام کاربران رو از طریق سرور شناسایی کنم ( توکن گوشی به آیدی کاربر تو دیتابیس داده بشه ) و برای کاربری خاص نوتیفیکیشن بفرستم به نظر شما چطور میتونم این کار رو بکنم؟ یعنی وقتی کاربر شماره تلفنش رو وارد میکنه و ثبت نام میکنه از طریق وب ویو توکن گوشی هم به سرور فرستاده بشه و تو دیتابیس ثبت بشه.
قسمت ارسال توکن گوشی به دیتابیس سمت سرور و ذخیره اون تو دیتابیس رو هم بگین ممنون میشم!
با سلام
برای گرفتن توکن اپلیکیشن شما ملزم به پیاده سازی SDK سرویس مورد نظرتون هستید ( برای مثال FCM ) که با استفاده از دستوراتی که SDK بهتون ارائه میده بتونید توکن اون دیوایس خاص رو گرفته و با کتابخونه هایی مثل retrofit یا volley به سرور خودتون جهت ذخیره سازی در دیتابیس ارسال کنید.
با احترام
سلام ممنون از آموزشتون
آیا سرویس نوتیفیکیشن فایربیس برای ما ایرانیا بازه یا تحریم هستیم؟ منظورم اینه که کاربرای ما که با آی پی ایران هستن نوتیفیکیشن دریافت می کنن؟
با سلام
کل سرویس فایربیس در کل ایران رو تحریم کرده به این صورت که شما بخواید وارد کنسول فایربیس بشید باید از فیلتر شکن استفاده کنید. اما بعضی سرویس هایی که فایربیس ارائه میدهد مانند Cloud Messaging (که موضوع پست تجاری اپ بود) , زمانی که در سورس ایمپورت و کانفیگ میشود دیگر نیازی نیست که موبایل یا هر دیوایس دیگری به فیلتر شکن وصل شده باشد تا توکن از سمت فایربیس به آن دیوایس اختصاص داده شود و اجازه استفاده کامل از FCM را بدهد.
درحالی که بعضی سرویس های دیگر فایربیس حتی زمان ایمپورت شدن در سورس باز هم نیاز است که دیوایس به فیلتر شکن وصل شود تا سرویس به درستی عمل کند.
با احترام
من همه مراحل رو انجام دادم ولی توکن دریافت نمیشه. راستی شما در مانیفست دوتا سرویس قرار دادین، سرویس دومی چیه؟ توضیحی ندادین.