android開機自動喚醒螢幕、開啟鎖屏頁並啟動app
阿新 • • 發佈:2019-01-19
最近有個需求要求app要開機自啟動,就按照一般的套路去註冊了一個靜態廣播接收器,程式碼如下:
manifest檔案:
[html]
view plain
copy
print?
具體說明見: 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
- <receiverandroid:name=".receiver.StartupReceiver">
- <intent-filter>
- <actionandroid:name="android.intent.action.BOOT_COMPLETED"/>
- </intent-filter>
- </receiver>
java檔案: [java] view plain copy print?<receiver android:name=".receiver.StartupReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
- publicclass StartupReceiver extends BroadcastReceiver {
- @Override
- publicvoid onReceive(Context context, Intent intent) {
- ByLog.i(intent.getAction());
- //開機啟動
- Intent mainIntent = new Intent(context, MainActivity.
- //在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啟動時,主動喚醒螢幕並解鎖,程式碼如下: [java] view plain copy print?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); } }
- //螢幕喚醒
- 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();
//螢幕喚醒
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();
[java]
view plain
copy
print?
- //螢幕解鎖
- KeyguardManager km= (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
- KeyguardManager.KeyguardLock kl = km.newKeyguardLock("StartupReceiver");//引數是LogCat裡用的Tag
- kl.disableKeyguard();
//螢幕解鎖
KeyguardManager km= (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock kl = km.newKeyguardLock("StartupReceiver");//引數是LogCat裡用的Tag
kl.disableKeyguard();
到此,開機自啟的這塊需求就算是完成了。最後附上完整的程式碼:
manifest檔案:
記得要新增許可權
[html]
view plain
copy
print?
- <uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
[html]
view plain
copy
print?
- <receiverandroid:name=".receiver.StartupReceiver">
- <intent-filter>
- <actionandroid:name="android.intent.action.BOOT_COMPLETED"/>
- <actionandroid:name="android.intent.action.QUICKBOOT_POWERON"/>
- </intent-filter>
- </receiver>
<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]
view plain
copy
print?
- publicclass StartupReceiver extends BroadcastReceiver {
- @Override
- publicvoid 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);
- }
- }
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廣播可能的原因
(1)、BOOT_COMPLETED對應的action和uses-permission("android.permission.RECEIVE_BOOT_COMPLETED" )沒有一起新增
(2)、應用安裝到了sd卡內,安裝在sd卡內的應用是收不到BOOT_COMPLETED廣播的,可以在manifest節點下新增android:installLocation="internalOnly"來指定只能安裝在手機記憶體裡面,也可以監聽開機載入sd卡的廣播,可惜有的手機是沒有sd卡的。。。
(3)、系統開啟了Fast Boot模式,這種模式下系統啟動並不會傳送BOOT_COMPLETED廣播
(4)、應用程式安裝後重來沒有啟動過,這種情況下應用程式接收不到任何廣播,包括BOOT_COMPLETED、ACTION_PACKAGE_ADDED、CONNECTIVITY_ACTION等等。
Android3.1之後,系統為了加強了安全性控制,應用程式安裝後或是(設定)應用管理中被強制關閉後處於stopped狀態,在這種狀態下接收不到任何廣播,除非廣播帶有FLAG_INCLUDE_STOPPED_PACKAGES標誌,而預設所有系統廣播都是FLAG_EXCLUDE_STOPPED_PACKAGES的,所以就沒法通過系統廣播自啟動了。所以Android3.1之後
(1)、應用程式無法在安裝後自己啟動
(2)、沒有ui的程式必須通過其他應用啟用才能啟動,如它的Activity、Service、Content Provider被其他應用呼叫。
存在一種例外,就是應用程式被adb push you.apk /system/app/下是會自動啟動的,不處於stopped狀態。
具體說明見: 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