التعامل مع الإشعارات في تطبيقات أندرويد

يتميز نظام تشغيل أندرويد بوجود شريط أعلى الشاشة يمُد المستخدم بالعديد من المعلومات الهامة من ضمنها الإشعارات التي ترسلها التطبيقات.
android-notifications.png
فالإشعارات هي جزء من واجهة المستخدم لكنها تظهر خارج التطبيق لإعلام المستخدم بحدث معين، مما يُمكّن المستخدم من عرضه والتفاعل معه بينما يستخدم تطبيقًا آخر. ويحتوي الإشعار على رسالة مختصرة عن هذا الحدث.
ويظهر الإشعار عند حدوثه كأيقونة تعبر عن التطبيق في شريط الحالة أعلى الشاشة، ويمكنك معرفة تفاصيله عند سحب درج الإشعارات والضغط على الإشعار.
11.png
هناك عدة خطوات لصنع الإشعارات من داخل تطبيقك:

صنع كائن البناء الخاص بالإشعار من الصنف Notification.Builder

Notification.Builder mBuilder = new Notification.Builder(this);
من خلال هذا الكائن يمكننا التحكم في الخصائص الخاصة بالإشعار مثل عنوان الإشعار، الأيقونة المستخدمة، التحكم في الأولوية، التحكم في المهام التي يستطيع القيام بها عند الضغط عليه وغيرهم من الخصائص المختلفة.

تخصيص الحد الأدنى من الخصائص للإشعار

بعد الحصول على كائن البناء نبدأ في التحكم في خصائص الإشعار، وهناك بعض الخصائص الأساسية اللازم توافرها في الإشعار وهي:
  • الأيقونة الخاصة بالإشعار.
  • عنوان الإشعار.
  • المحتوى الخاص بالإشعار.
12.png
mBuilder.setSmallIcon(R.drawable.msg_icon);
mBuilder.setContentTitle("New Message");
mBuilder.setContentText("Hi, This is the message text.");
ويوجد العديد من الخصائص الأخرى التي يمكنك استخدامها حسب حاجة التطبيق لها.

بناء الإشعار بالخصائص السابقة

يتم ذلك باستدعاء التابع ()build والحصول على كائن من Notification.
Notification notif = mBuilder.build();

إظهار الإشعار في درج الإشعارات

يوفر أندرويد الصنف NotificationManager لإدارة الإشعارات من حيث إصدار الإشعار، تعديل الإشعار بعد إصداره أو إلغاء الإشعار برمجيًا. لذا يجب أولًا الحصول على كائن من هذا الصنف وذلك عن طريق استدعاء الدالة ()getSystemService وتمرير الثابت NOTIFICATION_SERVICE والذي يعني طلب الخدمات الخاصة بالإشعارات من خدمات النظام. وسيتم استخدام الدالة ()getSystemService كثيرًا عند الحاجة لطلب خدمات من النظام.
NotificationManager notifyMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
بعد ذلك نستدعي التابع ()notify باستخدام الكائن من NotificationManager ليظهر الإشعار في الحال، وتمرير رقم مميز له يُعبر عن الإشعار ليُستخدم هذا الرقم فيما بعد للتعديل على الإشعار أو إلغائه، كما يتم تمرير الإشعار الذي تم بنائه من قبل.
int notificationId = 103;
notifyMngr.notify(notificationId, notif);

تطبيق 1

سنقوم في هذا التطبيق بتجربة الخطوات السابق شرحها لتكوين التطبيق مثل الصورة التالية:
13.png
أولًا نبدأ بصنع واجهة المستخدم البسيطة في ملف activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Notification"
android:id="@+id/shw_notification"/>
</LinearLayout>
بعد ذلك ننتقل إلى الشيفرة الخاصة بالتطبيق في MainActivity.java باتباع الخطوات ذاتها لصنع الإشعار عند الضغط على الزر.
package apps.noby.simplenotification;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private Button shwbtn;
private String title;
private String detailText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
shwbtn = (Button) findViewById(R.id.shw_notification);
title = "New Message";
detailText ="Hi, This is the message text.";
shwbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Step 1
Notification.Builder mBuilder = new Notification.Builder(MainActivity.this);
//Step 2
mBuilder.setSmallIcon(R.drawable.ic_message);
mBuilder.setContentTitle(title);
mBuilder.setContentText(detailText);
//Step 3
Notification notif = mBuilder.build();
//Step 4
NotificationManager notifyMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
int notificationId = 103;
notifyMngr.notify(notificationId,notif);
}
});
}
}
ثم نقوم بتجربة التطبيق على المحاكي للتأكد من عمله كما ينبغي.
14.png

تطبيق 2

في التطبيق السابق عند الضغط على الإشعار لا يحدث شيئ، لذا في هذا التطبيق سنقوم بفتح نشاط جديد يعرض تفاصيل الإشعار أو ما نريد من معلومات عند الضغط على الإشعار.
15.png
ولفتح نشاط جديد داخل التطبيق سنستخدم Intent ولكن سنقوم بتغليف الكائن من Intent داخل كائن آخر من PendingIntent وفائدة هذا التغليف هو أنه لا يمكن استخدام الكائن من Intent خارج التطبيق، والإشعار كما ذكرنا يُعرض خارج حدود التطبيق لذا يقوم PendingIntent بإعطاء الصلاحية للتطبيقات الأخرى أو النظام والذي نُرسل إليه PendingIntent القدرة على تنفيذ الأوامر كأنها تتم داخل تطبيقك.
أولًا نقوم بصنع نشاط جديد يُدعى ResultActivity.
ثانيًا سنقوم بتعديل الشيفرة الخاصة بـ MainActivity.java وإضافة كائن من Intent.
Intent intent = new Intent(MainActivity.this,ResultActivity.class);
ونستطيع إرسال بيانات إلى النشاط الآخر بنفس الطريقة المستخدمة في الدروس السابقة.
intent.putExtra(DESC_KEY,detailText);
ثم نقوم بتغليف الكائن داخل PendingIntent:
PendingIntent pIntent = PendingIntent.getActivity(MainActivity.this , 0 , intent , PendingIntent.FLAG_UPDATE_CURRENT);
والخطوة الأخيرة هي وضع هذا Intent ضمن خصائص الإشعار باستخدام كائن البناء:
mBuilder.setContentIntent(pIntent);
لتُصبح الشيفرة النهائية لملف MainActivity.java بعد التعديل هي:
package apps.noby.simplenotification;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private Button shwbtn;
private String title;
private String detailText;
public final static String DESC_KEY ="descriptionKey";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
shwbtn = (Button) findViewById(R.id.shw_notification);
title = "New Message";
detailText ="Hi, This is the message text.";
shwbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Step 1
Notification.Builder mBuilder = new Notification.Builder(MainActivity.this);
//Step 2
mBuilder.setSmallIcon(R.drawable.ic_message);
mBuilder.setContentTitle(title);
mBuilder.setContentText(detailText);
Intent intent = new Intent(MainActivity.this,ResultActivity.class);
intent.putExtra(DESC_KEY,detailText);
PendingIntent pIntent = PendingIntent.getActivity(MainActivity.this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pIntent);
//Step 3
Notification notif = mBuilder.build();
//Step 4
NotificationManager notifyMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
int notificationId = 103;
notifyMngr.notify(notificationId,notif);
}
});
}
}
ولم نقم بتغيير شيء في ملف الواجهة activity_main.xml.
الآن لعرض التفاصيل التي سترسل إلى النشاط الجديد ResultActivity.java نبدأ في صنع واجهة المستخدم الخاصة بالنشاط ثم بتغيير الشيفرة الخاصة به ولا يوجد اختلاف بينها وبين الطريقة المستخدمة في الدروس السابقة.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:id="@+id/desc"/>
</LinearLayout>
package apps.noby.simplenotification;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class ResultActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
TextView tv = (TextView) findViewById(R.id.desc);
Intent intent = getIntent();
String description = intent.getExtras().getString(MainActivity.DESC_KEY);
tv.setText(description);
}
}
16.png
ثم نقوم بتجربة التطبيق على المحاكي.

تطبيق 3

لاحظ أنه عند الضغط على الإشعار في التطبيق السابق يقوم بفتح نشاط جديد ولكن يظل الإشعار متواجدًا في درج الإشعارات رغم عرضه والتفاعل معه لذا سنقوم في هذا التطبيق بتغيير بسيط حتى يختفي الإشعار بمجرد التفاعل معه.
في شيفرة التطبيق السابق بداخل الملف MainActivity.java سنقوم بتعديل السطور الخاصة بالخطوة الثانية لتُصبح.
mBuilder.setContentTitle(title);
mBuilder.setContentText(detailText);
mBuilder.setAutoCancel(true);
Intent intent = new Intent(MainActivity.this,ResultActivity.class);
intent.putExtra(DESC_KEY,detailText);
قمنا فقط بإضافة السطر الخاص باستدعاء التابع ()setAutoCancel وتمرير القيمة true باستخدام كائن البناء، والآن عند تجربة التطبيق بعد هذا التعديل ستجد أنه يقوم بإزالة الإشعار بمجرد الضغط عليه.
17.png

تطبيق 4

يتم استخدام الشكل السابق بكثرة خاصة في تطبيقات المحادثة أو رسائل البريد حيث يتم عرض صورة المستخدم وبجانبها بحجم صغير الأيقونة الخاصة بالتطبيق.
ولصنع ذلك يتم استدعاء التابع ()setLargeIcon باستخدام كائن البناء وتمرير له الصورة المراد عرضها بحجم كبير.
لكن هناك شرط وهو أن تكون الصورة بصيغة Bitmap ولأننا حتى الآن نقوم في الدروس باستخدام الصور المتواجدة في مجلد drawable لذا ينبغي قبل تمريرها للتابع ()setLargeIcon أن نقوم بتحويلها إلىBitmap ويتم ذلك عن طريق الخطوة التالية.
Bitmap img = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.drawable.ic_person);
ثم بعد ذلك تمريرها كما سبق لبناء الإشعار.
mBuilder.setLargeIcon(img);
لتُصبح الشيفرة الكاملة الخاصة بالملف MainActivity.java هي:
package apps.noby.simplenotification;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private Button shwbtn;
private String title;
private String detailText;
public final static String DESC_KEY ="descriptionKey";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
shwbtn = (Button) findViewById(R.id.shw_notification);
title = "New Message";
detailText ="Hi, This is the message text.";
shwbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Step 1
Notification.Builder mBuilder = new Notification.Builder(MainActivity.this);
//Step 2
mBuilder.setSmallIcon(R.drawable.ic_message);
Bitmap img = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.drawable.ic_person);
mBuilder.setLargeIcon(img);
mBuilder.setContentTitle(title);
mBuilder.setContentText(detailText);
mBuilder.setAutoCancel(true);
Intent intent = new Intent(MainActivity.this,ResultActivity.class);
intent.putExtra(DESC_KEY,detailText);
PendingIntent pIntent = PendingIntent.getActivity(MainActivity.this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pIntent);
//Step 3
Notification notif = mBuilder.build();
//Step 4
NotificationManager notifyMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
int notificationId = 103;
notifyMngr.notify(notificationId,notif);
}
});
}
}
ليعمل التطبيق كما هو متوقع على المحاكي.
18.png

تطبيق 5

في بعض الأحيان نحتاج إلى التفاعل السريع للمستخدم مع التطبيق دون الحاجة لفتح التطبيق أو لتوفير أكثر من اختيار لفتح أجزاء محددة في التطبيق.
19.png
للقيام بذلك نستخدم التابع ()addAction والذي يمكننا من إضافة زر إلى الإشعار.
PendingIntent pIntent = PendingIntent.getActivity(MainActivity.this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pIntent);
mBuilder.addAction(R.drawable.ic_reply,"Reply",pIntent);
mBuilder.addAction(R.drawable.ic_content_copy,"Copy",pIntent);
//Step 3
Notification notif = mBuilder.build();
ولاستخدام هذا التابع نقوم بتمرير صورة لتظهر داخل الزر، النص الخاص بالزر وأخيرًا كائن منPendingIntent ليتم تنفيذه عند الضغط على هذا الزر.
ويمكنك عمل ()addAction حتى ثلاث مرات فقط، ويمكن لكل زر أن يكون له PendingIntent مختلف خاص به ليقوم بتنفيذ أمر مختلف وفي المثال السابق لشرح الفكرة تم استخدام PendingIntent واحد.
والآن نقوم بتشغيل التطبيق على المحاكي للتأكد من عمله بشكل صحيح.

تطبيق 6

20.png
في بعض الأحيان تحتاج إلى التعديل على إشعار سابق دون إصدار إشعار جديد، وذلك بإضافة بعض المعلومات له أو بتغيير محتوى الإشعار أو كلاهما.
وقد تحتاج أيضًا إلى إزالة الإشعار برمجيًا دون تدخل من المستخدم وذلك عند حدوث شيء محدد أو مرور وقت محدد.
أولًا للقيام بالتعديل أو بتغيير محتوى إشعار دون إصدار إشعار آخر جديد نقوم ببناء الإشعار ثم نقوم بإصداره باستخدام نفس الـ NotificationID الذي نمرره للتابع ()notify حتى يقوم بتعديل الإشعار صاحب ID ذاته.
21.png
بفرض أن لدينا هذا الإشعار عند الضغط على زر Show Notification.
shwbtn = (Button) findViewById(R.id.shw_notification);
shwbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Step 1
Notification.Builder mBuilder = new Notification.Builder(MainActivity.this);
//Step 2
mBuilder.setSmallIcon(R.drawable.ic_message);
Bitmap img = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.drawable.ic_person);
mBuilder.setLargeIcon(img);
mBuilder.setContentTitle("New Message");
mBuilder.setContentText("Hi, This is the message text.");
mBuilder.setNumber(++totalNumber);
mBuilder.setAutoCancel(true);
Intent intent = new Intent(MainActivity.this,ResultActivity.class);
intent.putExtra(DESC_KEY,"Hi, This is the message text.");
PendingIntent pIntent = PendingIntent.getActivity(MainActivity.this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pIntent);
//Step 3
Notification notif = mBuilder.build();
//Step 4
NotificationManager notifyMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
int notificationId = 103;
notifyMngr.notify(notificationId,notif);
}
});
ثم عند الضغط على الزر Update Notification يتم تغييرها إلى المحتوى التالي.
updatebtn = (Button) findViewById(R.id.upd_notification);
updatebtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Step 1
Notification.Builder mBuilder = new Notification.Builder(MainActivity.this);
//Step 2
mBuilder.setSmallIcon(R.drawable.ic_message);
Bitmap img = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.drawable.ic_person);
mBuilder.setLargeIcon(img);
mBuilder.setContentTitle("Updated Message");
mBuilder.setContentText("Hi, This is an updated Message.");
mBuilder.setNumber(++totalNumber);
mBuilder.setAutoCancel(true);
Intent intent = new Intent(MainActivity.this,ResultActivity.class);
intent.putExtra(DESC_KEY,"Hi, This is an updated Message.");
PendingIntent pIntent = PendingIntent.getActivity(MainActivity.this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pIntent);
//Step 3
Notification notif = mBuilder.build();
//Step 4
NotificationManager notifyMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
int notificationId = 103;
notifyMngr.notify(notificationId,notif);
}
});
لاحظ أننا قمنا باستخدام نفس NotificationID في خطوة إظهار الإشعار وذلك لإخبار النظام أننا نريد التعديل على إشعار متواجد بالفعل.
والآن لإزالة الإشعار نضغط على الزر Cancel Notification.
cnclbtn = (Button) findViewById(R.id.cncl_notification);
cnclbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NotificationManager notifyMngr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
totalNumber = 0;
int notificationId = 103;
notifyMngr.cancel(notificationId);
}
});
لإزالة الإشعار نستدعي التابع ()cancel باستخدام الكائن من NotificationManager ونمرر لها الـ ID الخاص بالإشعار.
لاحظ أننا قد قمنا باستخدام التابع ()setNumber عند بناء الإشعار وذلك ليُظهر عدد مرات بناء وتعديل الإشعار ذاته، ويتم بدأ العد مجددًا عند الضغط على الزر Cancel Notification.

Unknown

Phasellus facilisis convallis metus, ut imperdiet augue auctor nec. Duis at velit id augue lobortis porta. Sed varius, enim accumsan aliquam tincidunt, tortor urna vulputate quam, eget finibus urna est in augue.

ليست هناك تعليقات:

إرسال تعليق