
简介本资源面向使用 Delphi XE10RAD Studio XE10进行 Android 跨平台开发的程序员聚焦于让应用在设备开机后自动运行这一常见需求。内容围绕 Android 系统的权限管理与启动服务配置展开涉及 BroadcastReceiver 监听 ACTION_BOOT_COMPLETED 广播、Service 后台组件编写以及 AndroidManifest 模板中 receiver、service 与 RECEIVE_BOOT_COMPLETED 权限的声明方式并包含 Delphi 与 Java 混合调用的实现思路适合具备一定 Delphi 与安卓基础、需要实现后台常驻功能的开发者参考。压缩包为 rar 格式共 15 个文件约 674KB涵盖 dproj、dpr、pas、fmx 等 Delphi 工程与界面源码deployproj、local、identcache 等部署与本地配置以及 xml、java、dex、class、jar、res、bat 等安卓清单、原生代码与构建资源。目前已有 777 人学习下载可帮助读者快速理解开机自启动的完整工程结构与关键配置位置。1. 开机自启动这件事在 Delphi Android 里到底卡在哪做过 Android 开机自启动的都知道这功能在 Java/Kotlin 里就是注册一个BOOT_COMPLETED广播接收器的事代码量不超过二十行。但换到 Delphi 的 FireMonkey 环境里情况完全不一样——你面对的是一个 Pascal 写的 Android 应用底层仍然跑在 JVM 上可你手上没有现成的AndroidManifest.template.xml编辑经验也不确定 Delphi 的 RTL 到底帮你封装了多少权限申请的逻辑。我见过太多人在这一步翻车广播注册了权限也加了开机后日志里能看到BOOT_COMPLETED确实发出去了但自己的应用就是纹丝不动。这个资源要解决的就是这个问题。它是一套完整的 Delphi Android 开机自启动实现方案包含权限声明、广播接收器注册、Delphi 侧的服务启动逻辑以及不同 Android 版本下的适配处理。适合已经能用 Delphi 编译出 Android APK、但对 Android 原生层机制不太熟悉的开发者。如果你正在做工业平板、自助终端、车载中控这类需要上电即启动的应用这套东西能帮你省掉至少两天的试错时间。2. 拆开看Delphi Android 自启动的完整链路2.1 从 BOOT_COMPLETED 到你的 Pascal 代码中间隔了几层Android 的开机自启动机制本身不复杂系统启动完成后ActivityManagerService会发出一个android.intent.action.BOOT_COMPLETED广播所有在 Manifest 里声明了接收该广播的应用都能收到。但 Delphi 应用和纯 Java 应用的区别在于你的入口点不是MainActivity而是 Delphi 的FMX.Platform.Android那一套初始化流程。整个链路是这样的系统发广播 → 你的BroadcastReceiver收到 → 在onReceive里启动一个Service或Activity→ Delphi 的运行时被拉起 → 你的 Pascal 代码开始执行。关键卡点在于第三步和第四步之间如果你直接在onReceive里启动主 ActivityAndroid 10 以上会限制后台启动 Activity必须走Service或者用PendingIntent配合通知。这是很多人第一次做自启动时最容易忽略的地方。Delphi 这边System.Android.Service单元提供了TLocalServiceConnection和TAndroidService的封装但它的文档极少参数含义基本靠猜。我一般会先确认三件事Manifest 里receiver的android:exported属性、RECEIVE_BOOT_COMPLETED权限是否声明、以及目标 SDK 版本是否在AndroidManifest.template.xml里正确设置。2.2 权限声明与 Manifest 模板的修改Delphi 的 Android 项目不会直接给你一个AndroidManifest.xml而是通过AndroidManifest.template.xml在编译时生成。这个文件通常位于项目目录下文件名就是AndroidManifest.template.xml。你需要在这个模板里加入权限声明和接收器注册。!-- AndroidManifest.template.xml 中需要添加的内容 -- uses-permission android:nameandroid.permission.RECEIVE_BOOT_COMPLETED / receiver android:namecom.embarcadero.firemonkey.BootReceiver android:enabledtrue android:exportedtrue intent-filter android:priority1000 action android:nameandroid.intent.action.BOOT_COMPLETED / action android:nameandroid.intent.action.QUICKBOOT_POWERON / /intent-filter /receiver这里有几个参数需要解释。android:exportedtrue是必须的因为BOOT_COMPLETED是系统发出的广播接收器必须对外暴露才能收到。Android 12 以后如果不显式声明exported编译会直接报错。android:priority1000是设置优先级数值越高越早收到广播但注意这个值在 Android 8.0 以后对隐式广播不再生效写上去主要是为了兼容老版本。QUICKBOOT_POWERON是部分厂商如小米、OPPO的快速开机广播加上它能提高在国产 ROM 上的成功率。但光有 Manifest 还不够。Delphi 的BootReceiver类并不存在你需要自己用 Java 写一个或者用 Delphi 的JNI桥接。常见做法是创建一个 Java 类继承BroadcastReceiver在onReceive里通过Intent启动 Delphi 的TLocalService。2.3 用 Java 桥接层写一个可靠的 BootReceiverDelphi 本身不提供现成的BroadcastReceiver实现所以你需要写一个 Java 类然后把它编译进 APK。具体做法是在 Delphi 项目里创建一个Java文件夹放入你的.java文件Delphi 编译时会自动调用javac把它编译成.class并打包。// BootReceiver.java package com.example.bootstart; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Build; public class BootReceiver extends BroadcastReceiver { Override public void onReceive(Context context, Intent intent) { String action intent.getAction(); if (Intent.ACTION_BOOT_COMPLETED.equals(action) || android.intent.action.QUICKBOOT_POWERON.equals(action)) { // 启动 Delphi 的主 Activity Intent launchIntent new Intent(context, com.embarcadero.firemonkey.FMXNativeActivity.class); launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (Build.VERSION.SDK_INT Build.VERSION_CODES.Q) { // Android 10 需要额外处理后台启动限制 launchIntent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); } context.startActivity(launchIntent); } } }这段代码的逻辑很直接收到开机广播后构造一个指向 Delphi 主 Activity 的Intent加上FLAG_ACTIVITY_NEW_TASK标志然后启动。FLAG_ACTIVITY_NEW_TASK是必须的因为BroadcastReceiver的上下文不是 Activity没有任务栈不加这个标志会直接抛异常。Android 10 以上额外加的FLAG_ACTIVITY_BROUGHT_TO_FRONT是为了让应用从后台回到前台时更顺畅减少被系统拦截的概率。参数方面com.embarcadero.firemonkey.FMXNativeActivity是 Delphi FireMonkey 应用的标准入口 Activity 类名不要改成你自己的类名除非你明确知道自己在做什么。QUICKBOOT_POWERON这个 action 字符串在不同厂商的 ROM 里可能略有差异但主流的就是这个写法。2.4 Delphi 侧的服务启动与延迟策略Java 层把 Activity 拉起来之后Delphi 的运行时开始初始化。但这里有个坑开机时系统资源紧张如果你的应用在onCreate里做了大量初始化工作可能会被系统判定为无响应而杀掉。我一般会在 Delphi 的FormCreate里加一个延迟让主线程先喘口气。// 在 Delphi 主窗体的 OnCreate 事件中 procedure TMainForm.FormCreate(Sender: TObject); begin // 延迟 3 秒再执行初始化避开开机高峰 TThread.CreateAnonymousThread( procedure begin Sleep(3000); TThread.Synchronize(nil, procedure begin // 这里放你的初始化代码 InitializeApp; end); end).Start; end;这段代码用了一个匿名线程做延迟Sleep(3000)让初始化推迟三秒执行然后通过TThread.Synchronize回到主线程。为什么要这样做因为开机后的前几秒CPU 和 IO 都在满负荷处理系统服务你的应用如果在这时候抢资源很容易被ActivityManager标记为ANR或者直接Force Stop。延迟三秒是个经验值实测在大多数设备上能显著提高存活率。TThread.CreateAnonymousThread是 Delphi 里创建轻量级线程的常用方式不需要手动管理线程生命周期。TThread.Synchronize确保 UI 相关的操作回到主线程执行避免线程安全问题。如果你的初始化逻辑不涉及 UI可以用TThread.Queue代替性能更好。3. 避坑指南五个让自启动失效的常见原因3.1 现象广播收到了但 Activity 没起来原因Android 10 及以上版本对后台启动 Activity 有严格限制BroadcastReceiver里直接startActivity会被系统静默拦截日志里能看到Background activity start blocked的警告。解决改用Service作为中转在Service的onStartCommand里再启动 Activity或者使用PendingIntent配合通知。如果必须直接启动 Activity确保应用在电池优化白名单里并且targetSdkVersion不要超过 29。3.2 现象国产 ROM 上完全收不到广播原因小米、OPPO、vivo 等厂商的 ROM 对自启动有额外的权限控制即使 Manifest 里声明了RECEIVE_BOOT_COMPLETED用户没有手动在系统设置里允许自启动广播也不会送达。解决在应用首次启动时引导用户去系统设置里开启自启动权限。可以通过Intent跳转到厂商的自启动管理页面但不同厂商的页面路径不一样需要做适配。常见做法是弹一个对话框告诉用户去「设置 → 应用管理 → 自启动」里手动打开。3.3 现象编译报错AndroidManifest.xml中receiver缺少exported属性原因Android 12API 31开始所有在 Manifest 里声明的组件如果包含intent-filter必须显式声明android:exported否则编译直接失败。解决在AndroidManifest.template.xml里给receiver加上android:exportedtrue。注意如果你的targetSdkVersion低于 31这个属性不是强制的但建议加上避免后续升级 SDK 时再改。3.4 现象应用启动后闪退日志显示ClassNotFoundException原因Java 桥接层的类名和 Manifest 里注册的android:name不一致或者 Java 文件没有被正确编译进 APK。解决检查AndroidManifest.template.xml里receiver的android:name是否和 Java 类的完整包名一致。另外确认 Java 文件放在 Delphi 项目的Java文件夹下并且文件名和类名相同。Delphi 编译时会在output目录下生成classes.dex可以用unzip解压 APK 确认 Java 类是否被打包进去。3.5 现象自启动成功但应用界面卡死原因Delphi 的FMXNativeActivity在开机时被拉起但Application.OnActivate或FormCreate里的代码执行时间过长导致主线程阻塞。解决把所有耗时操作放到线程里主线程只做 UI 初始化。如果必须在FormCreate里做初始化用上面提到的延迟策略并且把初始化拆成多个小步骤每步之间让出 CPU 时间。4. 进阶技巧用日志和 adb 验证自启动是否真正生效4.1 用 adb 模拟开机广播不需要真的重启设备用 adb 就能模拟BOOT_COMPLETED广播快速验证接收器是否注册成功。# 模拟开机广播 adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -p com.example.bootstart # 查看广播是否被接收 adb logcat | grep -i BootReceiver\|BOOT_COMPLETED第一条命令里的-p参数指定你的应用包名确保广播只发给你自己的应用。第二条命令过滤日志如果BootReceiver的onReceive被触发日志里会打印你加的Log.d信息。这个方法的局限在于它绕过了系统的权限检查所以即使广播被接收也不代表真实开机时一定能收到。但它能帮你快速排除代码层面的问题。4.2 用dumpsys检查接收器注册状态adb shell dumpsys package com.example.bootstart | grep -A 5 Receiver这条命令会输出你应用里所有注册的Receiver信息包括intent-filter里的 action。如果BOOT_COMPLETED没有出现在输出里说明 Manifest 的修改没有生效需要检查AndroidManifest.template.xml是否被正确编译。4.3 不同 Android 版本的适配对照表Android 版本关键限制适配方案7.0 及以下无特殊限制直接startActivity即可8.0 - 9.0隐式广播受限但BOOT_COMPLETED在白名单里正常注册即可注意后台服务限制10 - 11后台启动 Activity 被拦截改用Service中转或PendingIntent12 及以上exported属性强制声明Manifest 里显式加android:exported13 及以上通知权限需要动态申请如果自启动后要弹通知先申请POST_NOTIFICATIONS这张表是我在实际项目里踩坑后整理的每个版本的限制都对应着具体的报错日志。比如 Android 10 的后台启动限制日志里会明确写Background activity start blocked看到这个就知道要改方案了。4.4 一个容易被忽略的细节targetSdkVersion的影响Delphi 项目里targetSdkVersion是在AndroidManifest.template.xml里通过%%targetSdkVersion%%占位符替换的实际值在项目选项的Version Info里设置。很多人改了这个值但忘了同步修改 Manifest 模板导致编译出来的 APK 里 SDK 版本和预期不一致。我一般会在编译后解压 APK用aapt dump badging确认targetSdkVersion的实际值。aapt dump badging your_app.apk | grep targetSdkVersion如果输出的值和你在 Delphi 里设置的不一样说明 Manifest 模板里的占位符没有被正确替换需要检查模板文件里是否写了%%targetSdkVersion%%。从那以后我每次做自启动相关的改动都会先用adb shell am broadcast跑一遍再dumpsys确认注册状态最后才真机重启验证。这套流程走下来基本能覆盖九成以上的问题。希望帮到你。本文还有配套的精品资源点击获取