一、前言

在 Android 开发里,推送通知是个挺重要的功能。它能让应用及时把消息传达给用户,提升用户的使用体验。不过呢,实现推送通知可不是一件简单的事儿,会遇到各种各样的难题。今天咱们就来聊聊怎么解决这些难题,从 FCM 到本地通知,给大家来个完整的实现过程。

二、FCM 简介

2.1 什么是 FCM

FCM 就是 Firebase Cloud Messaging 的缩写,这是 Google 提供的一个跨平台的消息传递解决方案。它能让开发者很轻松地给 Android、iOS 和 Web 应用发送消息。简单来说,就是你可以用 FCM 把消息从服务器推送到用户的设备上。

2.2 FCM 的优点

FCM 的优点可不少。首先,它的稳定性很强,Google 的服务器很靠谱,基本不会出现消息丢失的情况。其次,它支持多种消息类型,像通知消息、数据消息都可以发送。而且,它还能和 Firebase 的其他服务集成,比如 Analytics 等,方便开发者做数据分析。

2.3 FCM 的缺点

当然啦,FCM 也有一些缺点。由于它是 Google 的服务,在某些网络环境下可能会受到限制。另外,对于一些小项目来说,使用 FCM 可能会增加一些不必要的复杂性。

2.4 FCM 的应用场景

FCM 适合那些需要实时推送消息的应用,比如社交应用、新闻应用等。这些应用需要及时把新消息推送给用户,FCM 就能很好地满足这个需求。

2.5 示例代码(Java 技术栈)

// 首先,在项目的 build.gradle 文件中添加 FCM 依赖
implementation 'com.google.firebase:firebase-messaging:23.1.2'

// 在 AndroidManifest.xml 中配置服务
<service
    android:name=".MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

// 创建一个继承 FirebaseMessagingService 的类
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // 处理接收到的消息
        if (remoteMessage.getNotification() != null) {
            String title = remoteMessage.getNotification().getTitle();
            String body = remoteMessage.getNotification().getBody();
            // 这里可以调用显示通知的方法
            showNotification(title, body);
        }
    }

    private void showNotification(String title, String body) {
        // 显示通知的代码
        // 这里省略具体实现,后续会详细介绍
    }
}

三、本地通知简介

3.1 什么是本地通知

本地通知就是应用在设备本地触发的通知。它不需要和服务器进行交互,应用可以根据自己的逻辑在合适的时间触发通知。比如,你设置了一个提醒,到时间了应用就会弹出通知。

3.2 本地通知的优点

本地通知的优点在于它不受网络限制,即使设备没有网络,也能正常触发通知。而且,它的灵活性很高,应用可以根据自己的需求自定义通知的时间、内容等。

3.3 本地通知的缺点

本地通知的缺点是它不能实时接收服务器的消息。如果需要接收服务器的消息,还是得依靠像 FCM 这样的推送服务。

3.4 本地通知的应用场景

本地通知适合那些需要提醒用户的场景,比如闹钟、日程提醒等。这些场景不需要实时接收服务器的消息,只需要在特定的时间提醒用户就可以了。

3.5 示例代码(Java 技术栈)

// 创建一个通知管理器
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

// 创建通知渠道(Android 8.0 及以上需要)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    NotificationChannel channel = new NotificationChannel("channel_id", "channel_name", NotificationManager.IMPORTANCE_DEFAULT);
    notificationManager.createNotificationChannel(channel);
}

// 创建通知
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "channel_id")
       .setSmallIcon(R.drawable.ic_notification)
       .setContentTitle("本地通知标题")
       .setContentText("本地通知内容")
       .setPriority(NotificationCompat.PRIORITY_DEFAULT);

// 显示通知
notificationManager.notify(1, builder.build());

四、从 FCM 到本地通知的完整实现

4.1 实现思路

我们的实现思路是这样的:首先,使用 FCM 接收服务器的消息。当接收到消息后,根据消息的内容和类型,决定是直接显示通知,还是触发本地通知。如果需要触发本地通知,就按照本地通知的流程来处理。

4.2 示例代码(Java 技术栈)

// 在 MyFirebaseMessagingService 类中添加处理逻辑
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import androidx.core.app.NotificationCompat;

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        if (remoteMessage.getNotification() != null) {
            String title = remoteMessage.getNotification().getTitle();
            String body = remoteMessage.getNotification().getBody();

            // 判断是否需要触发本地通知
            if (needTriggerLocalNotification()) {
                triggerLocalNotification(title, body);
            } else {
                showNotification(title, body);
            }
        }
    }

    private boolean needTriggerLocalNotification() {
        // 根据具体业务逻辑判断是否需要触发本地通知
        // 这里简单返回 false,实际开发中需要根据需求实现
        return false;
    }

    private void triggerLocalNotification(String title, String body) {
        // 创建通知管理器
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        // 创建通知渠道(Android 8.0 及以上需要)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("channel_id", "channel_name", NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        // 创建通知
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "channel_id")
               .setSmallIcon(R.drawable.ic_notification)
               .setContentTitle(title)
               .setContentText(body)
               .setPriority(NotificationCompat.PRIORITY_DEFAULT);

        // 显示通知
        notificationManager.notify(1, builder.build());
    }

    private void showNotification(String title, String body) {
        // 创建通知管理器
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        // 创建通知渠道(Android 8.0 及以上需要)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("channel_id", "channel_name", NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        // 创建通知
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "channel_id")
               .setSmallIcon(R.drawable.ic_notification)
               .setContentTitle(title)
               .setContentText(body)
               .setPriority(NotificationCompat.PRIORITY_DEFAULT);

        // 显示通知
        notificationManager.notify(1, builder.build());
    }
}

五、注意事项

5.1 FCM 配置注意事项

在使用 FCM 时,要确保在 Firebase 控制台正确配置项目信息,包括应用的包名、SHA-1 指纹等。另外,要注意网络环境的影响,在某些网络环境下可能需要进行额外的配置。

5.2 本地通知注意事项

对于本地通知,要注意通知渠道的创建(Android 8.0 及以上)。不同的通知渠道可以设置不同的优先级、声音等。另外,要合理设置通知的触发时间,避免给用户造成困扰。

六、文章总结

通过这篇文章,我们了解了 FCM 和本地通知的相关知识,以及如何从 FCM 到本地通知进行完整的实现。FCM 适合实时推送服务器消息,而本地通知适合本地提醒。在实际开发中,我们可以根据具体的需求,灵活使用这两种方式,为用户提供更好的通知体验。