如何在Delphi 10.4.2中实现Android后台读取推送通知?
Delphi 10.4.2 Android 后台推送自动执行任务解决方案
要实现推送到达时后台自动执行指定逻辑,核心要解决 Android 后台限制、Firebase 消息类型适配以及 Delphi 与原生 Android 代码交互这几个问题,具体步骤如下:
1. 确保推送为「数据消息」而非「通知消息」
Android 系统对两类 Firebase 推送的处理逻辑完全不同:
- 通知消息:后台状态下由系统接管展示,不会触发应用代码,仅用户点击后才会唤醒应用。
- 数据消息:无论前台/后台,都会直接传递给应用的 Firebase 消息处理服务,是实现后台自动执行的前提。
推送 payload 示例(仅包含 data 字段):
{ "data": { "action": "run_task", "param1": "value1" }, "to": "目标设备Token" }
2. 自定义 FirebaseMessagingService 处理后台消息
Delphi 默认的 Firebase 消息处理在后台场景下存在限制,需自定义原生 Android Service 来接管消息接收:
步骤2.1 编写 Java 服务类
创建 MyFirebaseMessagingService.java,继承 FirebaseMessagingService 并重写 onMessageReceived 方法:
package com.yourcompany.yourapp; // 替换为你的应用包名 import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; import android.os.PowerManager; import android.content.Context; public class MyFirebaseMessagingService extends FirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { // 获取推送指令 String action = remoteMessage.getData().get("action"); // 唤醒设备,防止休眠中断任务 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp:PushWakeLock"); wakeLock.acquire(60000); // 锁定1分钟,可根据任务时长调整 try { // 触发Delphi端任务逻辑 if ("run_task".equals(action)) { DelphiPushCallback.executeTask(); } } finally { wakeLock.release(); } } }
将该类编译为 Jar 文件,放入 Delphi 项目的 libs 目录,并在项目选项「Android → Libraries」中添加此 Jar。
步骤2.2 配置 AndroidManifest
修改项目的 AndroidManifest.template.xml,添加权限、注册自定义服务:
<!-- 添加必要权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 注册自定义Firebase消息服务 --> <service android:name="com.yourcompany.yourapp.MyFirebaseMessagingService"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
3. Delphi 端实现 JNI 回调
通过 JNI 让 Java 服务调用 Delphi 代码,执行指定任务:
步骤3.1 编写 Delphi 回调单元
unit PushCallback; interface implementation uses Androidapi.JNIBridge, Androidapi.JNI.JavaTypes, Androidapi.Helpers, Androidapi.JNI.Os, System.SysUtils; // 供Java调用的任务执行方法 procedure ExecuteTask; cdecl; export; begin // 此处编写你需要自动运行的逻辑 // 例:启动后台服务、执行数据同步等 if TJBuild_VERSION.JavaClass.SDK_INT >= TJBuild_VERSION_CODES.JavaClass.O then TAndroidHelper.Context.startForegroundService( TJIntent.JavaClass.init(TAndroidHelper.Context, TMyBackgroundService.ClassContext) ) else TAndroidHelper.Context.startService( TJIntent.JavaClass.init(TAndroidHelper.Context, TMyBackgroundService.ClassContext) ); end; // 导出方法名需与Java调用路径一致:Java_包名_类名_方法名 exports ExecuteTask name 'Java_com_yourcompany_yourapp_DelphiPushCallback_executeTask'; end.
步骤3.2 处理 Android 8.0+ 后台限制
Android 8.0 及以上版本禁止后台长时间运行服务,需将任务放在前台服务中执行:
- 创建 Delphi 后台服务
TMyBackgroundService(继承TAndroidService) - 在服务的
OnCreate方法中启动前台通知:
procedure TMyBackgroundService.ServiceCreate(Sender: TObject); var ChannelID: JString; NotificationChannel: JNotificationChannel; NotificationManager: JNotificationManager; Builder: JNotificationCompat_Builder; begin ChannelID := StringToJString('background_task_channel'); // 创建通知渠道(Android 8.0+ 必需) if TJBuild_VERSION.JavaClass.SDK_INT >= TJBuild_VERSION_CODES.JavaClass.O then begin NotificationChannel := TJNotificationChannel.JavaClass.init( ChannelID, StringToJString('后台任务'), TJNotificationManager.JavaClass.IMPORTANCE_LOW ); NotificationManager := TJNotificationManager.Wrap( TAndroidHelper.Context.getSystemService(TJContext.JavaClass.NOTIFICATION_SERVICE) ); NotificationManager.createNotificationChannel(NotificationChannel); end; // 构建前台通知 Builder := TJNotificationCompat_Builder.JavaClass.init(TAndroidHelper.Context, ChannelID); Builder.setContentTitle(StringToJString('执行后台任务')); Builder.setContentText(StringToJString('处理推送请求')); Builder.setSmallIcon(TAndroidHelper.Context.getApplicationInfo.icon); // 启动前台服务 startForeground(1001, Builder.build); end;
4. 额外注意事项
- 将应用加入设备电池优化白名单,避免系统杀死后台服务。
- 测试时确保设备处于锁屏/后台状态,验证任务是否自动执行。
- 若任务耗时较短,可直接在
ExecuteTask中执行,无需启动前台服务。
内容的提问来源于stack exchange,提问作者Claudemir Passoni
相关产品推荐
相关产品推荐

