Cordova Android后台/关闭状态下FCM带交互按钮推送实现问询
实现Cordova Android后台/关闭状态下FCM带交互按钮的推送通知
可以实现这个需求,你遇到的核心问题是应用被完全杀死后JS环境终止,无法触发前端的消息回调,必须通过Android原生层处理FCM消息并生成带按钮的通知。以下是基于你当前使用的cordova-plugin-firebasex和cordova-plugin-local-notification的具体实现方案:
一、调整FCM推送负载
后端推送时只发送data字段,不要包含notification字段。这样FCM会把消息直接传递到原生的FirebaseMessagingService,而非系统通知栏,确保应用在任何状态下都能捕获到消息:
{ "to": "DEVICE_TOKEN", "data": { "title": "测试通知", "body": "是否确认操作?", "customData": "你的自定义业务数据" } }
二、扩展Android原生代码(关键步骤)
cordova-plugin-firebasex默认的后台消息处理不支持自定义通知按钮,需要自定义FirebaseMessagingService来生成带交互按钮的通知:
1. 创建自定义MessagingService类
在你的Cordova项目的platforms/android/app/src/main/java/[你的包名]/下新建CustomFirebaseMessagingService.java:
package com.your.package.name; // 替换成你的应用包名 import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; import android.app.NotificationChannel; 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 CustomFirebaseMessagingService extends FirebaseMessagingService { private static final String CHANNEL_ID = "interactive_notifications"; @Override public void onMessageReceived(RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); // 从data字段获取推送内容 String title = remoteMessage.getData().get("title"); String body = remoteMessage.getData().get("body"); String customData = remoteMessage.getData().get("customData"); // 创建通知渠道(Android O及以上必需) createNotificationChannel(); // 构建按钮点击的Intent Intent yesIntent = new Intent(this, NotificationActionReceiver.class); yesIntent.setAction("YES_ACTION"); yesIntent.putExtra("customData", customData); PendingIntent yesPendingIntent = PendingIntent.getBroadcast(this, 0, yesIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); Intent noIntent = new Intent(this, NotificationActionReceiver.class); noIntent.setAction("NO_ACTION"); noIntent.putExtra("customData", customData); PendingIntent noPendingIntent = PendingIntent.getBroadcast(this, 1, noIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // 构建带按钮的通知 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.mipmap.ic_launcher) // 替换成你的通知图标 .setContentTitle(title) .setContentText(body) .setPriority(NotificationCompat.PRIORITY_HIGH) .addAction(R.drawable.ic_yes, "确认", yesPendingIntent) // 按钮图标、文字、Intent .addAction(R.drawable.ic_no, "取消", noPendingIntent); // 显示通知 NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify((int) System.currentTimeMillis(), builder.build()); } private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { CharSequence name = "交互通知"; String description = "带按钮的通知渠道"; int importance = NotificationManager.IMPORTANCE_HIGH; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance); channel.setDescription(description); NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } } }
2. 创建通知按钮的广播接收器
同样在包名下新建NotificationActionReceiver.java,用于处理按钮点击事件并传递到JS层:
package com.your.package.name; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import org.apache.cordova.CordovaWebView; import org.apache.cordova.PluginResult; import org.json.JSONObject; public class NotificationActionReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); String customData = intent.getStringExtra("customData"); try { JSONObject data = new JSONObject(); data.put("action", action); data.put("customData", customData); // 发送消息到JS层 if (CordovaWebView.getWebView() != null) { PluginResult result = new PluginResult(PluginResult.Status.OK, data); result.setKeepCallback(true); CordovaWebView.getWebView().sendPluginResult(result, "notificationAction"); } } catch (Exception e) { e.printStackTrace(); } } }
3. 修改AndroidManifest.xml
在platforms/android/app/src/main/AndroidManifest.xml中注册自定义服务和广播接收器,替换插件默认的FirebaseMessagingService:
<!-- 移除插件默认的MessagingService注册(如果存在) --> <!-- <service android:name="com.google.firebase.messaging.FirebaseMessagingService"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> --> <!-- 注册自定义MessagingService --> <service android:name=".CustomFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> <!-- 注册广播接收器 --> <receiver android:name=".NotificationActionReceiver" android:exported="false"> <intent-filter> <action android:name="YES_ACTION" /> <action android:name="NO_ACTION" /> </intent-filter> </receiver>
三、JS层接收按钮点击事件
在前端代码中添加监听原生传递的按钮点击事件,保留原有的token获取逻辑:
import { getDevice } from "framework7/lite-bundle"; function setupPushNotification(getTokenCallBack) { const device = getDevice(); if (device.cordova) { FirebasePlugin.getToken((token) => getTokenCallBack(token)); // 监听原生传递的通知按钮点击事件 window.addEventListener('notificationAction', (event) => { const { action, customData } = event.detail; // 处理按钮点击后的业务逻辑,比如请求后端更新状态 console.log(`用户点击了${action},自定义数据:${customData}`); }); } } // 初始化推送 setupPushNotification((deviceToken) => { // 更新设备令牌到后端 });
四、注意事项
- 后台权限:部分国产厂商(小米、华为、OPPO等)会限制应用后台服务,需要引导用户开启「自启动权限」和「后台弹出界面权限」,否则应用被杀死后可能无法接收FCM消息。
- 通知图标:确保Android项目中存在通知图标资源(
ic_yes、ic_no等),否则按钮会显示默认图标。 - 插件版本兼容:当前使用的
cordova-plugin-firebasex@14.2.1和cordova-plugin-local-notification@0.9.0-beta.2版本无需额外调整,但需确保原生代码与插件依赖不冲突。
内容的提问来源于stack exchange,提问作者Miguel Q
相关产品推荐
相关产品推荐

