Java反射
Android Launcher3
最近修改官方的 Launcher3 启动器,需求是要在桌面上添加自己的应用入口。简单说就是要生成一个快捷方式,单击进入我们的 Activity 界面。
先说下 Launcher3 是如何生成桌面图标的:
Launcher3 首先查找本地的带有LAUNCHER的Activity 如下 :
<category android:name="android.intent.category.LAUNCHER"/>
代码如下:
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
mainIntent.setPackage(packageName);
long ident = Binder.clearCallingIdentity();
try {
List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent, 0 ,user.getIdentifier());
return apps;
} finally {
Binder.restoreCallingIdentity(ident);
}
然后返回:List<ResolveInfo> apps
接着系统根据 apps 生成 List<LauncherActivityInfo> lais 返回给 Launcher3 渲染图标。
代码如下:
public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
List<ResolveInfo> activities = null;
try {
activities = mService.getLauncherActivities(packageName, user);
} catch (RemoteException re) {
throw new RuntimeException("Failed to call LauncherAppsService");
}
if (activities == null) {
return Collections.EMPTY_LIST;
}
ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>();
final int count = activities.size();
for (int i = 0; i < count; i++) {
ResolveInfo ri = activities.get(i);
long firstInstallTime = 0;
try {
firstInstallTime = mPm.getPackageInfo(ri.activityInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES).firstInstallTime;
} catch (NameNotFoundException nnfe) {
// Sorry, can't find package
}
LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri, user,
firstInstallTime);
if (DEBUG) {
Log.v(TAG, "Returning activity for profile " + user + " : "
+ lai.getComponentName());
}
lais.add(lai);
}
return lais;
}
到这里就知道了,只要我们多添加一个 LauncherActivityInfo 就可以实现在 Launcher3 上添加自己的 Activity 入口了。
可以看到** LauncherActivityInfo** 在实例化的时候需要 三个参数:
LauncherActivityInfo(Context context, ResolveInfo info, UserHandle user,long firstInstallTime) {
this(context);
mResolveInfo = info;
mActivityInfo = info.activityInfo;
mComponentName = LauncherApps.getComponentName(info);
mUser = user;
mFirstInstallTime = firstInstallTime;
}
并且是没有添加访问修饰符的,说明他在其他包是不可以访问的,如果你是在相同的包下就不用继续阅读以下内容了。
假设你是在其他包下调用,你是访问不到的,这时候就要用到我们的主角 反射 了
首先,我们得准备那三个参数,然后在传进去反射里面,具体代码如下:
/*添加自己的主题应用入口*/
Intent intent = new Intent();
intent.addCategory("com.android.launcher4.Theme");
intent.setAction("com.android.launcher4.Theme");
long firstInstallTime = System.currentTimeMillis();
List<ResolveInfo> resolveInfos = mPm.queryIntentActivities(intent, PackageManager.GET_INTENT_FILTERS);
ResolveInfo ri = null;
if (resolveInfos != null) {
ri = resolveInfos.get(0);
}
Class clazz = LauncherActivityInfo.class;
try {
/**
* 这里是重点!
* 这里是重点!
* 这里是重点!
**/
Constructor constructor = clazz.getDeclaredConstructor(new Class[]{Context.class, ResolveInfo.class, UserHandle.class, long.class});
constructor.setAccessible(true);
LauncherActivityInfo lai = (LauncherActivityInfo) constructor.newInstance(new Object[]{mContext, ri, user.getUser(), firstInstallTime});
compatList.add(new LauncherActivityInfoCompatVL(lai));
} catch (Exception e) {
e.printStackTrace();
}
运行:
Screenshot_20161229-093418.png到这里我们就完成了用反射添加自己的 Activity 入口了!
网友评论