Delphi开发App适配Android 8(API26)后后台推送失效求助
解决Delphi中targetSdkVersion升级到26后推送通知失效的问题
Hey Juan, 我之前在Delphi开发Android应用时也碰到过完全一样的问题——升级targetSdkVersion到26后,后台推送直接罢工,折腾了好一阵才搞定。结合Android 8.0的新限制和Delphi的适配逻辑,给你梳理下问题根源和解决办法:
问题根源
你猜的没错,Android 8.0(API 26)的后台执行限制和通知渠道强制要求是核心原因:
- 后台服务限制:Android O彻底收紧了后台服务的运行权限,之前依赖后台静默服务接收推送的逻辑会被系统直接终止
- 通知渠道要求:从O开始,所有推送通知必须绑定到一个已创建的通知渠道,没有渠道的通知系统会直接忽略,根本不会展示给用户
分步解决方案
1. 先搞定通知渠道(最关键的第一步)
在应用启动时必须创建对应的通知渠道,否则任何推送都无法显示。在Delphi里可以这么写:
uses Androidapi.JNI.App, Androidapi.JNI.Os, Androidapi.Helpers; procedure TMainForm.FormCreate(Sender: TObject); begin CreateNotificationChannel; end; procedure TMainForm.CreateNotificationChannel; var NotificationManager: JNotificationManager; Channel: JNotificationChannel; ChannelID, ChannelName, ChannelDesc: string; begin // 只在Android 8.0及以上版本执行 if TJBuild_VERSION.JavaClass.SDK_INT >= TJBuild_VERSION_CODES.JavaClass.O then begin ChannelID := 'push_notification_channel'; ChannelName := '推送通知'; ChannelDesc := '接收应用的推送消息'; // 获取通知管理器实例 NotificationManager := TJNotificationManager.Wrap( TAndroidHelper.Context.getSystemService(TJContext.JavaClass.NOTIFICATION_SERVICE)); // 创建渠道 Channel := TJNotificationChannel.JavaClass.init( StringToJString(ChannelID), StringToJString(ChannelName), TJNotificationManager.JavaClass.IMPORTANCE_DEFAULT); Channel.setDescription(StringToJString(ChannelDesc)); // 注册渠道到系统 NotificationManager.createNotificationChannel(Channel); end; end;
记得在推送时指定这个渠道ID,比如构建通知时调用setChannelId(StringToJString('push_notification_channel'))。
2. 调整推送服务的运行方式
如果你的推送是自定义的后台服务,现在必须改成前台服务才能在后台存活:
- 在服务的
onCreate或onStartCommand方法里调用startForeground(),绑定一个低优先级的通知(避免打扰用户):
procedure TMyPushService.ServiceCreate(Sender: TObject); var Notification: JNotification; begin if TJBuild_VERSION.JavaClass.SDK_INT >= TJBuild_VERSION_CODES.JavaClass.O then begin // 构建前台服务通知(用之前创建的渠道ID) Notification := TJNotificationCompat_Builder.JavaClass.init(TAndroidHelper.Context, StringToJString('push_notification_channel')) .setContentTitle(StringToJString('应用运行中')) .setContentText(StringToJString('正在接收推送')) .setSmallIcon(ResourceIDToJDrawable(Icon)) .build; // 启动前台服务,通知ID随便设一个不重复的数字 startForeground(1001, Notification); end; end;
- 更推荐的做法是迁移到Firebase Cloud Messaging(FCM):Delphi官方对FCM有完善支持,FCM会通过系统级的服务处理推送,完全不受Android O的后台限制影响,适配成本更低。
3. 补全AndroidManifest的权限和配置
- 新增前台服务权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
- 如果用FCM,确保Manifest里包含FCM的接收器和服务配置(Delphi的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="${applicationId}" /> </intent-filter> </receiver> <service android:name="com.google.firebase.iid.FirebaseInstanceIdService" android:exported="true"> <intent-filter android:priority="-500"> <action android:name="com.google.firebase.INSTANCE_ID_EVENT" /> </intent-filter> </service>
测试注意事项
- 一定要在Android 8.0+的设备上测试,模拟后台状态(按Home键退出,或者强制停止应用后触发推送)
- 尽量不要依赖旧版SDK(24.3.3)的兼容逻辑,建议升级Delphi的Android SDK组件到API 26及以上,减少兼容性坑
按照这些步骤调整后,你的推送应该就能正常工作了,而且能满足Google Play的targetSdkVersion要求。
内容的提问来源于stack exchange,提问作者Juan M
相关产品推荐
相关产品推荐

