Titanium Android端PubNub后台/锁屏状态无法接收消息求助
这个问题本质上是Android后台进程限制导致的——当应用进入后台、锁屏或被移出最近列表时,系统会挂起甚至终止应用的普通网络连接(包括PubNub默认的WebSocket连接),所以单纯靠PubNub的addListener无法在这些状态下收到消息。要解决这个问题,你需要结合**PubNub Push Notifications(基于FCM)**来实现后台消息推送,下面是具体步骤:
一、核心逻辑说明
PubNub支持通过FCM(Firebase Cloud Messaging)向Android设备推送消息,当应用在后台时,消息会通过FCM通道发送,由Android系统直接处理(显示通知、唤醒应用),不需要维持长连接,这就能绕过Android的后台限制。
二、配置前置条件
Firebase项目配置:
- 去Firebase控制台创建对应项目,获取
google-services.json文件,放到你的Titanium项目的platform/android目录下。 - 在Firebase控制台找到项目的FCM服务器密钥,复制后粘贴到PubNub控制台的Push Notifications配置中(关联FCM网关)。
- 去Firebase控制台创建对应项目,获取
Titanium项目tiapp.xml配置:
添加必要权限和FCM服务组件,替换YOUR_APP_PACKAGE_NAME为你的应用包名:<android xmlns:android="http://schemas.android.com/apk/res/android"> <manifest> <!-- 必要权限 --> <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" android:maxSdkVersion="33"/> <application> <!-- FCM接收器 --> <receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE"/> <action android:name="com.google.android.c2dm.intent.REGISTRATION"/> <category android:name="YOUR_APP_PACKAGE_NAME"/> </intent-filter> </receiver> <!-- FCM消息服务 --> <service android:name="com.google.firebase.messaging.FirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT"/> </intent-filter> </service> </application> </manifest> </android>安装Titanium FCM模块:
使用官方ti.firebase模块,通过npm安装:npm install ti.firebase
三、修改PubNub代码,集成FCM推送
1. 初始化FCM并注册设备到PubNub
在应用启动时,获取FCM设备令牌,将令牌与PubNub订阅通道绑定,这样PubNub就能通过FCM向设备推送消息:
var pubnub = new PubNub({ subscribeKey : 'sub-key', publishKey : 'pub-key' }); // 初始化FCM var Firebase = require('ti.firebase'); Firebase.getInstance().configure(); // 获取FCM令牌并注册到PubNub Firebase.getInstance().getToken(function(e) { if (e.success) { const deviceToken = e.token; // 将设备令牌绑定到PubNub通道 pubnub.addPushNotificationsOnChannels({ channels: ['Channel'], device: deviceToken, pushGateway: 'fcm' // 对应FCM网关 }, function(status) { if (status.error) { console.error("Push注册失败:", status); } else { console.log("Push注册成功"); } }); } else { console.error("获取FCM令牌失败:", e.error); } }); // 保留原有的前台监听(前台时继续用WebSocket接收) pubnub.addListener({ status : function(st) { if (st.category === "PNConnectedCategory") { console.log("PubNub已连接"); } }, message : function(m) { const pushStatus = m.message; console.log("前台收到消息:", pushStatus); // 前台显示通知(可选) showLocalNotification(pushStatus); }, presence : function(ps) { console.log("Presence更新:", ps); } }); pubnub.subscribe({ channels : ['Channel'] });
2. 监听FCM推送消息(后台状态下触发)
添加FCM消息监听器,当应用在后台时,FCM会收到PubNub的推送,此时创建本地通知展示给用户:
// 监听FCM远程消息 Firebase.getInstance().addEventListener('didReceiveRemoteNotification', function(e) { const messageData = e.data; console.log("后台收到FCM推送:", messageData); // 显示本地通知 showLocalNotification(messageData.message); }); // 封装本地通知函数 function showLocalNotification(content) { if (Ti.Platform.name === "android") { const notificationManager = Ti.Android.NotificationManager; const intent = Ti.Android.createIntent({ action: Ti.Android.ACTION_MAIN, className: 'YOUR_APP_PACKAGE_NAME.MainActivity', // 替换为你的主Activity flags: Ti.Android.FLAG_ACTIVITY_CLEAR_TOP | Ti.Android.FLAG_ACTIVITY_SINGLE_TOP }); const pendingIntent = Ti.Android.createPendingIntent({ intent: intent, type: Ti.Android.PENDING_INTENT_FOR_ACTIVITY, flags: Ti.Android.FLAG_UPDATE_CURRENT }); const notification = Ti.Android.createNotification({ contentTitle: "新消息", contentText: content, contentIntent: pendingIntent, icon: Ti.App.Android.R.drawable.appicon, // 替换为你的通知图标 defaults: Ti.Android.DEFAULT_SOUND | Ti.Android.DEFAULT_VIBRATE }); notificationManager.notify(1, notification); } }
四、优化后台稳定性
请求忽略电池优化:
Android的Doze模式会限制后台应用的网络和进程,请求用户将应用加入电池优化白名单:const powerManager = Ti.Android.PowerManager; if (!powerManager.isIgnoringBatteryOptimizations(Ti.App.id)) { const intent = Ti.Android.createIntent({ action: 'android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS', data: 'package:' + Ti.App.id }); Ti.Android.currentActivity.startActivity(intent); }Android 12+通知权限:
Android 12及以上版本需要动态申请POST_NOTIFICATIONS权限:if (Ti.Platform.Android.API_LEVEL >= 33) { const permission = 'android.permission.POST_NOTIFICATIONS'; if (!Ti.Android.hasPermission(permission)) { Ti.Android.requestPermissions([permission], function(e) { if (e.success) { console.log("通知权限已授予"); } else { console.warn("通知权限被拒绝"); } }); } }
五、测试验证
- 确保PubNub控制台的Push配置正确关联了FCM服务器密钥。
- 发送测试消息时,选择通过FCM推送(PubNub的推送API或控制台可指定推送网关)。
- 将应用切换到后台、锁屏或移出最近列表,检查是否能收到通知。
内容的提问来源于stack exchange,提问作者Nuibb

