PluginManifestUtil分析
PluginManifestUtil是Android PluginManager的一个工具类。只有一个公共方法setManifestInfo()
,负责解析插件apk中的androidManifest.xml文件,并将解析的信息保存到PluginInfo
中。
通过PackageManager
获取插件apk文件的PackageInfo
,保持在PluginInfo
中。
PackageInfo pkgInfo = context.getPackageManager()
.getPackageArchiveInfo(
apkPath,
PackageManager.GET_ACTIVITIES
| PackageManager.GET_RECEIVERS//
| PackageManager.GET_PROVIDERS//
| PackageManager.GET_META_DATA//
| PackageManager.GET_SHARED_LIBRARY_FILES//
// | PackageManager.GET_SERVICES//
// | PackageManager.GET_SIGNATURES//
);
// Log.d("ManifestReader: setManifestInfo", "GET_SHARED_LIBRARY_FILES="
// + pkgInfo.applicationInfo.nativeLibraryDir);
info.setPackageInfo(pkgInfo);
PackageInfo
保存有插件apk的包名、版本、注册的activities、services、receivers、providers、声明的权限等信息。
但是Android PluginManager目前只处理了activities、receivers。
查找插件apk中的lib
中的so文件,并解压到PluginBaseDir
即PluginManager
中dexInternalStoragePath
+ pluginId
+lib
下面。
File libdir = ActivityOverider.getPluginLibDir(info.getId());
try {
if(extractLibFile(zipFile, libdir)){
pkgInfo.applicationInfo.nativeLibraryDir=libdir.getAbsolutePath();
}
} finally {
zipFile.close();
}
查找过程会根据设备cpu架构copy相应的文件到PluginBaseDir
。
使用XmlManifestReader.getManifestXMLFromAPK()
读取插件apk中的manifest文件,然后通过setAttrs()
方法解析manifest文件,把activity、reciever、application的信息保存在PluginInfo
中。
ZipFile zipFile = new ZipFile(new File(apkPath), ZipFile.OPEN_READ);
ZipEntry manifestXmlEntry = zipFile.getEntry(XmlManifestReader.DEFAULT_XML);
String manifestXML = XmlManifestReader.getManifestXMLFromAPK(zipFile,
manifestXmlEntry);
...
setAttrs(info, manifestXML);
分别解析application、activity、reciever、service的信息,并绑定到PluginInfo
。
...
do {
switch (eventType) {
case XmlPullParser.START_DOCUMENT: {
break;
}
case XmlPullParser.START_TAG: {
String tag = parser.getName();
if (tag.equals("manifest")) {
namespaceAndroid = parser.getNamespace("android");
} else if ("activity".equals(parser.getName())) {
addActivity(info, namespaceAndroid, parser);
} else if ("receiver".equals(parser.getName())) {
addReceiver(info, namespaceAndroid, parser);
} else if ("service".equals(parser.getName())) {
addService(info, namespaceAndroid, parser);
}else if("application".equals(parser.getName())){
parseApplicationInfo(info, namespaceAndroid, parser);
}
break;
}
case XmlPullParser.END_TAG: {
break;
}
}
eventType = parser.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
下面已activity为例分析。
...
ResolveInfo act = new ResolveInfo();
act.activityInfo = info.findActivityByClassNameFromPkg(activityName);
do {
switch (eventType) {
case XmlPullParser.START_TAG: {
String tag = parser.getName();
if ("intent-filter".equals(tag)) {
if (act.filter == null) {
act.filter = new IntentFilter();
}
} else if ("action".equals(tag)) {
String actionName = parser.getAttributeValue(namespace,
"name");
act.filter.addAction(actionName);
} else if ("category".equals(tag)) {
String category = parser.getAttributeValue(namespace,
"name");
act.filter.addCategory(category);
} else if ("data".equals(tag)) {
// TODO parse data
}
break;
}
}
eventType = parser.next();
} while (!"activity".equals(parser.getName()));
//
info.addActivity(act);
模拟系统解析ResolveInfo
的方式,为每一个插件apk中注册的Activity生成一个ResolveInfo
,保存在PluginInfo
中,供之后获取指定Intent-Filter
的Activity、Service等使用。
目前对于intent-filter
中的data
标签没有处理。