Android 后臺(tái)運(yùn)行白名單,優(yōu)雅實(shí)現(xiàn)保活

image

?;瞵F(xiàn)狀

我們知道,Android 系統(tǒng)會(huì)存在殺后臺(tái)進(jìn)程的情況,并且隨著系統(tǒng)版本的更新,殺進(jìn)程的力度還有越來越大的趨勢。系統(tǒng)這種做法本身出發(fā)點(diǎn)是好的,因?yàn)榭梢怨?jié)省內(nèi)存,降低功耗,也避免了一些流氓行為。

但有一部分應(yīng)用,應(yīng)用本身的使用場景就需要在后臺(tái)運(yùn)行,用戶也是愿意讓它在后臺(tái)運(yùn)行的,比如跑步類應(yīng)用。一方面流氓軟件用各種流氓手段進(jìn)行?;睿硪环矫嫦到y(tǒng)加大殺后臺(tái)的力度,導(dǎo)致我們一些真正需要在后臺(tái)運(yùn)行的應(yīng)用被誤殺,苦不堪言。

優(yōu)雅保活?

為了做到?;?,出現(xiàn)了不少「黑科技」,比如 1 個(gè)像素的 Activity,播放無聲音頻,雙進(jìn)程互相守護(hù)等。這些做法可以說是很流氓了,甚至破壞了 Android 的生態(tài),好在隨著 Android 系統(tǒng)版本的更新,這些非常規(guī)的保活手段很多都已失效了。

對于那些確實(shí)需要在后臺(tái)運(yùn)行的應(yīng)用,我們?nèi)绾巫龅絻?yōu)雅的?;钅兀?/p>

后臺(tái)運(yùn)行白名單

從 Android 6.0 開始,系統(tǒng)為了省電增加了休眠模式,系統(tǒng)待機(jī)一段時(shí)間后,會(huì)殺死后臺(tái)正在運(yùn)行的進(jìn)程。但系統(tǒng)會(huì)有一個(gè)后臺(tái)運(yùn)行白名單,白名單里的應(yīng)用將不會(huì)受到影響,在原生系統(tǒng)下,通過「設(shè)置」 - 「電池」 - 「電池優(yōu)化」 - 「未優(yōu)化應(yīng)用」,可以看到這個(gè)白名單,通常會(huì)看到下面這兩位:

image

下次被產(chǎn)品說「 XXX 都可以?;睿瑸槭裁次覀儾恍?!」的時(shí)候,你就知道怎么懟回去了。大廠通過和手機(jī)廠商的合作,將自己的應(yīng)用默認(rèn)加入到白名單中。如果你在一個(gè)能談成這種合作的大廠,也就不用往下看了。

好在系統(tǒng)還沒有拋棄我們,允許我們申請把應(yīng)用加入白名單。

首先,在 AndroidManifest.xml 文件中配置一下權(quán)限:

|

1

|

<uses-permission android:name=``"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

|

可以通過以下方法,判斷我們的應(yīng)用是否在白名單中:

|

1

2

3

4

5

6

7

8

9

|

@RequiresApi(api = Build.VERSION_CODES.M)

private boolean isIgnoringBatteryOptimizations() {

boolean isIgnoring = ``false``;

PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);

if (powerManager != ``null``) {

isIgnoring = powerManager.isIgnoringBatteryOptimizations(getPackageName());

}

return isIgnoring;

}

|

如果不在白名單中,可以通過以下代碼申請加入白名單:

|

1

2

3

4

5

6

7

8

9

10

|

@RequiresApi(api = Build.VERSION_CODES.M)

public void requestIgnoreBatteryOptimizations() {

try {

Intent intent = ``new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);

intent.setData(Uri.parse(``"package:" + getPackageName()));

startActivity(intent);

} ``catch (Exception e) {

e.printStackTrace();

}

}

|

申請時(shí),應(yīng)用上會(huì)出現(xiàn)這樣一個(gè)窗口:

image

可以看到,這個(gè)系統(tǒng)彈窗會(huì)有影響電池續(xù)航的提醒,所以如果想讓用戶點(diǎn)允許,必須要有相關(guān)的說明。如果要判斷用戶是否點(diǎn)擊了允許,可以在申請的時(shí)候調(diào)用 startActivityForResult,在 onActivityResult 里再判斷一次是否在白名單中。

廠商后臺(tái)管理

Android 開發(fā)的一個(gè)難點(diǎn)在于,各大手機(jī)廠商對原生系統(tǒng)進(jìn)行了不同的定制,導(dǎo)致我們需要進(jìn)行不同的適配,后臺(tái)管理就是一個(gè)很好的體現(xiàn)。幾乎各個(gè)廠商都有自己的后臺(tái)管理,就算應(yīng)用加入了后臺(tái)運(yùn)行白名單,仍然可能會(huì)被廠商自己的后臺(tái)管理干掉。

如果能把應(yīng)用加入廠商系統(tǒng)的后臺(tái)管理白名單,可以進(jìn)一步降低進(jìn)程被殺的概率。不同的廠商在不同的地方進(jìn)行設(shè)置,一般是在各自的「手機(jī)管家」,但更難的是,就算同一個(gè)廠商的系統(tǒng),不同的版本也可能是在不同地方設(shè)置。

最理想的做法是,我們根據(jù)不同手機(jī),甚至是不同的系統(tǒng)版本,給用戶呈現(xiàn)一個(gè)圖文操作步驟,并且提供一個(gè)按鈕,直接跳轉(zhuǎn)到指定頁面進(jìn)行設(shè)置。但需要對每個(gè)廠商每個(gè)版本進(jìn)行適配,工作量是比較大的。我使用真機(jī)測試了大部分主流 Android 廠商的手機(jī)后,整理出了部分手機(jī)的相關(guān)資料。

首先我們可以定義這樣兩個(gè)方法:

作者:NanBox
鏈接:http://www.itdecent.cn/p/32b7241124a2
來源:簡書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

|

/**

* 跳轉(zhuǎn)到指定應(yīng)用的首頁

*/

private void showActivity(@NonNull String packageName) {

Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);

startActivity(intent);

}

/**

* 跳轉(zhuǎn)到指定應(yīng)用的指定頁面

*/

private void showActivity(@NonNull String packageName, @NonNull String activityDir) {

Intent intent = ``new Intent();

intent.setComponent(``new ComponentName(packageName, activityDir));

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(intent);

}

|

以下是部分手機(jī)的廠商判斷,跳轉(zhuǎn)方法及對應(yīng)設(shè)置步驟,跳轉(zhuǎn)方法不保證在所有版本上都能成功跳轉(zhuǎn),都需要加 try catch。

華為

廠商判斷:

|

1

2

3

4

5

6

7

|

public boolean isHuawei() {

if (Build.BRAND == ``null``) {

return false``;

} ``else {

return Build.BRAND.toLowerCase().``equals``(``"huawei"``) || Build.BRAND.toLowerCase().``equals``(``"honor"``);

}

}

|

跳轉(zhuǎn)華為手機(jī)管家的啟動(dòng)管理頁:

|

1

2

3

4

5

6

7

8

9

|

private void goHuaweiSetting() {

try {

showActivity(``"com.huawei.systemmanager"``,

"com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity"``);

} ``catch (Exception e) {

showActivity(``"com.huawei.systemmanager"``,

"com.huawei.systemmanager.optimize.bootstart.BootStartActivity"``);

}

}

|

操作步驟:應(yīng)用啟動(dòng)管理 -> 關(guān)閉應(yīng)用開關(guān) -> 打開允許自啟動(dòng)

小米

廠商判斷:

|

1

2

3

|

public static boolean isXiaomi() {

return Build.BRAND != ``null && Build.BRAND.toLowerCase().``equals``(``"xiaomi"``);

}

|

跳轉(zhuǎn)小米安全中心的自啟動(dòng)管理頁面:

|

1

2

3

4

|

private void goXiaomiSetting() {

showActivity(``"com.miui.securitycenter"``,

"com.miui.permcenter.autostart.AutoStartManagementActivity"``);

}

|

操作步驟:授權(quán)管理 -> 自啟動(dòng)管理 -> 允許應(yīng)用自啟動(dòng)

OPPO

廠商判斷:

|

1

2

3

|

public static boolean isOPPO() {

return Build.BRAND != ``null && Build.BRAND.toLowerCase().``equals``(``"oppo"``);

}

|

跳轉(zhuǎn) OPPO 手機(jī)管家:

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

|

private void goOPPOSetting() {

try {

showActivity(``"com.coloros.phonemanager"``);

} ``catch (Exception e1) {

try {

showActivity(``"com.oppo.safe"``);

} ``catch (Exception e2) {

try {

showActivity(``"com.coloros.oppoguardelf"``);

} ``catch (Exception e3) {

showActivity(``"com.coloros.safecenter"``);

}

}

}

}

|

操作步驟:權(quán)限隱私 -> 自啟動(dòng)管理 -> 允許應(yīng)用自啟動(dòng)

VIVO

廠商判斷:

|

1

2

3

|

public static boolean isVIVO() {

return Build.BRAND != ``null && Build.BRAND.toLowerCase().``equals``(``"vivo"``);

}

|

跳轉(zhuǎn) VIVO 手機(jī)管家:

|

1

2

3

|

private void goVIVOSetting() {

showActivity(``"com.iqoo.secure"``);

}

|

操作步驟:權(quán)限管理 -> 自啟動(dòng) -> 允許應(yīng)用自啟動(dòng)

魅族

廠商判斷:

|

1

2

3

|

public static boolean isMeizu() {

return Build.BRAND != ``null && Build.BRAND.toLowerCase().``equals``(``"meizu"``);

}

|

跳轉(zhuǎn)魅族手機(jī)管家:

|

1

2

3

|

private void goMeizuSetting() {

showActivity(``"com.meizu.safe"``);

}

|

操作步驟:權(quán)限管理 -> 后臺(tái)管理 -> 點(diǎn)擊應(yīng)用 -> 允許后臺(tái)運(yùn)行

三星

廠商判斷:

|

1

2

3

|

public static boolean isSamsung() {

return Build.BRAND != ``null && Build.BRAND.toLowerCase().``equals``(``"samsung"``);

}

|

跳轉(zhuǎn)三星智能管理器:

|

1

2

3

4

5

6

7

|

private void goSamsungSetting() {

try {

showActivity(``"com.samsung.android.sm_cn"``);

} ``catch (Exception e) {

showActivity(``"com.samsung.android.sm"``);

}

}

|

操作步驟:自動(dòng)運(yùn)行應(yīng)用程序 -> 打開應(yīng)用開關(guān) -> 電池管理 -> 未監(jiān)視的應(yīng)用程序 -> 添加應(yīng)用

樂視

廠商判斷:

|

1

2

3

|

public static boolean isLeTV() {

return Build.BRAND != ``null && Build.BRAND.toLowerCase().``equals``(``"letv"``);

}

|

跳轉(zhuǎn)樂視手機(jī)管家:

|

1

2

3

4

|

private void goLetvSetting() {

showActivity(``"com.letv.android.letvsafe"``,

"com.letv.android.letvsafe.AutobootManageActivity"``);

}

|

操作步驟:自啟動(dòng)管理 -> 允許應(yīng)用自啟動(dòng)

錘子

廠商判斷:

|

1

2

3

|

public static boolean isSmartisan() {

return Build.BRAND != ``null && Build.BRAND.toLowerCase().``equals``(``"smartisan"``);

}

|

跳轉(zhuǎn)手機(jī)管理:

|

1

2

3

|

private void goSmartisanSetting() {

showActivity(``"com.smartisanos.security"``);

}

|

操作步驟:權(quán)限管理 -> 自啟動(dòng)權(quán)限管理 -> 點(diǎn)擊應(yīng)用 -> 允許被系統(tǒng)啟動(dòng)

友商致敬?

在之前做的跑步應(yīng)用中,我在設(shè)置里增加了一個(gè)權(quán)限設(shè)置頁面,將上面提到的設(shè)置放在這里面。最近發(fā)現(xiàn)友商某咚也跟進(jìn)了,圖 1 是我們做的,圖 2 是某咚做的:

image

某咚從設(shè)計(jì)、從我寫的不夠好的文案,甚至是我從十幾臺(tái)手機(jī)上一張一張截下來的圖,進(jìn)行了全方位的致敬。感謝某咚的認(rèn)可,但最近在某個(gè)發(fā)布會(huì)上聽到這么一句話:在致敬的同時(shí),能不能說一句謝謝?

某咚的致敬,一方面說明了目前確實(shí)存在進(jìn)程容易被殺,?;铍y度大的問題,另一方面也說明了這種引導(dǎo)用戶進(jìn)行白名單設(shè)置的手段是有效的。

文章來自:https://www.cnblogs.com/Im-Victor/p/12533232.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容