Android设置默认Launcher(源码实现和动态代码实现)

来源:互联网 发布:淘宝充话费怎么充 编辑:程序博客网 时间:2024/05/21 17:23

采用修改Android Framework 源码的方式


步骤:在androidStudio中SDK–>sources–>android-25(对应api源码)–>com–>android–>server–>am–>ActivityManagerService类:

这里写图片描述

在ActivityManagerService类中,编辑

找到startHomeActivityLocked():

 boolean startHomeActivityLocked(int userId, String reason) {        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL                && mTopAction == null) {            // We are running in factory test mode, but unable to find            // the factory test app, so just sit around displaying the            // error message and don't try to start anything.            return false;        }        Intent intent = getHomeIntent();        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);        if (aInfo != null) {            intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));            // Don't do this if the home app is currently being            // instrumented.            aInfo = new ActivityInfo(aInfo);            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);            ProcessRecord app = getProcessRecordLocked(aInfo.processName,                    aInfo.applicationInfo.uid, true);            if (app == null || app.instrumentationClass == null) {                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);                mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);            }        } else {            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());        }        return true;    }

添加一段设置默认Laurncher的代码

private void setDefaultLauncher() {          String packageName = "com.android.test";    //默认launcher包名        String className = "com.android.test.MainActivity";    //默认launcher入口        Slog.i(TAG, "defautl packageName = " + packageName + ", default className = " + className);          IPackageManager pm = ActivityThread.getPackageManager();          //清除当前默认launcher         ArrayList<IntentFilter> intentList = new ArrayList<IntentFilter>();          ArrayList<ComponentName> cnList = new ArrayList<ComponentName>();          mContext.getPackageManager().getPreferredActivities(intentList, cnList, null);          IntentFilter dhIF = null;          for(int i = 0; i < cnList.size(); i++) {              dhIF = intentList.get(i);              if(dhIF.hasAction(Intent.ACTION_MAIN) && dhIF.hasCategory(Intent.CATEGORY_HOME)) {                  mContext.getPackageManager().clearPackagePreferredActivities(cnList.get(i).getPackageName());              }          }          //获取所有launcher activity         Intent intent = new Intent(Intent.ACTION_MAIN);          intent.addCategory(Intent.CATEGORY_HOME);          List<ResolveInfo> list = new ArrayList<ResolveInfo>();          try {              list = pm.queryIntentActivities(intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), PackageManager.MATCH_DEFAULT_ONLY);          }catch (RemoteException e) {              throw new RuntimeException("Package manager has died", e);          }        // get all components and the best match          IntentFilter filter = new IntentFilter();          filter.addAction(Intent.ACTION_MAIN);          filter.addCategory(Intent.CATEGORY_HOME);          filter.addCategory(Intent.CATEGORY_DEFAULT);        final int N = list.size();          Slog.d(TAG, "N:::::hyhyhyhy:::: = " + N);          //设置默认launcher         ComponentName launcher = new ComponentName(packageName, className);          ComponentName[] set = new ComponentName[N];          int defaultMatch = 0;          for (int i = 0; i < N; i++) {              ResolveInfo r = list.get(i);              set[i] = new ComponentName(r.activityInfo.packageName, r.activityInfo.name);              Slog.d(TAG, "r.activityInfo.packageName:::::hyhyhyhy:::: = " + r.activityInfo.packageName);            Slog.d(TAG, "r.activityInfo.name:::::hyhyhyhy:::: = " + r.activityInfo.name);            if(launcher.getClassName().equals(r.activityInfo.name)) {                defaultMatch = r.match;            }        }        //将设置的默认launcher,添加到系统偏好                        try {              pm.addPreferredActivity(filter, defaultMatch, set, launcher);          } catch (RemoteException e) {              throw new RuntimeException("factorytest.MainActivity : Package manager has died", e);          }       }

调用设置的代码

boolean startHomeActivityLocked(int userId, String reason) {    if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL                && mTopAction == null) {            // We are running in factory test mode, but unable to find            // the factory test app, so just sit around displaying the            // error message and don't try to start anything.            return false;    }    //调用添加的默认设置Launcher代码    setDefaultLauncher();    //...................省略部分代码    return true;}

以上该方法的教程: http://huamm.blog.51cto.com/5646020/1550305

修改完后保存,利用AndroidStudio重新编译项目。

测试结果

android 7.0模拟器上:

开启后,并未实现自动设置成默认的Launcher效果:

这里写图片描述

动态代码设置默认Launcher


前言

修改源码比较麻烦,若是采用动态代码的方式就比较可操作性。

动态代码的编写

这里将设置默认Launcher的操作封装到了一个类中,采用Koltin编程,已经添加与Java交互的注解,也可以使用在Java代码中。

class LauncherUtils {    /**     * 设置系统默认的Launcher     */    fun setDefaultLauncher(context: Context, mainActivityName: String) {        clearDefaultLauncherApps(context)        var allLauncherList = getAllLauncherApps(context)        Log.i(tag," 设备上安装的Launcher个数 : ${allLauncherList.size}  ")        var intentFilter = IntentFilter(Intent.ACTION_MAIN)        intentFilter.addCategory(Intent.CATEGORY_DEFAULT)        intentFilter.addCategory(Intent.CATEGORY_HOME)        var launcher = ComponentName(context.packageName, mainActivityName)        var componentNameSet = kotlin.arrayOfNulls<ComponentName>(allLauncherList.size)        var defaultMatchLauncher = 0        for (i in allLauncherList.indices) {            var resolveInfo = allLauncherList[i]            componentNameSet[i] = ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)            var stringBuffer=createMatchName(launcher)            Log.i(tag," 索引是$i  将要设置成默认的Launcher:${stringBuffer.toString()}    信息名:${resolveInfo.activityInfo.name} ")            if (stringBuffer.toString().equals(resolveInfo.activityInfo.name)) {                defaultMatchLauncher = resolveInfo.match                Log.i(tag," 匹配到的match : ${resolveInfo.match}  ")            }        }        try {            context.packageManager.addPreferredActivity(intentFilter, defaultMatchLauncher, componentNameSet, launcher)        } catch (e: Exception) {            e.printStackTrace()        }    }    /**     * 创建匹配的名字     */    fun  createMatchName(launcher:ComponentName ):StringBuffer{        var stringBuffer=StringBuffer()        stringBuffer.append(launcher.packageName)        stringBuffer.append(".")        stringBuffer.append(launcher.className)        return  stringBuffer    }    /**     * 清除当前默认的Launcher     */    fun clearDefaultLauncherApps(context: Context) {        var packageManager = context.packageManager        var intentList = ArrayList<IntentFilter>()        var componetNameList = ArrayList<ComponentName>()        //查询到首先的Activity        packageManager.getPreferredActivities(intentList, componetNameList, null)        try {            for (i in intentList.indices) {                var intentFilter = intentList[i]                //筛选除首先的Launcher中主界面                if (intentFilter.hasAction(Intent.ACTION_MAIN) && intentFilter.hasCategory(Intent.CATEGORY_HOME)) {                    Log.i(tag," 清空的Launcher包名: ${componetNameList[i].packageName}")                    packageManager.clearPackagePreferredActivities(componetNameList[i].packageName)                }            }        }catch (e:Exception){            e.printStackTrace()        }    }    /**     * 获取到Android系统硬件或者手机上安装的全部的Launcher     */    fun getAllLauncherApps(context: Context): List<ResolveInfo> {        var packageManager = context.packageManager        var intent = Intent(Intent.ACTION_MAIN)        intent.addCategory(Intent.CATEGORY_HOME)        return packageManager.queryIntentActivities(intent, 0)    }    companion object {        @JvmStatic//Java代码可以调用        var instance= LauncherUtils()        val tag=LauncherUtils::class.java.simpleName    }}

运行设备

AndroidStudio自带模拟器,系统5.1,API22

运行程序报错

 Caused by: java.lang.SecurityException: Neither user 10058 nor current process has android.permission.SET_PREFERRED_APPLICATIONS.              at android.os.Parcel.readException(Parcel.java:1546)              at android.os.Parcel.readException(Parcel.java:1499)              at android.content.pm.IPackageManager$Stub$Proxy.addPreferredActivity(IPackageManager.java:3186)              at android.app.ApplicationPackageManager.addPreferredActivity(ApplicationPackageManager.java:1418)

在AndroidManifest.xml,根据提示,添加权限

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

运行项目,依旧报错误,无效。

傻眼的节奏,立马使用谷歌大法。

解决方式

  • 网上的来源

    1 、将手机root后,把apk强行pushsystem/app目录下,重启手机2、SET_PREFERRED_APPLICATIONS是系统权限,需要有系统的shareUs  erID和签名
  • GoogleGroup上关于这个问题的讨论。

从上面的答案可知,拿不到国内手机大厂的系统签名,可知这个只适合公司自家定制系统,一些Android系统的智能硬件


自家公司的硬件中设置默认Launcher的效果


在经过Launcher项目被系统签名后,和adb Push为系统应用后的的两个步骤后。

设置默认Launcher后,重新启动系统,输出日志如下

07-27 06:55:35.650 1435-1435/com.zhongke.launcher I/LauncherUtils:  清空Launcher的包名: com.zhongke.launcher07-27 06:55:35.651 1435-1435/com.zhongke.launcher I/LauncherUtils:  设备上安装的Launcher个数 : 2  07-27 06:55:35.651 1435-1435/com.zhongke.launcher I/LauncherUtils:  索引是0  将要设置成默认的Launcher:com.zhongke.launcher.MainActivity    信息名:com.android.launcher3.Launcher 07-27 06:55:35.651 1435-1435/com.zhongke.launcher I/LauncherUtils:  索引是1  将要设置成默认的Launcher:com.zhongke.launcher.MainActivity    信息名:com.zhongke.launcher.MainActivity 07-27 06:55:35.651 1435-1435/com.zhongke.launcher I/LauncherUtils:  匹配到的match : 1081344  

从打印的日志可知,已经设置成默认的Launcher.

调试结果如下

这里写图片描述

这里写图片描述

后续篇章,将介绍如何将开发的应用程序拥有系统的签名和将程序添为系统程序(一些公司自家智能硬件需要用到)。

PS: 若是有哪位大神知道如何实现国内手机系统中设置默认Launcher,欢迎告之。

原创粉丝点击