ویژگی‌ها و استایل‌های مختلف نوتیفیکیشن در اندروید

در این قسمت از سری مباحث آموزش برنامه نویسی اندروید به نحوه ساخت انواع نوتیفیکیشن یا اعلان در اندروید پرداخته و طریقه پیاده سازی استایل‌های مختلف و ویژگی‌ها و امکانات متنوعی که برای نوتیفیکیشن معرفی شده را بررسی و تمرین می‌کنیم.

آنچه در این آموزش می‌خوانید:

  • آشنایی با ساختار نوتیفیکیشن (Notification) در سیستم عامل اندروید
  • معرفی متد PendingIntent جهت تعامل کاربر با نوتیفیکیشن‌ها و هدایت وی به مقصد موردنظر
  • کار با دکمه‌های Action در نوتیفیکیشن
  • تفاوت نحوه نمایش اکشن‌ها در نسخه‌های قدیم و جدید اندروید
  • نمایش متن طولانی در اعلان به وسیله استایل BigTextStyle و گنجاندن خلاصه متن در نوتیفیکیشن
  • معرفی نوتیفیکیشن‌هایی که باز و بسته می‌شوند (Expandable Notification)
  • نمایش تصویر بزرگ در Notification با استفاده از استایل BigPictureStyle
  • نحوه تبدیل تصاویر با فرمت JPG و PNG به Bitmap در اندروید
  • نمایش لیست پیغام‌های دریافتی توسط InboxStyle
  • حذف و یا لغو نوتیفیکیشن پس از انجام یک عمل خاص و یا بصورت خودکار و پس از گذشت زمان مشخص
  • مدیریت Notification Badge از قبیل نحوه نمایش اعلان‌ها و همچنین تعداد پیغام‌های دریافتی
  • نحوه غیر فعال کردن Notification Badge یا Notification Dots
  • حذف یک Notification Channel از روی سیستم عامل اندروید توسط deleteNotificationChannel

این مبحث در قالب PDF و در ۲۷ صفحه تهیه شده که در ادامه چند صفحه‌ی ابتدایی را مشاهده می‌کنید:

در قسمت قبل با نحوه ساخت نوتیفیکیشن در اندروید آشنا شدیم. در این مبحث قصد دارم انواع نوتیفیکیشن، حالت‌ها و امکانات مختلف قابل پیاده سازی برای اعلان‌های اندرویدی را معرفی کنم.
برای این قسمت پروژه جدیدی نمی‌سازم و از همان پروژه قسمت قبل استفاده می‌کنم.

ساختار نوتیفیکیشن اندروید

به نام خدا. قبل از ادامه مبحث ابتدا بهتر است ساختار نوتیفیکیشنی که در مبحث قبل ساختیم را مرور کنیم. هرکدام از اجزاء اعلان را به ترتیب شماره توضیح می‌دهم:

ساختار نوتیفیکیشن Notification در اندروید

۱: آیکون کوچک (Small icon): این آیکون توسط setSmallIcon ساخته شده که تعریف آن برای نوتیفیکیشن الزامی است.
۲: در اینجا نام اپلیکیشنی که نوتیفیکیشن را اجرا کرده نمایش داده می‌شود.
۳: زمان ساخت نوتیفیکیشن را نشان می‌دهد. البته می‌توان این قسمت را به دلخواه تغییر داد و یا حذف کرد.
۴: آیکون بزرگ (Large icon): این آیکون توسط setLargeIcon ساخته شده و کاربرد آن نمایش یک آیکون یا تصویر بزرگ در کنار پیغام است.
۵: عنوان نوتیفیکیشن
۶: متن نوتیفیکیشن

انواع نوتیفیکیشن در اندروید

اعلان‌ها یا همان Notification را به روش‌های مختلفی می‌توان پیاده سازی کرد که هرکدام کاربرد مختص خود را داراست. یک نوتیفیکیشن صرفا پیام مختصری را به کاربر اطلاع می‌دهد. دیگری جزئیات بیشتری در اختیار کاربر قرار داده و او را به سمت یک اکتیویتی در اپلیکیشن و یا یک صفحه وب هدایت می‌کند. و انواع دیگری از نحوه ساخت و اجرای نوتیفیکیشن وجود دارد که در اینجا تعدادی را بررسی می‌کنیم.

نکته: کد کامل اکتیویتی علاوه بر سورس پروژه، در انتهای همین آموزش نیز قید شده. بنابراین در هر مرحله اگر با ابهامی مواجه شدید به کد کامل مراجعه کنید. به جهت خلاصه شدن متن، از توضیحات تکراری (شامل ساخت دکمه، تعریف آن در کلاس اکتیویتی، ساخت متد setOnClickListener و…) تا حد امکان اجتناب کردم.
نکته: پیاده سازی قواعد و اصول طراحی متریال در نوتیفیکیشن‌ها از اهمیت بالایی برخوردار است. منابعی مانند این لینک کمک زیادی در درک بهتر جزئیات طراحی به ما می‌کند.

استفاده از PendingIntent و ساخت Action برای نوتیفیکیشن

نوتیفیکیشنی که قبلا ساختیم صرفا یک پیغام را به کاربر نمایش می‌دهد و غیر از بستن آن، کاربر هیچگونه تعاملی نمی‌تواند با این پیغام داشته باشد. در صورتی که ما به این تعامل نیاز داریم. اگر اعلان مربوط به یک تخفیف است، می‌بایست کاربر را به صفحه مرتبط با آن هدایت کند. در اینجا از pendingIntent استفاده می‌کنیم. قبلا با نحوه کار با intent در اندروید آشنا شدیم. حالا در نوتیفیکیشن هم با استفاده از اینتنت تعیین می‌کنیم بعد از لمس اعلان توسط کاربر، چه عملی صورت پذیرد.
پروژه Notification را باز می‌کنم. ابتدا یک دکمه با عنوان PendingIntent Notification به Layout اکتیویتی اضافه می‌کنم:

ساخت نوتیفیکیشن در اندروید توسط PendingIntent

سپس طبق کد زیر یک نوتیفیکیشن دیگر داخل اکتیویتی می‌سازم:

package ir.android_studio.notification;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
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.graphics.Color;
import android.media.RingtoneManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Button simpleButton, pendingButton;
    NotificationManager notifManager;
    String offerChannelId = "Offers";
    PendingIntent mpIntent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        simpleButton = findViewById(R.id.simple_notif);
        pendingButton = findViewById(R.id.pending_notif);

        notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        Intent pIntent = new Intent(this, CartActivity.class);
        mpIntent = PendingIntent.getActivity(this, 0, pIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        simpleButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                createNotifChannel();
                simpleNotification();

            }
        });

        pendingButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                createNotifChannel();
                pendingNotification();

            }
        });

    }

    private void createNotifChannel() {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            String offerChannelName = "Shop offers";
            String offerChannelDescription= "Best offers for customers";
            int offerChannelImportance = NotificationManager.IMPORTANCE_DEFAULT;

            NotificationChannel notifChannel = new NotificationChannel(offerChannelId, offerChannelName, offerChannelImportance);
            notifChannel.setDescription(offerChannelDescription);
            //notifChannel.enableVibration(true);
            notifChannel.enableLights(true);
            notifChannel.setLightColor(Color.GREEN);

            notifManager.createNotificationChannel(notifChannel);

        }

    }

    public void simpleNotification() {

        NotificationCompat.Builder sNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
                .setSmallIcon(R.drawable.notif_icon)
                .setContentTitle("بروزرسانی")
                .setContentText("یک نسخه جدید از برنامه آماده دریافت است")
                .setVibrate(new long[]{100,500,500,500,500,500})
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.android))
                .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);

        notifManager.notify(1, sNotifBuilder.build());

    }

    public void pendingNotification() {

        NotificationCompat.Builder pNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
                .setSmallIcon(R.drawable.notif_icon)
                .setContentTitle("تخفیف پنجاه درصدی!")
                .setContentText("پنجاه درصد تخفیف به مناسبت طلوع خورشید")
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.android))
                .setContentIntent(mpIntent);

        notifManager.notify(2, pNotifBuilder.build());

    }

}

در کد فوق ابتدا pendingButton را به دکمه مربوطه در لِی اوت متصل کردم. سپس یک شیء از Intent با نام mIntent ساختم:

Intent pIntent = new Intent(this, CartActivity.class);

به جهت ملموس بودن نتیجه کار، یک اکتیویتی با نام CartActivity به پروژه اضافه کرده و به اینتنت معرفی کردم.

mpIntent = PendingIntent.getActivity(this, 0, pIntent, PendingIntent.FLAG_UPDATE_CURRENT);

سپس با استفاده از متد PendingIntent و getActivity تعیین می‌کنم با لمس نوتیفیکیشن، pIntent اجرا شود. این متد ۴ پارامتر می‌گیرد که در جدول زیر معرفی شده:

پارامترهای ورودی pendingIntent

اولی Context است که this وارد کردم. پارامتر دوم یک مقدار از جنس int است که به عنوان یک کد درخواست خصوصی تلقی می‌شود. من برای این نوتیفیکیشن مقدار ۰ قرار دادم. پارامتر سوم اینتنتی است که قبلا تعریف کردم یعنی pIntent. آخرین پارامتر یعنی flags جهت تعیین وضعیت اینتنت است که من در اینجا از نوع FLAG_UPDATE_CURRENT انتخاب کردم.
در قدم بعد یک تابع با نام pendingNotification به کلاس اضافه کردم. ۴ متد نخست این تابع مشابه simpleNotification است که در مبحث قبل توضیحات لازم ارائه شده.

public void pendingNotification() {

    NotificationCompat.Builder pNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
            .setSmallIcon(R.drawable.notif_icon)
            .setContentTitle("تخفیف پنجاه درصدی!")
            .setContentText("پنجاه درصد تخفیف به مناسبت طلوع خورشید")
            .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.android))
            .setContentIntent(mpIntent); 

    notifManager.notify(2, pNotifBuilder.build());

}

توسط setContentIntent اینتنتی که قبلا ساختم را به نوتیفیکیشن معرفی می‌کنم.
در نهایت متد setOnClickListener مربوط به دکمه pendingButton را ساخته و توابع مرتبط با کانال و نوتیفیکیشن را فراخوانی می‌کنم. (برای سایر نوتیفیکیشن‌ها نیز همین مراحل تکرار می‌شود؛ یعنی اضافه کردن دکمه در Layout، ساخت متد setOnClickListener و فراخوانی توابع کانال و نوتیفیکیشن مربوط به آن درون این متد).
پروژه را اجرا کرده و روی دکمه PendingIntent Notification کلیک می‌کنم:

اجرای نوتیفیکیشن در اندروید

حذف نوتیفیکیشن بعد از کلیک روی آن

با کلیک روی نوتیفیکیشن، به اکتیویتی CartActivity هدایت شدم. اما یک ایراد وجود دارد. به نوار وضعیت تصویر دوم دقت کنید. هنوز آیکون نوتیفیکیشن مشاهده می‌شود. یعنی با وجود اینکه کاربر روی نوتیفیکیشن کلیک کرده و به مقصد مدنظر منتقل شده، اعلان همچنان باقی مانده که لازم است این مشکل را رفع کنیم. اینکار توسط متد setAutoCancel انجام می‌پذیرد:

NotificationCompat.Builder pNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
        .setSmallIcon(R.drawable.notif_icon)
        .setContentTitle("تخفیف پنجاه درصدی!")
        .setContentText("پنجاه درصد تخفیف به مناسبت طلوع خورشید")
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.android))
        .setContentIntent(mpIntent)
        .setAutoCancel(true);

با اجرای مجدد پروژه، بعد از کلیک روی Notification، علاوه بر انتقال کاربر به صفحه CartActivity نوتیفیکیشن نیز حذف می‌شود.
علاوه بر کلیک روی نوتیفیکیشن، می‌توان دکمه‌هایی به اعلان افزود که برای هرکدام نیز یک intent مجزا تعریف شده باشد. این دکمه‌ها یک Action می‌نامیم.
برای مثال، نوتیفیکیشن برنامه مدیریت پیامک عموما دو گزینه دارد. اولی Reply جهت پاسخ دادن به پیامک دریافتی و دومی Mark as read که با لمس این دکمه، پیامک از حالت “خوانده نشده” به “خوانده شده” تغییر وضعیت پیدا می‌کند.
من متد setContentIntent را غیرفعال کرده و بجای آن دو Action به نوتیفیکیشن اضافه می‌کنم:

NotificationCompat.Builder pNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
        .setSmallIcon(R.drawable.notif_icon)
        .setContentTitle("تخفیف پنجاه درصدی!")
        .setContentText("پنجاه درصد تخفیف به مناسبت طلوع خورشید")
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.android))
        //.setContentIntent(mpIntent)
        .addAction(R.drawable.notif_icon, "Buy", mpIntent)
        .addAction(R.drawable.notif_icon, "Product details", mpIntent)
        .setAutoCancel(true);

addAction سه ورودی می‌گیرد:
ورودی اول: برای هر گزینه می‌توان یک آیکون تعریف کرد. البته توجه داشته باشید از اندروید Nougat به بعد برای سادگی بیشتر محیط نوتیفیکیشن، این آیکون‌ها نمایش داده نمی‌شوند.
ورودی دوم: عنوان اکشن است که برای اکشن اول “Buy” و اکشن دوم “Product details” وارد کردم.
ورودی سوم: PendingIntent ای که قبلا تعریف شده.

مجدد پروژه را اجرا می‌کنم:

اضافه کردن دکمه Action به نوتیفیکیشن اندروید توسط متد addAction

دو اکشن به انتهای نوتیفیکیشن اضافه شده که البته در این مثال هردو یک عملکرد دارند؛ یعنی هدایت به CartActivity.
همانطور که قبلا اشاره کردم، از اندروید N و به بالاتر، آیکون گزینه‌ها نمایش داده نمی‌شود. اما روی دیوایس‌های پایین‌تر از این نسخه، آیکون‌ها در کنار عنوان دکمه وجود دارد. پروژه را روی یک دیوایس با API 23 اجرا کردم:

عدم نمایش آیکون اکشن نوتیفیکیشن در اندروید پایینتر از N

نکته: با کلیک روی اکشن‌ها کاربر به مقصد هدایت شده اما بازهم نوتیفیکیشن حذف نمی‌شود. یعنی setAutoCancel اینجا کاربردی ندارد. برای حل این مشکل از متد cancel استفاده می‌شود که در صفحه ۱۸ به آن پرداخته شده است.

نمایش متن بزرگ در نوتیفیکیشن توسط BigTextStyle

گاهی اوقات لازم است متن طولانی تری در نوتیفیکیشن به کاربر نمایش دهیم. اگر برای متن طولانی از setContentText استفاده کنیم تنها چند کلمه ابتدای آن قابل مشاهده خواهد بود. اینجاست که استایل‌ها در نوتیفیکیشن امکان شخصی سازی بیشتری به ما می‌دهند. به کد زیر دقت کنید:

public void bigTextNotification() {

    NotificationCompat.BigTextStyle bStyle = new NotificationCompat.BigTextStyle()
            .bigText("لورم ایپسوم متنی است که ساختگی برای طراحی و چاپ آن مورد است. صنعت چاپ زمانی لازم بود شرایطی شما باید فکر ثبت نام و طراحی، لازمه خروج می باشد ")
            .setBigContentTitle("نوتیفیکیشن طولانی")
            .setSummaryText("خلاصه متن طولانی");

    NotificationCompat.Builder bNotifBuilder = new NotificationCompat.Builder(this, offerChannelId)
            .setSmallIcon(R.drawable.notif_icon)
            .setContentTitle("تخفیف پنجاه درصدی! ")
            .setContentText("پنجاه درصد تخفیف به مناسبت طلوع خورشید")
            .setStyle(bStyle);

    notifManager.notify(3, bNotifBuilder.build());

}

مانند قبل یک تابع جدید به کلاس اضافه کردم. نام این تابع را bigTextNotification گذاشتم.
در NotificationCompat امکان تعریف Style ها را داریم. در اینجا من از BigTextStyle یک شیء با نام bStyle ایجاد کرده‌ام که ۳ ویژگی برای آن تعریف شده.

جهت مطالعه ادامه آموزش، فایل PDF را دانلود نمائید

توجه : سورس پروژه درون پوشه Exercises قرار دارد

با توجه به اینکه آموزش‌های پایه با قیمت پایین در اختیار کاربر قرار گرفته و درآمد حاصل صرف تامین هزینه‌های وب سایت و تهیه آموزش‌های آتی می‌شود، به اشتراک گذاری این فایل با دیگران خلاف اخلاق است.

دانلود نسخه کامل این آموزش به همراه سورس پروژه
تعداد صفحات : ۲۶
حجم : ۲ مگابایت
قیمت : ۱۶ هزار تومان
توجه: صرفا در صورتی از درگاه پشتیبان استفاده کنید که قادر به پرداخت از طریق سبد دانلود نباشید.
افزودن به سبد دانلود درگاه پشتیبان
این مطلب چقدر برایتان مفید بود؟ لطفا امتیاز دهید
4.6/5 - (12 امتیاز)
پرسش‌ها و دیدگاه‌های کاربران
دوره آموزش برنامه نویسی اندروید
دوره آموزش برنامه نویسی اندروید

با دریافت این دوره به تمامی آموزش‌های غیر رایگان و رایگان موجود در وب سایت دسترسی دارید که تخفیفی برای آموزش‌های غیر رایگان نیز درنظر گرفته شده. این پکیج به دو صورت دانلودی و ارسال پستی ارائه می‌گردد.
آموزش‌های اندروید استودیو در دو دسته «پایه» و «تکمیلی» منتشر می‌شوند.
آموزش‌های پایه شامل مباحث اصلی و ضروری و آموزش‌های تکمیلی مطالبی است که می‌بایست در کنار مطالب اصلی بررسی شود.
با خرید این دوره، به تمامی آموزش‌های غیر رایگانی که در آینده منتشر می‌شود نیز به صورت رایگان دسترسی خواهید داشت!

یک دیدگاه بنویسید

پرسش‌های زیر تایید و پاسخ داده نـــخواهند شد:
۱: جزء موارد مطرح شده در صفحات مشکلات و پرسش‌های رایج و بروزرسانی‌های محتوای آموزشی باشد
۲: سوال قبلا توسط کاربران در دیدگاه‌ها مطرح و پاسخ داده شده باشد
۳: پرسش خارج از مبحث آموزشی موجود در این صفحه باشد

  • احسان بستاوند گفت:

    سلام میشه راهنمایی کنید چطور میشه نوتیفیکیشنی مثل برنامه باد صبا طراحی کرد که در همه دستگاه ها یکسان نمایش داده بشه؟ من از RemoteView استفاده کردم….. اما باز در ورژن های مختلف اندروید یکسان نمایش داده نیمشه؟

  • آرتم گفت:

    واقعا که واسه دریافت نسخه پی دی اف پول می گیرید! شرم آوره. آدم با لپتاب خودش بره پرینت بگیره از صفحه به صرفه تره.

  • Hosn گفت:

    سلام.
    بنده یک سوالی داشتم.
    الان تمام چیزهایی که فرمودید در این پست و قبلی به نحوی بود که نوتیفیکیشن از درون اکتیویتی فراخوانی میشد.
    در آموزش سرویس نیز در Forground services نوتیفیکیشن از داخل سرویس فراخوانی میشد و خود سرویس نیز از درون اکتیویتی فراخوانی میشد.
    تلگرام ، واتساپ ، اینستاگرام و … اگر توجه کنید یک سیستمی دارند که وقتی شما انلاین میشوید لیست اخرین پیام های دریافتی رو بدون اینکه نیاز باشه شما وارد اپلیکیشن شوید برای شما در غالب نوتیفیکیشن ارسال میکند.
    من باید چجوری بدون ورود به اکتیویتی سرویس رو فعال کنم تا نوتیفیکیشن رو ارسال کنه؟
    بعد مورد مشابهش رو شما در تماس واتساپ یا حتی خود تلفن همراهتون هم دیده اید که بدون اینکه توی اپلیکیشن باشید ناگهان زنگ میخورد.
    حتی اگر یه اسمی چیزی هم به من معرفی کنید که من برم سرچ کنم خیلی خوب میشه.
    چون من اصلا هیچی تو سایت های خارجی و داخلی پیدا نکردم.
    ممنون میشم راهنمایی کنید.