最近有個需求要求app要開機自啟動蔑赘,就按照一般的套路去注冊了一個靜態(tài)廣播接收器狸驳,代碼如下:
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" />
的緣故施无,于是添加上這行代碼繼續(xù)測試。必孤。猾骡。然而并沒有作用!7筇隆兴想!
OK,繼續(xù)google购啄。但是google來google去得到的的結論都差不多襟企,只要按照上面的套路來就可以接收到開機廣播了。期間在stackoverflow一篇問答上看到有的說法是要加上
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
于是嘗試了狮含。顽悼。。然而并沒有作用几迄。
然后蔚龙,我想到了可能是權限的問題,可能自啟動權限被系統(tǒng)禁用了映胁,于是到應用管理里面找到自家的app木羹,進入權限設置頁,沒有自啟動這一選項啊。坑填。抛人。那可能就是手機的問題了,因為剛才用來測試的是國產(chǎn)機脐瑰。妖枚。〔栽冢可能有改了些什么系統(tǒng)代碼(stackoverflow 有一篇問答上就有提到小米和htc使用了非常規(guī)或者自定義的開機廣播action)绝页。。寂恬。于是就換了一部機子測試续誉,通過了!3跞狻?嵫弧!
冷靜下來仔細想想朴译,發(fā)現(xiàn)還有個解釋不通的地方:第一部機子開機時留意到某些軟件是可以開機自啟的(啟動后馬上在通知欄里面出現(xiàn)了)井佑,也就是說我的app應該也可以在那部機子上開機自啟的才對。于是抱著學習的心態(tài)去反編譯了那些軟件眠寿,結果發(fā)現(xiàn)它們不僅僅接受BOOT_COMPLETED廣播躬翁,同時還接收了NEW_OUTGOING_CALL、PHONE_STATE盯拱、CONNECTIVITY_CHANGE盒发,難怪。狡逢。宁舰。但我不能這么做啊,它那個只是在通知欄里面通知奢浑,我這是要啟動app的蛮艰。。雀彼。
想不通啊壤蚜,最后想來想去覺得最有可能還是設置里面某些選項禁掉了開機啟動,于是在設置里面一項一項仔細的找徊哑,然后我看到了應用權限頁面里有個設置單項權限的菜單袜刷,想著設置單項跟外面的一起列出來的應該是一樣的權限選項才對(之前也是這么想的,所以就沒點進去)莺丑,但是點進去一看著蟹,里面竟然就有外面沒列出的應用自動啟動選項 !!萧豆!我頓時就忍不住爆粗了奸披。。炕横。把這個選項打開源内,測試,毫無懸念的通過了份殿。。嗽交。
開機自啟這個是通過了卿嘲,但是還有個問題就是開機之后一般都會停留在鎖屏頁且短時間內沒有進行解鎖操作屏幕會進入休眠狀態(tài),之后要手動操作進到系統(tǒng)才能看到打開的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");//最后的參數(shù)是LogCat里用的Tag
wl.acquire();
//屏幕解鎖
KeyguardManager km= (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock kl = km.newKeyguardLock("StartupReceiver");//參數(shù)是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());
//開機后一般會停留在鎖屏頁面且短時間內沒有進行解鎖操作屏幕會進入休眠狀態(tài)左医,此時就需要先喚醒屏幕和解鎖屏幕
//屏幕喚醒
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.SCREEN_DIM_WAKE_LOCK, "StartupReceiver");//最后的參數(shù)是LogCat里用的Tag
wl.acquire();
//屏幕解鎖
KeyguardManager km= (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock kl = km.newKeyguardLock("StartupReceiver");//參數(shù)是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);
}
}
在解決開機自啟的問題時發(fā)現(xiàn)了一篇文章同木,覺得里面提到的自啟動失敗的原因總結的很好浮梢,后面的adb發(fā)送廣播更是省下了很多操作,節(jié)約了很多時間彤路,在這里摘錄(略有修改)一下以防以后找不到:
2秕硝、自啟動失敗的原因
接收不到BOOT_COMPLETED廣播可能的原因
- BOOT_COMPLETED對應的action和uses-permission("android.permission.RECEIVE_BOOT_COMPLETED" )沒有一起添加
- 應用安裝到了sd卡內,安裝在sd卡內的應用是收不到BOOT_COMPLETED廣播的洲尊,可以在manifest節(jié)點下添加android:installLocation="internalOnly"來指定只能安裝在手機內存里面远豺,也可以監(jiān)聽開機加載sd卡的廣播,可惜有的手機是沒有sd卡的颊郎。憋飞。。
- 系統(tǒng)開啟了Fast Boot模式姆吭,這種模式下系統(tǒng)啟動并不會發(fā)送BOOT_COMPLETED廣播
- 應用程序安裝后重來沒有啟動過榛做,這種情況下應用程序接收不到任何廣播,包括BOOT_COMPLETED、ACTION_PACKAGE_ADDED检眯、CONNECTIVITY_ACTION等等厘擂。
Android3.1之后,系統(tǒng)為了加強了安全性控制锰瘸,應用程序安裝后或是(設置)應用管理中被強制關閉后處于stopped狀態(tài)刽严,在這種狀態(tài)下接收不到任何廣播,除非廣播帶有FLAG_INCLUDE_STOPPED_PACKAGES標志避凝,而默認所有系統(tǒng)廣播都是FLAG_EXCLUDE_STOPPED_PACKAGES的舞萄,所以就沒法通過系統(tǒng)廣播自啟動了。所以Android3.1之后
- 應用程序無法在安裝后自己啟動
- 沒有ui的程序必須通過其他應用激活才能啟動管削,如它的Activity倒脓、Service、Content Provider被其他應用調用含思。
存在一種例外崎弃,就是應用程序被adb push you.apk /system/app/下是會自動啟動的,不處于stopped狀態(tài)含潘。
具體說明見:
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發(fā)送BOOT_COMPLETED
我們可以通過 adb shell am broadcast -a android.intent.action.BOOT_COMPLETED命令發(fā)送BOOT_COMPLETED廣播,而不用重啟測試機或模擬器來測試BOOT_COMPLETED廣播(用真機測過遏弱,還是會重啟的盆均,所以推薦后面的指定包名命令),以下命令可以更精確的發(fā)送到某個package腾窝,如下:
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -c android.intent.category.HOME -n package_name/class_name