android并没有提供获取四大组件的intentFilter信息功能,例如获取其它应用的activity中的action定义等,因为系统返回的ComponentInfo中删除了IntentFilter字段,如果要获取这些信息只能用其它方法。这里介绍两种方法,一种是调用PackageManager中的getAllIntentFilters方法,返回一个List<IntentFilter>集合,这个是系统api,只能反射调用,不过它返回的是所有intentfilter,里面没有component信息,所以不知道是哪个组件下的,另一种是反射调用系统PackageParser类,手动解析apk获取应用所有信息。第三种方法是直接解析AndroidManifest.xml,这个可以利用第三方插件实现,或者调用系统的AssetManager类实现(关于AssetManager解析xml请参考我写的另一篇文章《android反编译xml资源文件》),下面给出第二种方法代码:
这里不用反射调用信息,我们直接创建一个系统子类,在里面填写需要的信息即可,首先在java目录下创建包android.content.pm,然后创建以下两个类,用于获取最终信息:
public class PackageParser$Package {
//用到的字段
public final ArrayList<PackageParser$Component> activities = new ArrayList<>(0);
public final ArrayList<PackageParser$Component> receivers = new ArrayList<>(0);
public final ArrayList<PackageParser$Component> providers = new ArrayList<>(0);
public final ArrayList<PackageParser$Component> services = new ArrayList<>(0);
//可以在这里添加其它字段,参考系统源码PackageParser.Package类
//...
}
public class PackageParser$Component {
public ArrayList<IntentFilter> intents; //这个就是我们要的数据
public String className; //这个类名也要有
public Bundle metaData;
public Package owner;
public int order;
ComponentName componentName;
String componentShortName;
}
最后上具体实现代码:
public class PackageUtils {
//根据包名获取Package信息
public static PackageParser$Package getPackageInfo(Context context, String packageName) {
ApplicationInfo info = null;
try {
info = context.getPackageManager().getApplicationInfo(packageName, 0);
if (info.sourceDir != null) {
return getPackageInfo(new File(info.sourceDir));
}
} catch (Exception e) {
Log.e("walx", e.toString());
}
return null;
}
public static PackageParser$Package getPackageInfo(File apkFile) {
try {
Class<?> clazz = Class.forName("android.content.pm.PackageParser");
Object packageParser = newInstance(clazz, null, null);
PackageParser$Package pkg = (PackageParser$Package) invokeMethod(packageParser, "parsePackage", new Class[]{File.class, int.class}, new Object[]{apkFile, 0});
return pkg;
} catch (Exception e) {
Log.e("walx", e.toString());
}
return null;
}
private static Object newInstance(Class clazz, Class[] argsType, Object[] args) {
Object instance = null;
try {
Constructor constructor;
if (argsType == null) {
constructor = clazz.getConstructor();
constructor.setAccessible(true);
instance = constructor.newInstance();
} else {
constructor = clazz.getConstructor(argsType);
constructor.setAccessible(true);
instance = constructor.newInstance(args);
}
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
private static Object readField(Object object, String name) {
try {
Field field = object.getClass().getField(name);
field.setAccessible(true);
return field.get(object);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static Object invokeMethod(Object object, String name, Class[] argsType, Object[] args) {
try {
Method method = object.getClass().getMethod(name, argsType);
method.setAccessible(true);
return method.invoke(object, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
//调用测试
PackageParser$Package pkgInfo = PackageUtils.getPackageInfo(this, "com.android.settings");
if (pkgInfo != null) {
Log.i(TAG, "activities:" + pkgInfo.activities.size());
Log.i(TAG, "receivers:" + pkgInfo.receivers.size());
Log.i(TAG, "providers:" + pkgInfo.providers.size());
Log.i(TAG, "services:" + pkgInfo.services.size());
//...
}