Delphi 10.3如何在Android Oreo中启动前台服务?
在Delphi 10.3中实现Android Oreo前台服务的完整方案
我来帮你搞定这个问题——Android Oreo(API 26+)对后台服务的限制确实挺严格的,你现在的代码只是启动了普通服务,还没适配前台服务的要求,下面分应用端和服务端一步步给你调整:
一、应用端:改用startForegroundService启动服务
原来用TLocalServiceConnection.StartService在Oreo及以上版本会被系统限制,必须判断系统版本,调用Android原生的startForegroundService方法:
uses Androidapi.JNI.App, Androidapi.JNI.Os, Androidapi.Helpers, Androidapi.JNI.GraphicsContentViewText; // 替换你原来的启动服务代码 procedure TMainForm.StartMyService; var LIntent: JIntent; begin // 判断Android版本是否为Oreo及以上 if TJBuild_VERSION.JavaClass.SDK_INT >= TJBuild_VERSION_CODES.JavaClass.O then begin // 构建启动服务的Intent,这里的TJDM是你服务类(TDM)对应的Java类 LIntent := TJIntent.JavaClass.init(TAndroidHelper.Context, TJDM.JavaClass); // 调用前台服务启动方法 TAndroidHelper.Context.startForegroundService(LIntent); end else begin // 低版本继续用原来的TLocalServiceConnection方式 FService := TLocalServiceConnection.Create; FService.StartService('MySvc'); end; end;
二、服务端:在AndroidServiceStartCommand中启动前台
服务启动后必须在5秒内调用startForeground,否则系统会直接杀死服务,同时Oreo要求通知必须绑定通知渠道,所以我们需要先创建渠道,再构建通知:
1. 先添加创建通知渠道的方法
在你的TDM类中新增一个私有方法:
procedure TDM.CreateNotificationChannel; var LChannel: JNotificationChannel; LNotificationManager: JNotificationManager; begin if TJBuild_VERSION.JavaClass.SDK_INT >= TJBuild_VERSION_CODES.JavaClass.O then begin // 获取通知管理器 LNotificationManager := TJNotificationManager.Wrap( TAndroidHelper.Context.getSystemService(TJContext.JavaClass.NOTIFICATION_SERVICE)); // 创建通知渠道,ID和名称可以自定义 LChannel := TJNotificationChannel.JavaClass.init( 'ForegroundService_Channel', StrToJCharSequence('前台服务通知'), TJNotificationManager.JavaClass.IMPORTANCE_LOW); // 选低重要性避免打扰用户 LChannel.setDescription(StrToJCharSequence('用于维持前台服务运行')); // 注册渠道 LNotificationManager.createNotificationChannel(LChannel); end; end;
2. 修改AndroidServiceStartCommand方法
更新你的服务启动命令处理逻辑,加入前台服务的启动代码:
function TDM.AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent; Flags, StartId: Integer): Integer; var LNotificationBuilder: JNotificationCompat_Builder; LNotification: JNotification; LPendingIntent: JPendingIntent; LLaunchIntent: JIntent; LIconResId: Integer; begin // 第一步:创建通知渠道(Oreo+必需) CreateNotificationChannel; // 第二步:构建点击通知后打开主界面的Intent LLaunchIntent := TAndroidHelper.Context.getPackageManager.getLaunchIntentForPackage( TAndroidHelper.Context.getPackageName); LPendingIntent := TJPendingIntent.JavaClass.getActivity(TAndroidHelper.Context, 0, LLaunchIntent, 0); // 第三步:获取通知小图标(注意要用符合Android规范的白色透明图标) LIconResId := TAndroidHelper.Context.getResources.getIdentifier('ic_launcher', 'drawable', TAndroidHelper.Context.getPackageName); // 第四步:构建前台通知 LNotificationBuilder := TJNotificationCompat_Builder.JavaClass.init(TAndroidHelper.Context, 'ForegroundService_Channel'); LNotificationBuilder.setContentTitle(StrToJCharSequence('我的前台服务')) .setContentText(StrToJCharSequence('服务正在后台运行')) .setSmallIcon(LIconResId) .setContentIntent(LPendingIntent) .setOngoing(True); // 设置为不可手动取消,除非服务停止 // 第五步:启动前台服务,第一个参数是通知ID(只要唯一就行) startForeground(1001, LNotificationBuilder.build); // 保持服务被杀死后自动重启 Result := TJService.JavaClass.START_STICKY; end;
3. 服务停止时清理前台状态
在TDM的AndroidServiceDestroy事件中添加停止前台的代码,避免通知残留:
procedure TDM.AndroidServiceDestroy(Sender: TObject); begin // 停止前台服务并移除通知 stopForeground(True); end;
三、必要的权限配置
别忘了在AndroidManifest中添加前台服务权限:
- 打开Project -> Options -> Application -> Permissions
- 勾选
FOREGROUND_SERVICE权限(如果找不到,也可以手动编辑AndroidManifest.xml,添加<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />)
几个关键注意点:
- 调用
startForegroundService后,服务必须在5秒内调用startForeground,否则系统会终止服务 - 通知小图标必须符合Android规范(白色透明背景),否则通知可能显示异常
- 如果你需要停止服务,记得调用
stopSelf()或者stopService(),同时会触发stopForeground
内容的提问来源于stack exchange,提问作者Micha
相关产品推荐
相关产品推荐

