方案一

通过setComponentEnabledSetting方式,禁止掉应用的监听开机启动的广播组件。

代码如下:

getContext().getPackageManager().setComponentEnabledSetting(
                new ComponentName("包名", "组件名"),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);

缺点:

  1. 让组件不能再使用,除非设置成COMPONENT_ENABLED_STATE_ENABLED。
  2. 系统开关机仍然有效,但应用被卸载此属性会失效。

方案二

通过forceStopPackage方式,将应用stop掉。应用被stop后,stopped属性变为true,
如果应用没再被使用,开机启动时即使接收了开机广播应用也不会自启动。

代码如下:

private void setPackageForceStop(String pkg) {
	try {
		Method method = Class.forName("android.app.ActivityManager").getMethod("forceStopPackage", String.class);
		if (mActivityManager == null) {
			mActivityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
		}
		method.invoke(mActivityManager, pkg);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

缺点:

  • 如果该应用是系统应用,每次开机启动stopped属性会被置为false,即该应用能开机自启。
  • 同样的,如果该应用被卸载后重装也会导致stopped属性会被置为false,即该应用能开机自启。
  • 应用被stop后然后被使用,stopped属性会被置为false,即该应用能开机自启。

方案三

通过拦截应用的开机广播,不让应用接收到开机广播。
因开机广播是全局的、无序的广播,暂时没有办法做到拦截应用的开机广播
(系统端能做到,但这是应用层的业务,显然系统端不会做这样不合理的处理)。

方案四

通过禁止应用的开机广播权限,不让应用接收到开机广播。
此想法应该是,暂时没法拦截应用的开机广播,就想法禁止应用的开机广播权限。
总之,就是不想让应用接收到开机广播,但目前没有好的办法去禁止应用的开机广播权限。

总结

方案一和方案二是一般应用的实现方式,但两者都有一些小缺点,并且两者的实现都不能保证应用开机后不自启。
所以,无论采用方案一和方案二,目前能想到的最好方式还是,管理应用自启动的APK自己开机自启后,
stop掉被限制开机自启的应用,然后,如果此管理APK不必要,可以kill掉自己。

备注

  • 查看应用的stopped属性:dumpsys package com.tcl.tvweishi | grep stop
  • shell命令stop掉应用:am force-stop com.tcl.tvweishi