程序化安装应用时MY_PACKAGE_REPLACED广播未触发问题排查
这问题我之前也碰到过!咱们来拆解一下:
首先,为什么adb install -r能触发MY_PACKAGE_REPLACED广播,而root下的pm install -r不行?核心原因大概率是两种安装方式的系统流程差异,或者广播接收的时机问题:
可能的问题根源
广播发送/接收的时机冲突
当你在自己的应用里通过su执行pm install -r时,安装过程中系统会直接杀死你的应用进程(因为要替换APK)。而MY_PACKAGE_REPLACED广播是在安装完成后发送的,这时候系统可能还没来得及重新拉起你的应用进程来触发静态接收器,或者广播发送时你的进程已经被杀死,导致接收器无法响应。root安装的流程跳过了广播触发
虽然pm install -r理论上应该触发完整的安装流程,但以root权限执行时,系统可能跳过了某些面向普通应用的广播发送逻辑——毕竟root操作属于系统级行为,部分应用级的通知可能被省略。接收器注册方式不对
如果你的接收器是动态注册的(比如在Activity里用registerReceiver),那应用进程被杀死后接收器就失效了,肯定收不到广播。必须用静态注册(在AndroidManifest.xml里声明)才能让系统在应用未运行时拉起进程接收广播。
解决办法
办法1:确保接收器是静态注册
先检查你的AndroidManifest.xml,接收器必须这样声明:
<receiver android:name=".MyPackageReplacedReceiver"> <intent-filter> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> </intent-filter> </receiver>
如果之前是动态注册,改成静态注册后再试试。
办法2:放弃广播,手动在安装完成后启动应用
既然pm install -r是阻塞式命令(会等到安装完成才返回),你可以直接等待命令执行结束,根据退出码判断安装成功后手动启动应用,这比依赖广播更可靠:
try { String installCmd = "pm install -r /mnt/sdcard/Download/app-debug.apk"; Process process = Runtime.getRuntime().exec(new String[]{"su", "-c", installCmd}); int exitCode = process.waitFor(); // 等待安装完成 if (exitCode == 0) { // 安装成功,获取应用启动Intent Intent launchIntent = getPackageManager().getLaunchIntentForPackage("io.my.package"); if (launchIntent != null) { launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 必须加这个标志,因为当前进程可能已经被杀死 startActivity(launchIntent); } } else { Log.e("AppInstall", "安装失败,退出码:" + exitCode); } } catch (IOException | InterruptedException e) { e.printStackTrace(); }
调试小技巧
你可以用logcat确认广播是否真的发送了:
adb logcat | grep "MY_PACKAGE_REPLACED"
如果执行pm install -r后没有任何相关日志,说明系统确实没发这个广播,那手动启动就是最优解。
内容的提问来源于stack exchange,提问作者Moshe Yamini

