您的当前位置:首页正文

Android 设置默认桌面Launcher

2024-10-23 来源:个人技术集锦

一、概述

二、前提条件

三、思路分析

四、实现方法

五、业务扩展


一、概述

在android系统开发中,Launcher是常用常见常修改的,有时会出现多个Launcher的情况,怎么设置默认launcher就比较重要了。本文针对不内置在系统内的应用,怎么去设置默认Luancher做一个分享。

二、前提条件

前提条件是虽然应用不内置于系统中,但是还是需要系统签名的,不然是不够权限去修改的。所以此方案适合拥有相应系统签名的开发者,多见于各种工具或者中间件的开发。

三、思路分析

1、原生默认桌面是Launcher3的桌面,对应的包名类名为:com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher;

2、设置其他应用为默认launcher,实质上是替换掉原来的,通过PackageManager的replacePreferredActivity方法可进行替换;

3、默认Launcher实质上对应的是FLAG有Intent.CATEGORY_HOME的应用;

4、最后可根据实际情况把默认包名用settings存储起来,方便后面查询;

四、实现方法

public boolean setDefaultLauncher(Context context,String pkg, String cls) {
        final PackageManager mPm = context.getPackageManager();
        ComponentName DefaultLauncher = new ComponentName(pkg, cls);
        ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
        ComponentName currentDefaultHome;
        boolean isPkgExist = false;
        try {
            Class<?> packageManager = Class.forName("android.content.pm.PackageManager");
            Method getHomeActivities = packageManager.getMethod("getHomeActivities", List.class);
            getHomeActivities.setAccessible(true);
            currentDefaultHome = (ComponentName) getHomeActivities.invoke(mPm, homeActivities);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        ComponentName[] mHomeComponentSet = new ComponentName[homeActivities.size()];
        for (int i = 0; i < homeActivities.size(); i++) {
            final ResolveInfo candidate = homeActivities.get(i);
            final ActivityInfo ai = candidate.activityInfo;
            if (ai.packageName.equals(pkg) && ai.name.equals(cls)){
                isPkgExist = true;
            }
            ComponentName activityName = new ComponentName(ai.packageName, ai.name);
            mHomeComponentSet[i] = activityName;
        }
        IntentFilter mHomeFilter = new IntentFilter(Intent.ACTION_MAIN);
        mHomeFilter.addCategory(Intent.CATEGORY_HOME);
        mHomeFilter.addCategory(Intent.CATEGORY_DEFAULT);
        if (!isPkgExist){
            Toast.makeText(context, "应用不存在", Toast.LENGTH_SHORT).show();
            return false;
        }
        try {
            Class<?> packageManager = Class.forName("android.content.pm.PackageManager");
            Method replacePreferredActivity = packageManager.getMethod("replacePreferredActivity",
                    IntentFilter.class, int.class, ComponentName[].class, ComponentName.class);
            replacePreferredActivity.setAccessible(true);
            replacePreferredActivity.invoke(mPm, mHomeFilter,
                    IntentFilter.MATCH_CATEGORY_EMPTY, mHomeComponentSet, DefaultLauncher);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        Settings.Secure.putString(context.getContentResolver(),"xxx.xx.x",pkg+"/"+cls);
       
        return true;
    }

可以看到基本都是通过反射系统api去实现的。关键步骤其实就是

1、通过 getHomeActivities方法获得目前有HOME标签的应用,判断是否传入的包名类名包含其中。

2、通过replacePreferredActivity方法替换默认launcher。

3、把默认launcher包名类名信息放进Settings.Secure中保存。

五、业务扩展

如果调用此方法的是你的launcher里的,业务需求是:切换默认launcher,切换后跳转到默认launcher。

我们可以在方法的最后延迟一定时间后,跳转到默认launcher。

    public boolean setDefaultLauncher(Context context,String pkg, String cls) {
        final PackageManager mPm = context.getPackageManager();
        ComponentName DefaultLauncher = new ComponentName(pkg, cls);
        ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
        ComponentName currentDefaultHome;
        boolean isPkgExist = false;
        try {
            Class<?> packageManager = Class.forName("android.content.pm.PackageManager");
            Method getHomeActivities = packageManager.getMethod("getHomeActivities", List.class);
            getHomeActivities.setAccessible(true);
            currentDefaultHome = (ComponentName) getHomeActivities.invoke(mPm, homeActivities);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        ComponentName[] mHomeComponentSet = new ComponentName[homeActivities.size()];
        for (int i = 0; i < homeActivities.size(); i++) {
            final ResolveInfo candidate = homeActivities.get(i);
            final ActivityInfo ai = candidate.activityInfo;
            if (ai.packageName.equals(pkg) && ai.name.equals(cls)){
                isPkgExist = true;
            }
            ComponentName activityName = new ComponentName(ai.packageName, ai.name);
            mHomeComponentSet[i] = activityName;
        }
        IntentFilter mHomeFilter = new IntentFilter(Intent.ACTION_MAIN);
        mHomeFilter.addCategory(Intent.CATEGORY_HOME);
        mHomeFilter.addCategory(Intent.CATEGORY_DEFAULT);
        if (!isPkgExist){
            Toast.makeText(context, "应用不存在", Toast.LENGTH_SHORT).show();
            return false;
        }
        try {
            Class<?> packageManager = Class.forName("android.content.pm.PackageManager");
            Method replacePreferredActivity = packageManager.getMethod("replacePreferredActivity",
                    IntentFilter.class, int.class, ComponentName[].class, ComponentName.class);
            replacePreferredActivity.setAccessible(true);
            replacePreferredActivity.invoke(mPm, mHomeFilter,
                    IntentFilter.MATCH_CATEGORY_EMPTY, mHomeComponentSet, DefaultLauncher);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        Settings.Secure.putString(context.getContentResolver(),"xxx.xx.x",pkg+"/"+cls);
        //延迟2秒后,跳转到默认launcher中
        new Handler().postDelayed(() -> {
            String currentPkgName = context.getApplicationContext().getPackageName();
            if (currentPkgName.equals(pkg)){
                return;
            }
            if (context instanceof Activity){
                ((Activity) context).finish();
                killPackage(context, currentPkgName);
            }
            Intent home = new Intent(Intent.ACTION_MAIN);
            home.addCategory(Intent.CATEGORY_HOME);
            context.startActivity(home);
        }, 2000);
        return true;
    }

至此,就能在应用侧设置默认launcher了。别忘了加上系统签名。

显示全文