7.3 PackageParser
插件的解析就是将获取插件的信息填到对应的变量中。
PluginPackageParser构造方法主要逻辑如下,
1,构造PackageParser对象,
mParser = PackageParser.newPluginParser(hostContext);
2,解析插件
mParser.parsePackage(pluginFile, 0);
3,获取插件的信息,例如四大组件信息,
mPackageName = mParser.getPackageName();
mHostPackageInfo = mHostContext.getPackageManager().getPackageInfo(mHostContext.getPackageName(), 0);
List datas = mParser.getActivities();
•••
PackageParser的newPluginParser方法如下,
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP_MR1) {
if ("1".equals(SystemPropertiesCompat.get("ro.build.version.preview_sdk", ""))) {
return new PackageParserApi22Preview1(context);
} else {
return new PackageParserApi22(context);//API 20
}
} else if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
return new PackageParserApi21(context);//API 21
}
•••
根据当前的android系统版本构建不同的子类对象PackageParser。
以API21 为例论述,对应于android 5.0.
PackageParserApi21的构造方法如下,
public PackageParserApi21(Context context) throws Exception {
super(context);
initClasses();
}
initClasses方法主要是为变量赋值,如下,
sPackageParserClass = Class.forName("android.content.pm.PackageParser");
sActivityClass = Class.forName("android.content.pm.PackageParser$Activity");
sServiceClass = Class.forName("android.content.pm.PackageParser$Service");
sProviderClass = Class.forName("android.content.pm.PackageParser$Provider");
sInstrumentationClass = Class.forName("android.content.pm.PackageParser$Instrumentation");
sPermissionClass = Class.forName("android.content.pm.PackageParser$Permission");
sPermissionGroupClass = Class.forName("android.content.pm.PackageParser$PermissionGroup");
try {
sArraySetClass = Class.forName("android.util.ArraySet");
} catch (ClassNotFoundException e) {
}
•••
那么这些变量有何作用呢?
在android系统中,解析apk主要是通过PackageParser.java这个类完成的,打开这个类看看就可以很清楚了。
这些变量就是为了调用PackageParser的方法,获取获取PackageParser.java的解析信息。
解析插件通过调用PackageParser 的parsePackage方法完成, PackageParserApi21实现该方法如下,
public void parsePackage(File file, int flags) throws Exception {
/* public Package parsePackage(File packageFile, int flags) throws PackageParserException*/
mPackageParser = sPackageParserClass.newInstance();
mPackage = MethodUtils.invokeMethod(mPackageParser, "parsePackage", file, flags);
}
利用反射调用PackageParser.java的parsePackage方法完成。
PackageParser.java指代android系统中的PackageParser类,
PackageParser指DroidPlugin框架中的PackageParser类。因为这两个类的名字完全一样,所以有点不好区分。
7.4 Activity解析
调用PackageParser.java的parsePackage方法之后,插件的所有信息都保存在PackageParser.java的相关变量中, PackageParser中解析
四大组件其实就是利用反射将PackageParser.java 的相关变量读取出来然后保存在自己的变量中。
PluginPackageParser的构造方法中有关Activity解析的代码主要逻辑如下,
1,获取插件中所有的Activity,然后逐个获取Activity的其他信息。
List datas = mParser.getActivities();
PackageParserApi21的getActivities方法如下,
public List getActivities() throws Exception {
/*PackageParser.Package.activities*/
return (List) FieldUtils.readField(mPackage, "activities");
}
其实就是利用反射获取PackageParser.java的内部类Package的activities变量,定义如下,
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
public final ArrayList<Service> services = new ArrayList<Service>(0);
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>();
其实获取其他信息也完全一样。
2,获取Activity的ComponentName并保存在mActivityObjCache中,
ComponentName componentName = new ComponentName(mPackageName, mParser.readNameFromComponent(data));
synchronized (mActivityObjCache) {
mActivityObjCache.put(componentName, data);
}
PackageParserApi21的readNameFromComponent方法如下,
public String readNameFromComponent(Object data) throws Exception {
return (String) FieldUtils.readField(data, "className");
}
其实就是获取PackageParser.java的内部类Component的className变量。
3,获取Activity其他相关信息,并放入mActivityInfoCache变量中。
synchronized (mActivityInfoCache) {
ActivityInfo value = mParser.generateActivityInfo(data, 0);
fixApplicationInfo(value.applicationInfo);
if (TextUtils.isEmpty(value.processName)) {
value.processName = value.packageName;
}
mActivityInfoCache.put(componentName, value);
}
PackageParserApi21的generateActivityInfo方法如下,
public ActivityInfo generateActivityInfo(Object activity, int flags) throws Exception {
/* public static final ActivityInfo generateActivityInfo(Activity a, int flags,
PackageUserState state, int userId) */
Method method = MethodUtils.getAccessibleMethod(sPackageParserClass, "generateActivityInfo", sActivityClass, int.class, sPackageUserStateClass, int.class);
return (ActivityInfo) method.invoke(null, activity, flags, mDefaultPackageUserState, mUserId);
}
直接调用PackageParser.java的generateActivityInfo方法获取对应的ActivityInfo信息。
4,获取Activity的IntentFilter信息,保存在mActivityIntentFilterCache变量中,
List<IntentFilter> filters = mParser.readIntentFilterFromComponent(data);
synchronized (mActivityIntentFilterCache) {
mActivityIntentFilterCache.remove(componentName);
mActivityIntentFilterCache.put(componentName, new ArrayList<IntentFilter>(filters));
}
PackageParserApi21的readIntentFilterFromComponent方法如下,
public List<IntentFilter> readIntentFilterFromComponent(Object data) throws Exception {
return (List) FieldUtils.readField(data, "intents");
}
其实就是获取PackageParser.java的内部类Component的intents变量,定义如下,
public final ArrayList<II> intents;
7.5 组件解析
PluginPackageParser的构造方法中对其他组件的解析和Activity的完全相同,整个套路流程完全一样。关于Services 解析如下,
datas = mParser.getServices();
for (Object data : datas) {
ComponentName componentName = new ComponentName(mPackageName, mParser.readNameFromComponent(data));
synchronized (mServiceObjCache) {
mServiceObjCache.put(componentName, data);
}
synchronized (mServiceInfoCache) {
ServiceInfo value = mParser.generateServiceInfo(data, 0);
fixApplicationInfo(value.applicationInfo);
if (TextUtils.isEmpty(value.processName)) {
value.processName = value.packageName;
}
mServiceInfoCache.put(componentName, value);
}
List<IntentFilter> filters = mParser.readIntentFilterFromComponent(data);
synchronized (mServiceIntentFilterCache) {
mServiceIntentFilterCache.remove(componentName);
mServiceIntentFilterCache.put(componentName, new ArrayList<IntentFilter>(filters));
}
}
其他的在此不赘述了。
主要是利用反射调用android系统中的PackageParser.java。
将PluginPackageParser的相关变量填写完整。