最近有个需求要求app要开机自启动,就按照一般的套路去注册了一个静态广播接收器,代码如下:
manifest文件:
<receiver android:name=".receiver.StartupReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
java文件:
[java] view plain copy
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ByLog.i(intent.getAction());
//开机启动
Intent mainIntent = new Intent(context, MainActivity.class);
//在BroadcastReceiver中显示Activity,必须要设置FLAG_ACTIVITY_NEW_TASK标志
mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(mainIntent);
}
}
OK,运行然后重启。。。然而并没有作用。换了几个姿势重新重启。。。然而并没有作用。
google了一下,应该是没有添加
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
的缘故,于是添加上这行代码继续测试。。。然而并没有作用!!!
OK,继续google。但是google来google去得到的的结论都差不多,只要按照上面的套路来就可以接收到开机广播了。期间在stackoverflow一篇问答上看到有的说法是要加上
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
于是尝试了。。。然而并没有作用。
然后,我想到了可能是权限的问题,可能自启动权限被系统禁用了,于是到应用管理里面找到自家的app,进入权限设置页,没有自启动这一选项啊。。。那可能就是手机的问题了,因为刚才用来测试的是国产机。。。可能有改了些什么系统代码(stackoverflow 有一篇问答上就有提到小米和htc使用了非常规或者自定义的开机广播action)。。。于是就换了一部机子测试,通过了!!!!
冷静下来仔细想想,发现还有个解释不通的地方:第一部机子开机时留意到某些软件是可以开机自启的(启动后马上在通知栏里面出现了),也就是说我的app应该也可以在那部机子上开机自启的才对。于是抱着学习的心态去反编译了那些软件,结果发现它们不仅仅接受BOOT_COMPLETED广播,同时还接收了NEW_OUTGOING_CALL、PHONE_STATE、CONNECTIVITY_CHANGE,难怪。。。但我不能这么做啊,它那个只是在通知栏里面通知,我这是要启动app的。。。
想不通啊,最后想来想去觉得最有可能还是设置里面某些选项禁掉了开机启动,于是在设置里面一项一项仔细的找,然后我看到了应用权限页面里有个设置单项权限的菜单,想着设置单项跟外面的一起列出来的应该是一样的权限选项才对(之前也是这么想的,所以就没点进去),但是点进去一看,里面竟然就有外面没列出的应用自动启动选项 !!!我顿时就忍不住爆粗了。。。把这个选项打开,测试,毫无悬念的通过了。。。
开机自启这个是通过了,但是还有个问题就是开机之后一般都会停留在锁屏页且短时间内没有进行解锁操作屏幕会进入休眠状态,之后要手动操作进到系统才能看到打开的app,这个不能放着不管。于是又只能靠google了,花费了些时间,终于找到了解决方法(改源码那些解决方法我就不用想了,暂时做不到T_T),就是在app启动时,主动唤醒屏幕并解锁,代码如下:
//屏幕唤醒
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.SCREEN_DIM_WAKE_LOCK, "StartupReceiver");//最后的参数是LogCat里用的Tag
wl.acquire();
//屏幕解锁
KeyguardManager km= (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock kl = km.newKeyguardLock("StartupReceiver");//参数是LogCat里用的Tag
kl.disableKeyguard();
到此,开机自启的这块需求就算是完成了。最后附上完整的代码:
manifest文件:
记得要添加权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> ```
```xml
<receiver android:name=".receiver.StartupReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver> ```
java文件:
```java
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ByLog.i(intent.getAction());
//开机后一般会停留在锁屏页面且短时间内没有进行解锁操作屏幕会进入休眠状态,此时就需要先唤醒屏幕和解锁屏幕
//屏幕唤醒
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.SCREEN_DIM_WAKE_LOCK, "StartupReceiver");//最后的参数是LogCat里用的Tag
wl.acquire();
//屏幕解锁
KeyguardManager km= (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock kl = km.newKeyguardLock("StartupReceiver");//参数是LogCat里用的Tag
kl.disableKeyguard();
//开机启动
Intent mainIntent = new Intent(context, MainActivity.class);
//在BroadcastReceiver中显示Activity,必须要设置FLAG_ACTIVITY_NEW_TASK标志
mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(mainIntent);
}
}
在解决开机自启的问题时发现了一篇文章,觉得里面提到的自启动失败的原因总结的很好,后面的adb发送广播更是省下了很多操作,节约了很多时间,在这里摘录(略有修改)一下以防以后找不到:
2、自启动失败的原因
接收不到BOOT_COMPLETED广播可能的原因
- BOOT_COMPLETED对应的action和uses-permission("android.permission.RECEIVE_BOOT_COMPLETED" )没有一起添加
- 应用安装到了sd卡内,安装在sd卡内的应用是收不到BOOT_COMPLETED广播的,可以在manifest节点下添加android:installLocation="internalOnly"来指定只能安装在手机内存里面,也可以监听开机加载sd卡的广播,可惜有的手机是没有sd卡的。。。
- 系统开启了Fast Boot模式,这种模式下系统启动并不会发送BOOT_COMPLETED广播
- 应用程序安装后重来没有启动过,这种情况下应用程序接收不到任何广播,包括BOOT_COMPLETED、ACTION_PACKAGE_ADDED、CONNECTIVITY_ACTION等等。
Android3.1之后,系统为了加强了安全性控制,应用程序安装后或是(设置)应用管理中被强制关闭后处于stopped状态,在这种状态下接收不到任何广播,除非广播带有FLAG_INCLUDE_STOPPED_PACKAGES标志,而默认所有系统广播都是FLAG_EXCLUDE_STOPPED_PACKAGES的,所以就没法通过系统广播自启动了。所以Android3.1之后
- 应用程序无法在安装后自己启动
- 没有ui的程序必须通过其他应用激活才能启动,如它的Activity、Service、Content Provider被其他应用调用。
存在一种例外,就是应用程序被adb push you.apk /system/app/下是会自动启动的,不处于stopped状态。
具体说明见:
http://developer.android.com/about/versions/android-3.1.html#launchcontrols
http://commonsware.com/blog/2011/07/13/boot-completed-regression-confirmed.html
3、adb发送BOOT_COMPLETED
我们可以通过 adb shell am broadcast -a android.intent.action.BOOT_COMPLETED命令发送BOOT_COMPLETED广播,而不用重启测试机或模拟器来测试BOOT_COMPLETED广播(用真机测过,还是会重启的,所以推荐后面的指定包名命令),以下命令可以更精确的发送到某个package,如下:
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -c android.intent.category.HOME -n package_name/class_name