一、概述
二、前提条件
三、思路分析
四、实现方法
五、业务扩展
在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了。别忘了加上系统签名。