Android开机自启报错:ActivityNotFoundException求助
这个场景我太熟悉了——把应用塞进system/app后开机就崩,手动打开却正常,核心问题出在系统应用开机时的类加载机制和普通应用完全不一样,尤其是你通过MainActivity$Companion启动Activity的方式,在开机阶段踩了类加载的坑。
下面是一步步的排查和解决方法:
1. 改掉通过Companion类启动Activity的写法
如果你的BootReceiver里是调用MainActivity.Companion的方法来启动Activity(比如Kotlin里的伴生对象方法),那大概率是这里出问题了。开机时系统类加载器还没完全初始化你的应用类,伴生对象Companion作为静态内部类,可能还没被加载,直接调用它会触发ActivityNotFoundException(其实本质是找不到Companion类,但报错信息会误导你是找不到Activity)。
把启动代码改成直接指向MainActivity本身,同时必须加FLAG_ACTIVITY_NEW_TASK(因为广播上下文没有任务栈):
// 错误写法(通过Companion) // MainActivity.Companion.start(context) // 正确写法 val intent = Intent(context, MainActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(intent)
2. 确保Manifest里的组件声明完全正确
系统应用对组件的exported属性要求更严格,哪怕你的API低于30,也要明确设置:
- BootReceiver必须exported:因为开机广播是系统从外部发送的,不设置的话系统无法触发它
- MainActivity必须exported:系统应用的Activity如果要被外部(这里是广播)启动,必须明确开放
示例Manifest代码:
<!-- BootReceiver声明 --> <receiver android:name=".BootReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- 加上这个适配快速开机场景 --> <action android:name="android.intent.action.QUICKBOOT_POWERON" /> </intent-filter> </receiver> <!-- MainActivity声明 --> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
3. 检查系统应用的签名和权限
你说应用已经签名,但系统应用需要和ROM同签名的系统签名,普通的debug/release签名放到system/app后,会有类加载、权限的隐性问题。可以做两个验证:
- 查看应用的sharedUserId:如果你的应用需要系统级权限,在Manifest里添加
android:sharedUserId="android.uid.system"(必须配合系统签名才能生效) - 确认签名文件:用系统ROM的签名文件重新签名你的APK,再放到
system/app里测试
4. 排查Companion类的潜在问题
如果一定要用Companion类启动,检查它的静态代码块或初始化逻辑:有没有依赖开机时还未就绪的系统服务(比如LocationManager、PackageManager)?有没有耗时操作?这些在开机阶段都会导致类初始化失败,进而触发崩溃。
调试小技巧
用adb logcat过滤你的包名,看更详细的报错栈,能定位到具体是Companion类的哪一行出问题:
adb logcat -s YourPackageName:V *:E
内容的提问来源于stack exchange,提问作者Ahmet KAYGISIZ

