进程保活-账号同步实现

账户同步的作用 : 如果应用的数据发生了改变 , 可以通过账户进行同步 , 进而与服务器进行数据同步操作 , 执行同步时 , 系统会拉活对应的应用进程 ;

实现的话,主要是应用 APP 中可以注册 " 账户服务 Service " , 应用安装后 , 如果系统发现应用中有该类型服务 , 就会为该应用开放添加账户的功能 ;

系统通过 Binder 机制 , 操作用户的 " 账户服务 Service " ;

第三方应用可以通过该账户服务 , 将数据同步 到服务器中 ;

系统在进行应用账户同步时 , 会自动将对应的应用拉活 ;

Google 官方提供了账户同步案例 , https://github.com/googlearchive/android-BasicSyncAdapter , 已经停止维护了 , 但是项目还是有参考价值的 ; ( 源码放在了本博客的资源文件中 )

在上述项目中指向了推荐的后台任务示例 https://github.com/android/background-tasks-samples ; ( 源码放在了本博客的资源文件中 )

说白了,进程拉活只是账户同步的附带作用 ;

具体实现:

1.创建一个账号同步工具类

public class AccountUtil {private static final String TAG = "AccountHelper";private static final String ACCOUNT_TYPE = "com.example.appprocesskeepalive.accounttype";private static final String ACCOUNT_AUTHORITY = "com.example.appprocesskeepalive.provider";private static final String ACCOUNT_NAME = "app账号同步demo";/*** 添加账号* @param context*/public static void addAccount(Context context) {AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);// 获得此类型的账户// 需要增加权限  GET_ACCOUNTSAccount[] accounts = accountManager.getAccountsByType(ACCOUNT_TYPE);if (accounts.length > 0) {Log.e(TAG, "账户已存在");return;}Account account = new Account(ACCOUNT_NAME, ACCOUNT_TYPE);// 给这个账户类型添加一个账户// 需要增加权限  AUTHENTICATE_ACCOUNTSaccountManager.addAccountExplicitly(account, "xx", new Bundle());}/*** 设置账户自动同步*/public static void sync() {Account account = new Account(ACCOUNT_NAME, ACCOUNT_TYPE);// 下面三个都需要同一个权限  WRITE_SYNC_SETTINGS// 设置同步ContentResolver.setIsSyncable(account, ACCOUNT_AUTHORITY, 1);// 自动同步ContentResolver.setSyncAutomatically(account, ACCOUNT_AUTHORITY, true);// 设置同步周期ContentResolver.addPeriodicSync(account, ACCOUNT_AUTHORITY, new Bundle(), 1);}}

2.账号服务注册

注册一个服务 , 该服务的 onBind 方法返回 AbstractAccountAuthenticator 对象的 Binder , 只要该应用安装 , 就可以在 " 设置 -> 账号 " 中查看该应用的账号

public class AuthService extends Service {private AccountAuthenticator accountAuthenticator;@Nullable@Overridepublic IBinder onBind(Intent intent) {return accountAuthenticator.getIBinder();}@Overridepublic void onCreate() {super.onCreate();accountAuthenticator = new AccountAuthenticator(this);}public static class AccountAuthenticator extends AbstractAccountAuthenticator {private Context mContext;public AccountAuthenticator(Context context) {super(context);mContext=context;}@Overridepublic Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {return null;}@Overridepublic Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType,String[] requiredFeatures, Bundle options) throws NetworkErrorException {AccountUtil.addAccount(mContext);AccountUtil.sync();return null;}@Overridepublic Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,Bundle options) throws NetworkErrorException {return null;}@Overridepublic Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,String authTokenType, Bundle options) throws NetworkErrorException {return null;}@Overridepublic String getAuthTokenLabel(String authTokenType) {return null;}@Overridepublic Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,String authTokenType, Bundle options) throws NetworkErrorException {return null;}@Overridepublic Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,String[] features) throws NetworkErrorException {return null;}}
}

 3.注册一个ContentProvider

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

4. 注册一个服务,这个服务提供一个Action给系统以便系统能找到它;然后就是继承和实现AbstractThreadedSyncAdapter,此类中包含实现了ISyncAdapter.Stub内部类,这个内部类封装了远程接口调用

public class SyncService extends Service {private SyncAdapter mSyncAdapter;private static final String TAG = "SyncService";@Nullable@Overridepublic IBinder onBind(Intent intent) {return mSyncAdapter.getSyncAdapterBinder();}@Overridepublic void onCreate() {super.onCreate();mSyncAdapter = new SyncAdapter(getApplicationContext(), true);}public class SyncAdapter extends AbstractThreadedSyncAdapter {public SyncAdapter(Context context, boolean autoInitialize) {super(context, autoInitialize);}@Overridepublic void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {// 账户同步操作// 与数据库 , 服务器同步操作 , 这里只是为了应用进程拉活 , 不实现具体的逻辑Log.i("AccountSyncService", "账户同步拉活激活");Log.i("AccountSyncService","是否还在运行:"+isServiceRunning(App.instance,"com.example.appprocesskeepalive.WakeUpService"));Intent intent=new Intent(App.instance, WakeUpService.class);if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ContextCompat.startForegroundService(App.instance, intent);}else {startService(intent);}}}public static boolean isServiceRunning(Context context, String serviceName) {ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);List<ActivityManager.RunningServiceInfo> runningServices = activityManager.getRunningServices(Integer.MAX_VALUE);if (runningServices != null) {for (ActivityManager.RunningServiceInfo serviceInfo : runningServices) {if (serviceInfo.service.getClassName().equals(serviceName)) {return true;}}}return false;}}

核心也是这块onPerformSync,收到账号同步的回调,收到后启动一个前台Service,

public class WakeUpService extends Service {@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 在这里启动你的应用startForeground(110, getNotification());Intent intent2 = getPackageManager().getLaunchIntentForPackage("com.example.appprocesskeepalive");if (intent2 != null) {//setFlags看自己情况使用,也可以不调用intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);getApplication().startActivity(intent2);}return START_STICKY;}@Overridepublic void onCreate() {super.onCreate();createNotificationChannel();}private void createNotificationChannel() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {CharSequence name = "My Foreground Service Channel";String description = "This channel is used for my foreground service";int importance = NotificationManager.IMPORTANCE_DEFAULT;NotificationChannel channel = new NotificationChannel("测试保活", name, importance);channel.setDescription(description);NotificationManager notificationManager = getSystemService(NotificationManager.class);notificationManager.createNotificationChannel(channel);}}private Notification getNotification() {Intent notificationIntent = new Intent(this, MainActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);return new NotificationCompat.Builder(this, "测试保活").setContentTitle("My Foreground Service").setContentText("Running...").setSmallIcon(R.drawable.ic_launcher_background).setContentIntent(pendingIntent).build();}}

在service中启动一个activity,但是要注意的是,如果要启动activity的话,需要申请一个悬浮窗权限

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

 然后就是配置文件的注册了

      <serviceandroid:name=".auth.AuthService"android:enabled="true"android:exported="true"><intent-filter><action android:name="android.accounts.AccountAuthenticator" /></intent-filter><meta-dataandroid:name="android.accounts.AccountAuthenticator"android:resource="@xml/account_auth" /></service><serviceandroid:name=".auth.SyncService"android:enabled="true"android:exported="true"><intent-filter><action android:name="android.content.SyncAdapter" /></intent-filter><meta-dataandroid:name="android.content.SyncAdapter"android:resource="@xml/up" /></service><providerandroid:name=".auth.SyncProvider"android:authorities="@string/account_authority"android:exported="false"android:syncable="true" /><serviceandroid:name=".WakeUpService"android:enabled="true"android:exported="true"android:persistent="true"android:stopWithTask="false" />

其中 android:persistent是表示app常驻内存的意思,虽然其实没啥大作用,app被杀死了后,它服务该死还是得死--

account_auth.xml

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"android:label="@string/app_name"android:icon="@mipmap/ic_launcher"android:accountType="@string/account_type"android:smallIcon="@mipmap/ic_launcher"/>

这块是用来配置账号同步在设置界面的UI显示的,要注意的时候此处的accountType要跟AbstractAccountAuthenticator执行创建账号、同步账号时的accountType要一样

up.xml

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"android:accountType="@string/account_type"android:contentAuthority="@string/account_authority"android:userVisible="true"android:supportsUploading="false"android:allowParallelSyncs="false"android:isAlwaysSyncable="true"/>
<!--    android:isAlwaysSyncable 属性 , 表示该账户同步操作 , 是否总是同步 , 这里设置 true , 账户拉活 , 越频繁越好 ;-->
<!--    android:userVisible 属性 , 表示是否在 " 设置 -> 账号 " 界面 , 展示一个账户同步开关 , 这里选择 false , 不给用户展示 , 万一用户给关了 , 就无法进行账户拉活应用进程操作 ;-->

写的可能有点乱,具体实现在这个demo:

AppProcessKeepAlive: 进程保活来的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/150600.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB常用绘图函数的使用

文章目录 绘制一图一线绘制一图多线用法一&#xff1a;plot用法二&#xff1a;hold on 绘制一图多图其他形式的坐标图分段函数绘制方法一&#xff1a;分段写函数的定义域值域方法二&#xff1a;判断定义域方法三&#xff1a;if else 判断 横纵坐标范围设置标题、轴标签、图例、…

4-2计算小于1000的正整数的平方根

#include<stdio.h> #include<math.h> int main() {int i;int t;printf("请输入一个数:");scanf("%d",&i);if(i>1000){printf("请重新输入一个数&#xff1a;");scanf("%d",&i);}tsqrt(i);printf("%d的平方…

数字化文化的守护之星:十八数藏的非遗创新之道

在数字时代的浪潮中&#xff0c;十八数藏犹如一颗璀璨的守护之星&#xff0c;为传统文化注入了新的生命力。这个非遗创新项目以数字化为工具&#xff0c;以守护为使命&#xff0c;开辟了文化传承的新航道。 十八数藏是文化数字守护的引领者&#xff0c;通过数字技术&#xff0…

极智嘉(Geek+)官宣重磅合作伙伴,再度赋能仓储自动化解决方案落地

近日&#xff0c;全球仓储机器人引领者极智嘉(Geek)再度官宣重磅合作伙伴&#xff0c;其与全球先进的物流自动化和软件公司FORTNA达成了战略合作。 当前&#xff0c;电商领域发展迅速&#xff0c;高效、可拓展的订单履行方案需求急剧增长。基于这一形势&#xff0c;极智嘉与FO…

测试之路,女孩子软件测试-职业规划建议,路就在脚下...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、测试岗是不是加…

网站被攻击怎么办?德迅云安全SCDN为您保驾护航

安全加速&#xff08;Secure Content Delivery Network&#xff0c;SCDN&#xff09;是德迅云安全推出的集分布式DDoS防护、CC防护、WAF防护、BOT行为分析为一体的安全加速解决方案。已使用内容分发网络&#xff08;CDN&#xff09;或全站加速网络&#xff08;ECDN&#xff09;…

Python-正则表达式使用

Python-正则表达式使用 一、正则表达式概述二、正则表达式元字符三、正则表达式示例四、Python中使用正则表达式的方法五、使用案例 一、正则表达式概述 正则表达式是一种用于描述字符串模式的语言。它由一系列字符组成&#xff0c;可以用来匹配和操作文本。正则表达式的特点是…

buildAdmin 后端控制器的代码分析

buildAdmin的代码生成&#xff0c;很像是 fastadmin 的生成模式&#xff0c;当我们利用数据库生成了一个控制器的时候&#xff0c;我们可以看到&#xff0c; 它的生成代码很简洁 <?phpnamespace app\admin\controller\askanswer;use app\common\controller\Backend;/*** 回…

day17-高速缓冲区的管理机制

1.目的 用户与磁盘进行文件交互时的流程 磁盘与高速缓冲区的关系 加深块设备驱动的理解 hash 循环链表 单链表的使用方法 2.高速缓冲区的工作流程 高速缓冲区中存储这对应的块设备驱动的数据 当从块设备中读取数据的时候&#xff0c;OS首先会从高速缓冲区中进行检索&#xff0…

Web UI 自动化测试方案(超级干货)看完不会你找我!

项目讨论 一、项目中符合自动化测试的部分有哪些&#xff1f;(目标和范围 scope&#xff0c; 准入准出标准) 1、稳定的需求点、变动较少的页面 2、每日构建后的测试验证 daily build 3、比较频繁的回归测试 4、需要在多平台上运行的相同测试案例、组合遍历型的测试、大量的重…

openssl1.0.2版本Windows安装问题

之前安装过1.1版本&#xff0c;Windows环境下C 安装OpenSSL库 源码编译及使用&#xff08;VS2019&#xff09;_vs2019安装openssl_肥宝Fable的博客-CSDN博客 后来发现linux编译不过&#xff0c;以为是版本问题&#xff0c;相差太大&#xff0c;所以降一下版本&#xff0c;以免…

Idea远程debug

Idea远程debug 一、方法 1.1、启动时加参数 java -agentlib:jdwptransportdt_socket,servery,suspendn,address5005 -jar remote-debug-0.0.1-SNAPSHOT.jar1.2、运行时加参数 在没有显式-agentlib:jdwp参数的情况下进行远程调试&#xff1a; 首先&#xff0c;确保您的Sprin…

【unity实战】unity3D中的PRG库存系统和换装系统(附项目源码)

文章目录 先来看看最终效果前言素材简单绘制库存UI前往mixamo获取人物模型动画获取一些自己喜欢的装备物品模型库存系统换装系统装备偏移问题添加消耗品最终效果源码完结 先来看看最终效果 前言 之前2d的换装和库存系统我们都做过不少了&#xff0c;这次就来学习一个3d版本的&…

如何解决找不到vcruntime140_1.dll问题,亲测有效的5个解决方法分享

在您平常在电脑上正常操作时&#xff0c;有时可能会碰到一个很常见的困扰&#xff0c;那就是弹出一条“找不到vcruntime140_1.dll”的报错信息。这种情况常常是因为咱们在点击启动某个应用程序或者执行某项任务时&#xff0c;系统所需的一款叫作"vcruntime140_1.dll"…

15. Spring源码篇之获取方法参数名

简介 通常在没有显示的指定beanName的时候&#xff0c;都是会根据要注入的类型以及方法名&#xff0c;属性名或者参数名来找Bean&#xff0c;方法名属性名还好说&#xff0c;但是参数名就有点难获取&#xff0c;jdk也并没有给我们提供获取的方法 在Spring中主要以两种方式来获…

深入理解 synchronized 原理

目录 一. 前言 二. Java对象的内存布局 2.1. 对象头 2.2. Mark Word 2.3. Class Metadata Pointer 2.4. Length 三. 偏向锁 3.1. 偏向锁的工作流程 3.2. 偏向失效 3.2.1. 误区一 3.3. 偏向撤销 3.3.1. 误区一 3.4. 偏向撤销的底层实现 3.5. HashCode与偏向撤销 …

【算法萌新闯力扣】:最常见的单词

力扣热题&#xff1a;最常见的单词 开篇 今天是备战蓝桥杯的第17天&#xff0c;今天到现在刷了5道算法题&#xff0c;分享一道很不错的题目。 题目链接:819.最常见的单词 题目描述 代码思路 根据题目要求&#xff0c;我的思路是&#xff1a;建立一个哈希表&#xff0c;把每个…

释放搜索潜力:基于Docker快速搭建ES语义检索系统(快速版),让信息尽在掌握

搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…

uni-app(1)pages. json和tabBar

第一步 在HBuilderX中新建项目 填写项目名称、确定目录、选择模板、选择Vue版本&#xff1a;3、点击创建 第二步 配置pages.json文件 pages.json是一个非常重要的配置文件&#xff0c;它用于配置小程序的页面路径、窗口表现、导航条样式等信息。 右键点击pages&#xff0c;按…

Leetcode刷题详解——打家劫舍 II

1. 题目链接&#xff1a;213. 打家劫舍 II 2. 题目描述&#xff1a; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 &#xff0c;这意味着第一个房屋和最后一个房屋是紧挨着的。同时&#xff0c;相邻…