【锁定直播】字节、华为云、阿里云等技术专家讨论如何将大模型接入 AIOps 解决实际问题,戳>>> 了解详情
写点什么

Android App 保活服务的配置与禁用

  • 2021-01-20
  • 本文字数:6589 字

    阅读完需:约 22 分钟

Android App 保活服务的配置与禁用

Android 应用保活是应用、系统、用户三个角色相互影响的产物。几乎每一款应用都希望自己能实现永久保活,并通过保活实现消息推送、信息上报等等交互行为;几乎所有的系统厂商都想把应用关在笼子里,通过控制应用的运行时间来避免过多的电量和性能的消耗,这样可以大大提高系统流畅度和手机使用时间;对于用户来说我们希望使用的时候应用可以更好的运行,比如音乐、导航、通信软件,但是我们又希望不使用时彻底关闭应用,但是大部分用户都不清楚如何彻底关闭一个应用并让它不再运行。那么本文介绍一下在 Android 系统里面是如何实现保活方案,如何启动或禁用应用的保活。


Android 应用自启与白名单


Android 应用的保活一般会从两个方面着手:一是如何提高应用的存活周期;二是如何唤醒关闭的应用。一般情况下会通过 Android 账户的自动同步机制和开机广播唤醒已关闭的应用;然后通过定时任务、前台服务、在屏幕上显示控件等方式提高应用的存活周期。在账户同步的服务和开机广播接收器中为应用开启一个前台 Service 就实现了应用保活的基本策略。下面分别介绍各个方式的实现。


Android 应用自启与白名单


通过静态注册开机广播可以在系统启动时唤醒应用,应用被唤醒后可以检查并初始化前台服务等保活策略。


  1. 首先我们需要实现 BroadcastReceiver 的子类作为开机广播的接收器,并在 onReceive 方法中处理业务逻辑。

public class BootReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        //检查并初始化前台服务等保活策略    }}
复制代码


2. 然后我们将开机广播接收器注册到 AndroidManifest.xml 中,并增加开机动作过滤器。

<receiver    android:name=".receiver.BootReceiver"    android:directBootAware="true"    android:enabled="true"    android:exported="true">    <!--通过priority指定广播的优先级-->    <intent-filter android:priority="2147483647">        <action android:name="android.intent.action.BOOT_COMPLETED" />        <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />    </intent-filter>  </receiver>
复制代码


账户同步机制


Android 应用可以在运行时注册系统账户,并通过 service 与系统账户进行关联,当系统运行时会在特定时期同步账户,同步账户的时候会启动所关联的 service,在关联 service 中可以检查保活方案,通过账户同步机制可以唤醒被关闭的应用。


在开始之前首先定义两常量,在文中通过{常量名}的方式方式指代:accountType=“xxxxxx”contentAuthority=“xxxx”


  1. 在项目 res/xml 中添加账户配置文件,指定文件名为 account_sync_adapter.xml


<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:accountType="{accountType}" android:allowParallelSyncs="false" android:contentAuthority="{contentAuthority}" android:isAlwaysSyncable="true" android:supportsUploading="true" android:userVisible="true" />
复制代码


2. 在项目 res/xml 中配置账户显示信息,命名为 account_authenticator.xml


<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android" android:accountType="com.qihoo.qa.ticker.account" android:icon="@mipmap/ic_launcher" <!--在系统设置中显示的账户图标--> android:label="@string/app_name" /><!--在系统设置中显示的账户名称-->
复制代码


3. 实现 ContentProvider 的子类,并在 AndroidManifest.xml 中注册

public class AccountSyncProvider extends ContentProvider {    @Override    public boolean onCreate() {        return false;    }
@Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { return null; }
@Nullable @Override public String getType(@NonNull Uri uri) { return null; }
@Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { return null; }
@Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; }
@Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; }}
复制代码


注册服务


<providerandroid:name=".account.AccountSyncProvider"android:authorities="{contentAuthority}"android:enabled="true"android:exported="true" />
复制代码


4. 实现账户的认证 service,系统会调用该 service 认证账户,由于是用于保活的空账户,所以不需要关注具体业务


public class AuthenticationService extends Service {
private AccountAuthenticator accountAuthenticator;
@Nullable @Override public IBinder onBind(Intent intent) { return accountAuthenticator.getIBinder();//返回binder对象供系统使用 }
@Override public void onCreate() { super.onCreate(); accountAuthenticator = new AccountAuthenticator(this); }
public static class AccountAuthenticator extends AbstractAccountAuthenticator {
public AccountAuthenticator(Context context) { super(context); }
@Override public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { return null; }
@Override public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { return null; }
@Override public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { return null; }
@Override public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { return null; }
@Override public String getAuthTokenLabel(String authTokenType) { return null; }
@Override public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { return null; }
@Override public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { return null; }
复制代码


在 AndroidManifest.xml 中注册账户认证服务


<service android:name=".account.AuthenticationService">    <intent-filter>        <action android:name="android.accounts.AccountAuthenticator" />    </intent-filter>    <meta-data        android:name="android.accounts.AccountAuthenticator"        android:resource="@xml/account_authenticator" /> <!--指定账户配置文件--></service>
复制代码


5. 编写并配置账户同步服务,系统自动同步账户时回调此服务


public class AccountSyncService extends Service {
private SyncAdapter mSyncAdapter;
private static final String TAG = "SyncService";
@Nullable @Override public IBinder onBind(Intent intent) { return mSyncAdapter.getSyncAdapterBinder(); }
@Override public void onCreate() { super.onCreate(); mSyncAdapter = new SyncAdapter(getApplicationContext(), true); }
; public static class SyncAdapter extends AbstractThreadedSyncAdapter { public SyncAdapter(Context context, boolean autoInitialize) { super(context, autoInitialize); }

@Override public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { //账户同步时回调此方法,在此处检测保活业务 } }}
复制代码


在 AndroidManifest.xml 中注册账户同步服务


<service  android:name=".account.AccountSyncService"<!--指定service文件-->  android:enabled="true"  android:exported="true">  <intent-filter>      <action android:name="android.content.SyncAdapter" />  </intent-filter>  <meta-data      android:name="android.content.SyncAdapter"      android:resource="@xml/account_sync_adapter" /><!--指定配置文件,该配置文件需要手动添加--></service>
复制代码


6. 添加账户并设置自动同步


accountName="test"accountPwd="pwd"//添加账户 AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); Account account = new Account(accountName,  {accountType}); accountManager.addAccountExplicitly(account, accountPwd, new Bundle()); //设置账户同步 Account account = new Account(accountName, {accountType});// 下面三个都需要同一个权限  WRITE_SYNC_SETTINGS// 设置同步ContentResolver.setIsSyncable(account, {contentAuthority}, 1);// 自动同步ContentResolver.setSyncAutomatically(account, {contentAuthority}, true);// 设置同步周期ContentResolver.addPeriodicSync(account, {contentAuthority}, new Bundle(), 1);
复制代码


Schedule 定时任务

1. 实现 JobService 的子类,用于执行任务时回调


@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public class LiveJobService extends JobService {    @Override    public boolean onStartJob(JobParameters params) {        //执行任务时回调        return false;    }
@Override public boolean onStopJob(JobParameters params) { return false; }}
复制代码


2. 在 AndroidManifest 中配置任务 service


<service    android:name=".service.LiveJobService"    android:enabled="true"    android:exported="true"    android:permission="android.permission.BIND_JOB_SERVICE" /><!--指定服务权限-->
复制代码


3. 设置定时任务


JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);//setPersisted 在设备重启依然执行JobInfo.Builder builder = new JobInfo.Builder(lastJobId+i, new ComponentName(context.getPackageName(),LiveJobService.class.getName())).setPersisted(true);// 50s后执行任务if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {    builder.setPeriodic(50000);} else {    // 延迟执行任务    builder.setMinimumLatency(50000);}jobScheduler.schedule(builder.build());
复制代码


前台服务

保活服务一般在 Service 中后台运行,而 Android 系统对后台服务有一些列的运行限制,所以把服务绑定为前台服务会提高服务的优先级,在系统资源紧张时可以更好的运行。

1. 实现 Service 子类 NotificationService,并在在 onStartCommand 方法中开启常驻通知


/** * @author walker * @date 2020/12/25. * @description 在应用后台处理数据 */public class NotificationService extends Service {
@Nullable @Override public IBinder onBind(Intent intent) { return null; }
@Override public void onCreate() { super.onCreate(); }
@Override public int onStartCommand(Intent intent, int flags, int startId) { // 如果Service被终止 // 当资源允许情况下,重启service //绑定前台通知 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setForegroundService(); } return START_STICKY; }
/** * 通过通知启动服务 */ @androidx.annotation.RequiresApi(api = Build.VERSION_CODES.O) public void setForegroundService() { //设定的通知渠道名称 String channelName = "slient_name"; String CHANNEL_ID = "slient_id"; //设置通知的重要程度 int importance = NotificationManager.IMPORTANCE_LOW; //构建通知渠道 NotificationChannel channel = new NotificationChannel(CHANNEL_ID, channelName, importance); channel.setDescription("test"); //在创建的通知渠道上发送通知 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID); builder.setSmallIcon(R.drawable.ic_launcher) //设置通知图标 .setContentTitle("通知")//设置通知标题 .setContentText("前台服务")//设置通知内容 .setAutoCancel(true) //用户触摸时,自动关闭 .setOngoing(true);//设置处于运行状态 //向系统注册通知渠道,注册后不能改变重要性以及其他通知行为 NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.createNotificationChannel(channel); //将服务置于启动状态 NOTIFICATION_ID指的是创建的通知的ID startForeground(111, builder.build()); }
@Override public void onDestroy() { super.onDestroy(); }}
复制代码


2. 在 AndroidManifest 中配置服务


<!--通过android:process标签指定独立进程名--><service    android:name=".service.DataService"    android:enabled="true"    android:exported="false"    android:process=":sync" />
复制代码


3. 在应用启动时开启服务


startService(new Intent(context,DataService.class));
复制代码


如何禁用后台运行


我们在开发或配置应用保活相关功能时主要通过开机自启、后台运行、关联启动、账户同步几个方面入手,不同的手机设置入口有可能不一样,但是可以参考这几点进行设置,下面介绍一下华为荣耀 20 上的配置方式。


01 开机自启权限的处理

以华为系统为例,在【手机管家】app 中找到【应用启动管理】,并在应用启动管理中找到对应的 app,将对应 app 切换为【手动管理】,并为激活【允许自动启动】【允许关联启动】【允许后台活动】三个选项。


允许设备开机自启以及后台服务的配置:



禁止后台服务以及开机自启的设置:


02 账户同步服务的处理

我们在【设置】/【账户】下可以看到系统内所有的账户信息,并可以在这里管理同步服务


允许账户同步设置:


允许账户同步时系统会按既定策略回调注册同步 Service,在 Service 内可以启动应用其他服务,但是部分机型上可能存在适配问题。



禁用所有账户同步功能:



禁用某一应用的账户同步功能:



本文转载自:360 技术(ID:qihoo_tech)

原文链接:Android App 保活服务的配置与禁用

2021-01-20 14:002401

评论

发布
暂无评论
发现更多内容

横空出世,智见未来,戴尔Latitude 9430傲视群雄

科技热闻

基于炼丹神器深度学习下的生命科学冷冻电镜单细胞基因分析的解决方案

蓝海大脑GPU

【云安全】云安全产品有哪些?哪个品牌好?

行云管家

云计算 网络安全 安全 云安全

数据结构学习,稀疏矩阵(三元组和十字链)

IC00

学习 数据结构 算法 学习笔记 10月月更

校招面试真题 | 和面试官聊的很 high,但就是拿不到 offer,怎么办?

霍格沃兹测试开发学社

Baklib|打造属于您自己的企业维基

Baklib

产品 效率工具 企业 wiki 产品文档

跑批为什么这么难

陈橘又青

训练营 | 如何成为一名开源社区贡献者?

阿里巴巴云原生

阿里云 开源 云原生 KubeVela

软件测试校招面试真题 | 面试官必问面试题之你有什么想问我的?

测试人

以开发之名|斗罗大陆:创造一个尽情探险的开放式游戏世界

HMS Core

华为 HMS Core

Baklib|企业知识管理的一些建议分享

Baklib

效率工具 知识管理 企业 知识 知识库

好文分享 | 记一次Oracle12c数据库SQL短暂缓慢问题分析

墨天轮

数据库 oracle 性能优化 征文投稿

MASA MAUI Plugin (四)条形码、二维码扫描功能

MASA技术团队

MASA MAUI MASA Blazor

云管理工具是干什么的?有哪些?哪个品牌好?

行云管家

云计算 云管理 云工具

嵌入式 Linux 入门(一、Linux 基本介绍及文件结构)

矜辰所致

Linux 10月月更 文件结构

Qt | QList的removeAt、takeAt的区别

YOLO.

qt 10月月更 C++

如何在 SAP Business Application Studio 里创建 SAP UI5 应用并部署到 BTP 平台上

Jerry Wang

云原生 云平台 SAP 10月月更

在云南,我用华为云AI开发出千万级用户的应用

华为云开发者联盟

人工智能 程序员 华为云 文字识别 企业号十月 PK 榜

EMQ走进富士康,探讨新生态模式下智能制造与智能汽车基础架构的未来

EMQ映云科技

车联网 物联网 IoT emqx 10月月更

C# TreeView控件方法属性学习

IC00

C# 学习 程序员 上位机 10月月更

Linux 各个Namespace 的作用

忙着长大#

linux namespace

峰会回顾 | 基于StarRocks,百草味如何通过数据赋能快消品行业

StarRocks

#数据库

IM跨平台技术学习(五):融云基于Electron的IM跨平台SDK改造实践总结

JackJiang

如何利用Java在Word中创建表格

Geek_249eec

Java word 表格

StartDT奇点云邀您参加2022云栖大会,11月3-5日杭州见

奇点云

云栖大会 奇点云

火力全开-Precision 7670触顶性能天花版

科技热闻

Qt|使用QDialog窗口调用exec时崩溃解决问题

中国好公民st

c++ qt 10月月更

CEF | CEF浏览器客户端功能扩展:实现与JS交互的功能

YOLO.

qt 10月月更 C++

小白必看——台式机选购指南

科技热闻

uniapp实现国际化多语言切换

源字节1号

软件开发

区服分析丨更透彻的游戏营运数据解读,助力高效增长

HMS Core

分析

Android App 保活服务的配置与禁用_移动_360技术_InfoQ精选文章