Android插件化-Broadcast篇

47 阅读3分钟

public final ArrayList activities = new ArrayList(0); public final ArrayList receivers = new ArrayList(0); public final ArrayList providers = new ArrayList(0); public final ArrayList services = new ArrayList(0);

这里我们只需要关心存储着类对象Activity的receivers列表,注意此Activity非彼Activity,这里的Activity也是PackageParser类的一个内部类而已,其声明如下:

public final static class Activity extends Component implements Parcelable { public final ActivityInfo info; //其它实现 ........ }

该类又实现了Component类,该类不例外的也是PackageParser类的一个内部类,所以我们继续往上看。

public static abstract class Component { public final ArrayList intents; public final String className;

public Bundle metaData; public Package owner; /** The order of this component in relation to its peers */ public int order;

ComponentName componentName; String componentShortName; //其他方法实现 ...... }

注意对于静态注册在插件AndroidManifest.xml文件中的Receiver,宿主需要知道Receiver的className以及其对应注册的Action,这样在宿主中才能实现广播的中转;因此整个解析过程也就需要解析出广播的ClassName以及其注册的Action就OK了。

对于ClassName在Component已经出现,而对于Action我们则继续看Component类中的intents这个列表,该列表中所存储的对象对应的类集成至IntentInfo,因此我们还需要继续往上看才行。

public static abstract class IntentInfo extends IntentFilter { public boolean hasDefault; // 其他属性以及方法 .... }

而该内部类又继承至类IntentFilter,这里IntentFilter则不再是PackageParser类的内部类了,它就是我们在动态注册Reciver所用到的IntentFilter;而在IntentFilter类中我们则能够直接通过其mActions属性拿到当前ClasName对应Receiver所静态注册的Action了。

2、插件中静态注册广播解析实现

接下来就是通过反射的方式调用PackageParser的parsePackage获取到PackageParser$Package对象,接着就是一步一步的对该对象进行解析了。对应源码如下:

public static void parsePackage(String apkPath) { try { //根据插件本地存储的文件地址生成对应的文件 File file = new File(apkPath); if (!file.exists()) { Log.i(TAG, "parse plugin receiver apk not exist"); return; } Log.i(TAG, "parse package path is " + apkPath); //获取到PackageParser类对象 Class<?> cls = Class.forName("android.content.pm.PackageParser"); Object packageParserObj = RefInvoke.createObject(cls, null, null); if (null == packageParserObj) { Log.i(TAG, "parse package create packageParser object failed"); return; } //调用parsePackage方法 Object packageObj = RefInvoke.on(packageParserObj, "parsePackage", new Class[]{File.class, int.class}) .invoke(file, PackageManager.GET_RECEIVERS); if (null == packageObj) { Log.i(TAG, "parse package get packageObj failed"); return; } //获取PackageParser$Package对象中的receivers列表 List receivers = (List) RefInvoke.getFieldValue(RefInvoke.getField(packageObj.getClass(), "receivers"), packageObj); if (null == receivers) { Log.i(TAG, "parse package get receivers failed"); return; } //遍历receivers列表获取AndroidManifest.xml文件中所注册的Receiver信息 for (Object receiver : receivers) { parseAction(receiver, apkPath); } } catch (Exception e) { Log.i(TAG, "parse package failed " + e); } }

上面代码就是通过反射的方式调用PackageParser的parsePackage方法,并遍历获取到的receivers列表。接下来就就是对receivers列表中的每个Receiver相关信息进行解析了。

private static void parseAction(Object receiver, String path) { try { //根据反射获取到PackageParserComponent对象中的intents列表Class<?>cls=RefInvoke.getClass("android.content.pm.PackageParserComponent对象中的intents列表 Class<?> cls = RefInvoke.getClass("android.content.pm.PackageParserComponent"); ArrayList intents = (ArrayList) RefInvoke.getFieldValue(RefInvoke.getField(cls, "intents"), receiver); if (null == intents || 0 == intents.size()) { return; } //获取该Receiver对应的ClassName String clsName = (String) RefInvoke.getFieldValue(RefInvoke.getField(cls, "className"), receiver); Log.i(TAG, "parseAction current receiver name is " + clsName); //根据插件所在文件地址生成对应的ClassLoader并根据获取到的ClassName生成对应的对象 Object receiverObj = creatReceiverObj(clsName, path); if (null == receiverObj) { Log.i(TAG, "parseAction create receiver obj failed"); return; }

//接着就是遍历该Receiver中所注册的Action并存储在内存中以便宿主在接收到对应Action的广播之后能够直接进行转发 for (IntentFilter intentFilter : intents) { Class<?> intentFilterCls = RefInvoke.getClass("android.content.IntentFilter"); Log.i(TAG, "field: " + RefInvoke.getField(intentFilterCls, "mActions")); List actions = (List) RefInvoke.getFieldValue(RefInvoke.getField(intentFilterCls, "mActions"), intentFilter);

for (String action : actions) { registerActionToReceiver(action, receiverObj); } } } catch (Exception e) { Log.i(TAG, "parseAction failed " + e); } }

private static Object creatReceiverObj(String clsName, String path) { try { DexClassLoader dexClassLoader = DeHostDexClassloader.getInstance().getDexClassLoader(DePluginApplication.getContext(), path); Class<?> cls = dexClassLoader.loadClass(clsName); return RefInvoke.createObject(cls, null, null); } catch (Exception e) { Log.i(TAG, "createReceiverObj failed " + e.getCause()); } return null; }

private static void registerActionToReceiver(String action, Object receiverObj) { List receiverObjs = mActionToReceiverMap.get(action); if(null == receiverObjs){ receiverObjs = new ArrayList<>(); mActionToReceiverMap.put(action, receiverObjs); } receiverObjs.add(receiverObj); }

最后就是宿主中预埋的Receiver在接收到某个Action之后转发给插件中对应的广播接收器了。

public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Log.i(TAG, "action is " + action); List receiverObjs = PluginReceiverParseUtils.getReceiverObjByAction(action); if (null != receiverObjs) { for(Object obj : receiverObjs){ ((BroadcastReceiver) obj).onReceive(context, intent); } Log.i(TAG, "translate receiver succ"); } else { Log.i(TAG, "not exist plugin receiver"); } } 4、总结

相较于Activity和Service插件化来说,Receiver的插件化则稍显简单;我们只需要通过PackageParser类中的parsePackage方法解析出插件中的静态注册的广播,接着预埋在宿主中的广播接收器在接收到对应Action广播之后再直接转发给插件中的广播接收器就OK了;而不需要通过反射的方式与Activitythread类打交道。