Android11.0系统中添加设置开机启动App功能

编程入门 行业动态 更新时间:2024-10-26 18:18:53

Android11.0系统中添加设置开机启动App<a href=https://www.elefans.com/category/jswz/34/1771378.html style=功能"/>

Android11.0系统中添加设置开机启动App功能

Android11.0系统中添加设置开机启动App功能

  • 添加设置开机启动App功能
    • 创建数据保存
    • 添加处理设置开机启动App广播接收器
    • 添加开机广播接收器
    • 通过广播设置开机启动App

添加设置开机启动App功能

本文主要描述Android11中通过在自已的系统App中添加设置开机启动App功能,实现在系统每次启动后,根据保存的需要启动的App包名启动对应App。
如何在系统源码中添加开发自己的系统App,可以查看: Android11.0系统中添加开发系统App

创建数据保存

开机启动的App是其它应用通过广播向demo应用设置App的包名实现,需要保存用户设置的此数据,可以使用SharedPreferences或数据库,这里使用SharedPreferences来保存数据。

  1. 添加SpHelper,路径为 /vendor/yjz/demo/app/src/main/java/com/yjz/demo/util/SpHelper.java;

package com.yjz.demo.util;import android.content.Context;
import android.content.SharedPreferences;public final class SpHelper {public static final int INVALID_INT = -1;public static final String INVALID_STRING = "";private final String NAME = "demo";private final String STARTUP_APP_KEY = "startup_app";private final String STARTUP_APP_DELAY_TIME_KEY = "startup_app_delay_time";private Context mContent;private static volatile SpHelper INSTANCE;private SpHelper (Context context) {mContent = context;}public static SpHelper getInstance(Context context) {if (null == INSTANCE) {synchronized (SpHelper.class) {if (null == INSTANCE) {INSTANCE = new SpHelper(context.getApplicationContext());}}}return INSTANCE;}public void setStartupApp(String packageName) {putString(STARTUP_APP_KEY, packageName);}public String getStartupApp() {return getSp().getString(STARTUP_APP_KEY, INVALID_STRING);}public void setStartupAppDelayTime(int time) {putInt(STARTUP_APP_DELAY_TIME_KEY, time);}public int getStartupAppDelayTime() {return getSp().getInt(STARTUP_APP_DELAY_TIME_KEY, INVALID_INT);}private void putInt(String key, int value) {getSp().edit().putInt(key, value)mit();}private void putString(String key, String value) {getSp().edit().putString(key, value)mit();}private SharedPreferences getSp() {return mContent.getSharedPreferences(NAME, Context.MODE_PRIVATE);}
}
  1. 在DemoApplication中初始化,路径为 /vendor/yjz/demo/app/src/main/java/com/yjz/demo/DemoApplication.java;

package com.yjz.demo;import android.app.Application;
import android.util.Log;import com.yjz.demo.util.SpHelper;public class DemoApplication extends Application {private static final String TAG = DemoApplication.class.getSimpleName();@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "DemoApplication onCreate--->");SpHelper.getInstance(this);}
}
  1. 通常使用SharedPreferences时,数据是保存在 /data/data/com.yjz.demo/shared_prefs/demo.xml下,demo应用是开机自启动的,此时在DemoApplication的onCreate()方法中操作SharedPreferences时,会报错无法访问,这是因为系统开机但用户未解锁时,系统是在安全的“直接启动”模式下运行,无法访问凭据加密存储(这是默认存储位置,仅在用户解锁设备后可用),如果需要访问数据,应用就要设置为支持设备加密存储(该存储位置在“直接启动”模式下和用户解锁设备后均可使用) ,是在AndroidManifest.xml中配置,路径为 /vendor/yjz/demo/app/src/main/AndroidManifest.xml;

    android:directBootAware=“true”
    android:defaultToDeviceProtectedStorage=“true”
    此时SharedPreferences的文件位置:/data/user_de/0/com.yjz.demo/shared_prefs/demo.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android=""xmlns:tools=""package="com.yjz.demo"android:sharedUserId="android.uid.system"><applicationandroid:name=".DemoApplication"android:allowBackup="false"android:directBootAware="true"android:defaultToDeviceProtectedStorage="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:persistent="true"android:supportsRtl="true"android:theme="@style/DemoNoActionBarTheme"tools:targetApi="31"></application></manifest>

添加处理设置开机启动App广播接收器

  1. 添加StartupAppReceive,接收其它应用发送的设置开机启动App的广播,路径为 /vendor/yjz/demo/app/src/main/java/com/yjz/demo/receive/StartupAppReceive.java;

package com.yjz.demo.receive;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.util.Log;import com.yjz.demo.util.SpHelper;public class StartupAppReceive extends BroadcastReceiver {private static final String TAG = "StartupAppReceive";@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if ("com.yjz.demo.ACTION_STARTUP_APP".equals(action)) {String appPackageName = intent.getStringExtra("startup_app");int delayTime = intent.getIntExtra("startup_app_delay_time", 0);Log.d(TAG, "startup app " + appPackageName + "  delay time " + delayTime);if (null == appPackageName || "".equals(appPackageName)) {SpHelper.getInstance(context).setStartupApp("");} else {ApplicationInfo appInfo = getApplicationInfo(context, appPackageName);if (null != appInfo) {SpHelper.getInstance(context).setStartupApp(appPackageName);if (delayTime > 0) {ChivalrousSpHelper.getInstance(context).setStartupAppDelayTime(delayTime);}} else {Log.w(TAG, "set startup app fail, app not existed " + appPackageName);}}}}public ApplicationInfo getApplicationInfo(Context context, String packageName) {ApplicationInfo info = null;try {info = context.getPackageManager().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);} catch (PackageManager.NameNotFoundException e) {e.printStackTrace();return null;}return info;}}
  1. 注册StartupAppReceive广播,路径为 /vendor/yjz/demo/app/src/main/AndroidManifest.xml;
//********省略代码******<receiverandroid:name=".receive.StartupAppReceive"android:enabled="true"android:exported="true"><intent-filter><action android:name="com.yjz.demo.ACTION_STARTUP_APP" /></intent-filter></receiver>//********省略代码******

添加开机广播接收器

  1. 添加BootCompletedReceive,监听系统开机广播,根据保存的开机启动App信息,启动App,路径为 /vendor/yjz/demo/app/src/main/java/com/yjz/demo/receive/BootCompletedReceive.java;
    收到开机广播后就启动设置的App,测试时发现会偶尔会有App无法启动的情况,添加一定的延迟可以解决;同时支持上层Api接口设置延时启动时间,单位秒;

package com.yjz.demo.receive;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.yjz.demo.util.SpHelper;public class BootCompletedReceive extends BroadcastReceiver {private static final String TAG = "DemoBootCompletedReceive";@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {//如果设置了开机启动app,进行启动startupApp(context);}}private void startupApp(Context context) {String appPackageName = SpHelper.getInstance(context).getStartupApp();if (null == appPackageName || SpHelper.INVALID_STRING.equals(appPackageName)) {Log.d(TAG, "no startup app");return;}int delayTime = SpHelper.getInstance(context).getStartupAppDelayTime();if (delayTime <= 0) {delayTime = 0;}final int startDelayTime = delayTime + 3;new Thread() {@Overridepublic void run() {try {Log.d(TAG, "startup app delay " + startDelayTime);Thread.sleep(startDelayTime * 1000);} catch (InterruptedException e) {e.printStackTrace();}if (launchApp(context, appPackageName)) {Log.d(TAG, "execute startup app success");} else {Log.e(TAG, "execute startup app fail");}}}.start();}public boolean launchApp(Context context, String packageName) {if (null == packageName || "".equals(packageName)) {return false;}ApplicationInfo info = getApplicationInfo(context, packageName);if (null != info) {Intent mLaunchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);if (mLaunchIntent != null) {List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(mLaunchIntent, 0);if (list != null && list.size() > 0) {//非Activity上下文中启动activity,需要添加标识Intent.FLAG_ACTIVITY_NEW_TASK,否则startActivityAsUser相关方法会报错mLaunchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivityAsUser(mLaunchIntent, UserHandle.SYSTEM);return true;} else {Log.w(TAG, "not query intent " + packageName);}} else {Log.w(TAG, "not get lanuch intent " + packageName);}} else {Log.w(TAG, "not found app " + packageName);}return false;}}
  1. 注册BootCompletedReceive,修改AndroidManifest.xml,路径为 /vendor/yjz/demo/app/src/main/AndroidManifest.xml;
//********省略代码******//添加权限
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />//********省略代码******<receiverandroid:name=".receive.BootCompletedReceive"android:enabled="true"android:exported="true"><intent-filter android:priority="1000"><action android:name="android.intent.action.BOOT_COMPLETED" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></receiver>//********省略代码******

通过广播设置开机启动App

  1. 其它应用可以通过广播向demo应用中设置要开机启动的应用包名,如果包名为空,是取消之前的保存。
    注意:系统禁止后台应用发送广播,想要发送,需要指明处理此广播的应用
public boolean setStartupApp(Context context, String packageName) {if (null != packageName && !"".equals(packageName)) {try {PackageInfo packinfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);String[] list = packinfo.requestedPermissions;boolean hasPermission = false;if (null != list) {for (int i = 0; i < list.length; i++) {if (Manifest.permission.QUERY_ALL_PACKAGES.equals(list[i])) {hasPermission = true;break;}}}if (!hasPermission) {throw new RuntimeException("need permission " + Manifest.permission.QUERY_ALL_PACKAGES);}} catch (PackageManager.NameNotFoundException e) {throw new RuntimeException(e);}try {ApplicationInfo info = context.getPackageManager().getApplicationInfo(packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES);if (null == info) {return false;}} catch (PackageManager.NameNotFoundException e) {e.printStackTrace();return false;}}Intent intent = new Intent("com.yjz.demo.ACTION_STARTUP_APP");intent.putExtra("startup_app", packageName);intent.putExtra("startup_app_delay_time", 5);//如果不指定包名,切到后台发送,会报后台无法发送intent.setPackage("com.yjz.demo");context.sendBroadcast(intent);return true;} 

更多推荐

Android11.0系统中添加设置开机启动App功能

本文发布于:2024-02-11 14:13:53,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1681415.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:功能   系统   App

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!