之前有做过1像素保活
现在2021年了,很多保活方式其实已经过时了
谷歌对于这方面的掌控也越来越严
而且作为开发者,其实也不建议应用长时间的驻留内存
搞得和流氓软件一样。
但一些实际场景,的确是需要进程保活的功能的
比如跑步,聊天,外卖软件等等
这几天也在搜集相关的知识
最后整理了下
发现有三种方式,还是比较能够提升app的存活率的
而且都是提示用户手动去开启的方式
不是利用系统漏洞之类的取巧方法
显得优雅了很多。
我大概整理了下,分别是
1后台运行白名单
2自启动管理
3电池策略(这一点不同厂商有不同的叫法,比如小米叫“设置后台无限制”,华为叫“设置电池优化”。这边我先统一叫电池策略)
下面就开始一一介绍,文末会放出全部代码。
1、后台运行白名单
这个方法需要添加以下权限
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
可以从权限的名字看出来,叫做忽略电池优化
这里我们还是叫做后台运行白名单
使用起来也很简单,检测下是否开启,没有就提示用户开启
也可以在onActivityResult方法里再判断一次是否开启
这个方式只对6.0以上的机器有效
文末的代码里我也做了判断
代码如下(KeepAliveUtil工具类代码会在文末放出)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!KeepAliveUtil.isIgnoringBatteryOptimizations(this)) {
KeepAliveUtil.requestIgnoreBatteryOptimizations(this,0x001);
}else {
Toast.makeText(this, "\"忽略电池优化功能\"已开启", Toast.LENGTH_SHORT).show();
}
}else {
Toast.makeText(this, "安卓版本太低,不支持此功能", Toast.LENGTH_SHORT).show();
}
2、自启动管理
这个主要是提示用户去开启应用的自启动
因为每个厂商跳转到自启动页面的代码都不一样
所以这边用工具类适配了几个主流机型
包括miui,华为,oppo,vivo
具体代码后面也会放出
3、电池策略
这个和自启动管理差不多,也是要去适配不同的厂商的
后面一样有代码放出
只是这个需要注意
不同的厂商叫法还不一样
这个叫法是我随便起的
比如小米叫“设置后台无限制”,华为叫“设置电池优化”。
oppo里面又叫应用速冻了
vivo里面叫做允许后台高耗电
为了实现这三个提示用户去开启的功能
我做了一个简单的demo
用三个按钮去代替这三个功能的实现
第三个按钮上方还添加了TextView对开启路径做一个提示
毕竟不同厂商的路径还不一样
业务代码封装在了KeepAliveUtil这个工具类。下面开始贴代码
首先是MainActivity
public class MainActivity extends AppCompatActivity {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn1 = findViewById(R.id.btn1);
Button btn2 = findViewById(R.id.btn2);
Button btn3 = findViewById(R.id.btn3);
TextView tv_tip = findViewById(R.id.tv_tip);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//后台运行白名单
btn1Fun();
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//自启动管理
btn2Fun();
}
});
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//省电策略
btn3Fun();
}
});
tv_tip.setText(KeepAliveUtil.getBatteryStrategyTipStr(this));
btn3.setText(KeepAliveUtil.getBatteryStrategyStr(this));
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void btn1Fun() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!KeepAliveUtil.isIgnoringBatteryOptimizations(this)) {
KeepAliveUtil.requestIgnoreBatteryOptimizations(this,0x001);
}else {
Toast.makeText(this, "\"忽略电池优化功能\"已开启", Toast.LENGTH_SHORT).show();
}
}else {
Toast.makeText(this, "安卓版本太低,不支持此功能", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0x001) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if (!KeepAliveUtil.isIgnoringBatteryOptimizations(this)) {
KeepAliveUtil.requestIgnoreBatteryOptimizations(this,0x002);
}else {
Toast.makeText(this, "\"忽略电池优化功能\"已开启", Toast.LENGTH_SHORT).show();
}
}else {
Toast.makeText(this, "安卓版本太低,不支持此功能", Toast.LENGTH_SHORT).show();
}
}
}
private void btn2Fun() {
KeepAliveUtil.startAppStartManagerActivity(this);
}
private void btn3Fun() {
KeepAliveUtil.startBatteryStrategyActivity(this);
}
}
对应的XML布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="后台运行白名单"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="自启动管理"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn1" />
<TextView
android:id="@+id/tv_tip"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/btn2" />
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="电池策略"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_tip" />
</androidx.constraintlayout.widget.ConstraintLayout>
KeepAlive工具类
/**
* 保活工具类
*/
public class KeepAliveUtil {
/**
* 判断我们的应用是否在白名单中
*
* @param activity
* @return
*/
@RequiresApi(api = Build.VERSION_CODES.M)
public static boolean isIgnoringBatteryOptimizations(Activity activity) {
boolean isIgnoring = false;
PowerManager powerManager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
if (powerManager != null) {
isIgnoring = powerManager.isIgnoringBatteryOptimizations(activity.getPackageName());
}
return isIgnoring;
}
/**
* 申请加入白名单
*
* @param activity
*/
@RequiresApi(api = Build.VERSION_CODES.M)
public static void requestIgnoreBatteryOptimizations(Activity activity,int requestCode) {
try {
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + activity.getPackageName()));
activity.startActivityForResult(intent, requestCode);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 得到电池策略文字
*/
public static String getBatteryStrategyStr(Context context) {
if (isHuawei()) {
return context.getString(R.string.str_battery_strategy_huawei);
} else if (isXiaomi()) {
return context.getString(R.string.str_battery_strategy_miui);
} else if (isOPPO()) {
return context.getString(R.string.str_battery_strategy_oppo);
} else if (isVIVO()) {
return context.getString(R.string.str_battery_strategy_vivo);
} else {
return context.getString(R.string.str_battery_strategy_miui);
}
}
/**
* 得到电池策略提示文字
*/
public static String getBatteryStrategyTipStr(Context context) {
if (isHuawei()) {
return context.getString(R.string.str_battery_strategy_tip_huawei);
} else if (isXiaomi()) {
return context.getString(R.string.str_battery_strategy_tip_miui);
} else if (isOPPO()) {
return context.getString(R.string.str_battery_strategy_tip_oppo);
} else if (isVIVO()) {
return context.getString(R.string.str_battery_strategy_tip_vivo);
} else {
return context.getString(R.string.str_battery_strategy_tip_miui);
}
}
/**
* 跳转不同机型的电池策略界面
*/
public static void startBatteryStrategyActivity(Context context) {
Intent intent = new Intent();
if (isHuawei()) {
try {
intent.setComponent(new ComponentName("com.android.settings", "com.android.settings.Settings$HighPowerApplicationsActivity"));
context.startActivity(intent);
} catch (Exception e) {
Toast.makeText(context, context.getResources().getString(R.string.str_battery_strategy_error), Toast.LENGTH_SHORT).show();
}
} else if (isXiaomi()) {
intent.putExtra("package_name", context.getPackageName());
intent.putExtra("package_label", context.getResources().getString(R.string.app_name));
try {
intent.setComponent(new ComponentName("com.miui.powerkeeper", "com.miui.powerkeeper.ui.HiddenAppsConfigActivity"));
context.startActivity(intent);
} catch (Exception e) {
Toast.makeText(context, context.getResources().getString(R.string.str_battery_strategy_error), Toast.LENGTH_SHORT).show();
}
} else if (isOPPO()) {
try {
intent.setComponent(new ComponentName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerConsumptionActivity"));
context.startActivity(intent);
} catch (Exception e) {
Toast.makeText(context, context.getResources().getString(R.string.str_battery_strategy_error), Toast.LENGTH_SHORT).show();
}
} else if (isVIVO()) {
try {
intent.setComponent(new ComponentName("com.iqoo.powersaving", "com.iqoo.powersaving.PowerSavingManagerActivity"));
context.startActivity(intent);
} catch (Exception e) {
Toast.makeText(context, context.getResources().getString(R.string.str_battery_strategy_error), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(context, context.getResources().getString(R.string.str_battery_strategy_error2), Toast.LENGTH_SHORT).show();
}
}
/**
* 跳转不同机型的自启动管理界面
*/
public static void startAppStartManagerActivity(Context context) {
if (isHuawei()){
goHuaweiSetting(context);
}else if (isXiaomi()){
goXiaomiSetting(context);
}else if (isOPPO()){
goOPPOSetting(context);
}else if (isVIVO()){
goVIVOSetting(context);
}else {
Toast.makeText(context, context.getResources().getString(R.string.str_battery_strategy_error2), Toast.LENGTH_SHORT).show();
}
}
private static void goHuaweiSetting(Context context) {
try {
showActivity(context, "com.huawei.systemmanager",
"com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity");
} catch (Exception e) {
showActivity(context, "com.huawei.systemmanager",
"com.huawei.systemmanager.optimize.bootstart.BootStartActivity");
}
}
private static void goXiaomiSetting(Context context) {
showActivity(context, "com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity");
}
private static void goOPPOSetting(Context context) {
try {
showActivity(context, "com.coloros.phonemanager");
} catch (Exception e1) {
try {
showActivity(context, "com.oppo.safe");
} catch (Exception e2) {
try {
showActivity(context, "com.coloros.oppoguardelf");
} catch (Exception e3) {
showActivity(context, "com.coloros.safecenter");
}
}
}
}
private static void goVIVOSetting(Context context) {
showActivity(context, "com.iqoo.secure");
}
/**
* 跳转到指定应用的指定页面
*/
private static void showActivity(Context context, @NonNull String packageName, @NonNull String activityDir) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(packageName, activityDir));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
/**
* 跳转到指定应用的首页
*/
private static void showActivity(Context context, @NonNull String packageName) {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
context.startActivity(intent);
}
/**
* 华为厂商判断
*
* @return
*/
public static boolean isHuawei() {
if (Build.BRAND == null) {
return false;
} else {
return Build.BRAND.toLowerCase().equals("huawei") || Build.BRAND.toLowerCase().equals("honor");
}
}
/**
* 小米厂商判断
* minSdkVersion在19以上,红米系列得到的是redmi的厂商名字,所以在这里适配下红米厂商
*
* @return
*/
public static boolean isXiaomi() {
return Build.BRAND != null && (Build.BRAND.toLowerCase().equals("xiaomi") || Build.BRAND.toLowerCase().equals("redmi"));
}
/**
* OPPO厂商判断
*
* @return
*/
public static boolean isOPPO() {
return Build.BRAND != null && Build.BRAND.toLowerCase().equals("oppo");
}
/**
* VIVO厂商判断
*
* @return
*/
public static boolean isVIVO() {
return Build.BRAND != null && Build.BRAND.toLowerCase().equals("vivo");
}
}
String.xml文件
<!--电池策略设置相关文字-->
<string name="str_battery_strategy_miui">设置后台[无限制]</string>
<string name="str_battery_strategy_huawei">设置[电池优化]</string>
<string name="str_battery_strategy_oppo">关闭应用速冻</string>
<string name="str_battery_strategy_vivo">允许后台高耗电</string>
<!--电池策略设置提示相关文字-->
<string name="str_battery_strategy_tip_miui">设置MIUI系统后台配置为[无限制]</string>
<string name="str_battery_strategy_tip_huawei">前往[电池优化]-[应用名称],设置[不允许]</string>
<string name="str_battery_strategy_tip_oppo">前往[电池]-[应用名称],关闭[后台冻结]和[检测到异常时自动优化]</string>
<string name="str_battery_strategy_tip_vivo">前往[电池]-[后台耗电管理]-[应用名称],设置[允许后台高耗电]</string>
<string name="str_battery_strategy_error">跳转设置失败</string>
<string name="str_battery_strategy_error2">机型不匹配,暂时无法支持该功能</string>
最后,关于保活相关的,也参考了下面两篇文章