Android插件化3-插桩式-动态广播插件化

Android插件化1-插桩式-Activity插件化:https://blog.csdn.net/hongxue8888/article/details/98887680

Android插件化2-插桩式-Service插件化:https://blog.csdn.net/hongxue8888/article/details/99165077

Github :AndroidPlugin/HxPlugin3Broadcast/

1 概述

BroadcastReceiver 中文翻译为“广播”,以下简称为 Receiver 。 Receiver 是 Android 四大组件中最简单的一个 。 它就是一个类 实现了观察者模式的类 。

Receiver分为动态广播和静态广播两种,相应的解决方案也有两种 。简单讨论一下它们的区别:

  1. 静态广播需要在 AndroidManifest 中注册 。 因为安装和 Android 系统重启时,PMS都会解析 App 中的 AndroidManifest 文件,所以静态广播的注册信息存在于 PMS 中 。

  2. 动态广播是通过写代码的方式进行注册,Context 的 registerReceiver 方法,最终调用 AMN.getDefault() .registerReceiver 方法,所以动态广播的注册信息存在于 AMS 中 。

静态广播和动态广播的区别仅在于上述注册方式的不同 。 之后,就都一样了,包括发送广播和接收广播 。

  1. 发送广播,也就是 Context 的 sendBroadcast 方法,最终会调用 AMN .getDefault().broadcastlntent ,把要发送的广播告诉 AMS 。

  2. AMS 在收到上述信息后,搜索 AMS 和 PMS 中保存的广播,看哪些广播符合条件,然后通知 App进程启动这些广播,也就是调用这些广播的 onReceive 方法 。

Receiver 的生命周期非常简单,仅一个 onReceive 方法,相当于一个Callback回调函数 。

无论是发送广播,还是接收广播,都携带一个筛选条件:intent-filter。 发送广播时,要设置 intent-filter ,这样 AMS 才知道要通知哪些广播符合 intent-filter。 我们看下面的代码 。

2 代码实现

动态广播不需要和 AMS 打交道,所以,它就是一个类 。我们只需要确保宿主 App 能加载插件中的这个动态广播类 。

2.1 pluginstand

2.1.1 PayInterfaceBroadcast

定义接口,如下:

public interface PayInterfaceBroadcast {
    void attach(Context context);
    void onReceive(Context context, Intent intent);
}

2.2 taopiaopiao

2.2.1 MyReceiver

public class MyReceiver extends BroadcastReceiver implements PayInterfaceBroadcast {
    @Override
    public void attach(Context context) {
        Toast.makeText(context, "-----绑定上下文成功-----", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "-----插件收到广播-----", Toast.LENGTH_SHORT).show();
    }
}

2.2.2 BaseActivity

    //重写广播注册
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return that.registerReceiver(receiver, filter);
    }

    //重写广播发送
    @Override
    public void sendBroadcast(Intent intent) {
        that.sendBroadcast(intent);
    }

2.2.3 TaoMainActivity

     findViewById(R.id.registerBroad).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(that,"插件",Toast.LENGTH_SHORT).show();
                //d动态注册广播
                IntentFilter intentFilter  = new IntentFilter();
                intentFilter.addAction("com.hongx.taopiaopiao.TaoMainActivity");
                registerReceiver(new MyReceiver(), intentFilter);
            }
        });

        findViewById(R.id.sendBroad).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.hongx.taopiaopiao.TaoMainActivity");
                sendBroadcast(intent);
            }
        });

2.3 app

2.3.1 ProxyBroadCast

public class ProxyBroadCast extends BroadcastReceiver {
    //需要加载插件的全类名
    private String className;
    private PayInterfaceBroadcast payInterfaceBroadcast;

    public ProxyBroadCast(String className, Context context) {
        this.className = className;

        try {
            Class<?> aClass = PluginManager.getInstance().getDexClassLoader().loadClass(className);
            Constructor constructor = aClass.getConstructor(new Class[]{});
            Object in = constructor.newInstance(new Object[]{});
            payInterfaceBroadcast = (PayInterfaceBroadcast) in;
            payInterfaceBroadcast.attach(context);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        payInterfaceBroadcast.onReceive(context, intent);
    }
}

2.3.2 ProxyActivity

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        IntentFilter intentFilter = new IntentFilter();
        for (int i = 0; i < filter.countActions(); i++) {
            intentFilter.addAction(filter.getAction(i));
        }
        return super.registerReceiver(new ProxyBroadCast(receiver.getClass().getName(),
                this), intentFilter);
    }

3 流程总结

3.1 加载插件app

点击宿主app的加载按钮,加载插件,模拟插件app的下载和加载过程,获取到插件app的Resources、DexClassLoader和PackageInfo三个对象。

3.2 跳转到插件app

点击宿主app的跳转按钮,通过Activity的插件化,跳转到插件app,Activity插件化这里不再累述,参考Android插件化1-插桩式-Activity插件化

3.3 注册广播

点击插件app的注册广播按钮,通过代码我们再看下广播注册过程:

TaoMainActivity:

IntentFilter intentFilter  = new IntentFilter();
                intentFilter.addAction("com.hongx.taopiaopiao.TaoMainActivity");
                registerReceiver(new MyReceiver(), intentFilter);

BaseActivity:

    //重写广播注册
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return that.registerReceiver(receiver, filter);
    }

ProxyActivity:

   @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        IntentFilter intentFilter = new IntentFilter();
        for (int i = 0; i < filter.countActions(); i++) {
            intentFilter.addAction(filter.getAction(i));
        }
        return super.registerReceiver(new ProxyBroadCast(receiver.getClass().getName(),
        //receiver:com.hongx.taopiaopiao.MyReceiver
                this), intentFilter);
    }

TaoMainActivity的registerReceiver覆写的是BaseActivity的registerReceiver方法,而BaseActivity的registerReceiver方法中会调用that(ProxyActivity)的registerReceiver方法。


上面的代码的registerReceiver方法中实例化了ProxyBroadCast对象,ProxyBroadCast代码如下:

ProxyBroadCast:

public class ProxyBroadCast extends BroadcastReceiver {
    //需要加载插件的全类名
    private String className;
    private PayInterfaceBroadcast payInterfaceBroadcast;

    public ProxyBroadCast(String className, Context context) {
        this.className = className;//com.hongx.taopiaopiao.MyReceiver

        try {
            Class<?> aClass = PluginManager.getInstance().getDexClassLoader().loadClass(className);
            Constructor constructor = aClass.getConstructor(new Class[]{});
            Object in = constructor.newInstance(new Object[]{});
            payInterfaceBroadcast = (PayInterfaceBroadcast) in;//payInterfaceBroadcast: com.hongx.taopiaopiao.MyReceiver
            payInterfaceBroadcast.attach(context);//context-ProxyActivity
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        payInterfaceBroadcast.onReceive(context, intent);
    }
}

在ProxyBroadCast中传入的className也就是com.hongx.taopiaopiao.MyReceiver的类名了。然后通过反射将得到MyReceiver对象并将其转化为PayInterfaceBroadcast对象。调用attach方法,将ProxyActivity作为context传入到MyReceiver中。

MyReceiver:

public class MyReceiver extends BroadcastReceiver implements PayInterfaceBroadcast {
    @Override
    public void attach(Context context) {
        Toast.makeText(context, "-----绑定上下文成功-----", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "-----插件收到广播-----", Toast.LENGTH_SHORT).show();
    }
}

在ProxyBroadCast中执行payInterfaceBroadcast.attach(context),也就执行了MyReceiver的attach方法,此时将ProxyActivity作为context传入到MyReceiver中

3.4 发送广播

在插件app中点击发送广播按钮,代码如下:
TaoMainActivity:

 findViewById(R.id.sendBroad).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.hongx.taopiaopiao.TaoMainActivity");
                sendBroadcast(intent);
            }
        });

sendBroadcast调用了BaseActivity的sendBroadcast方法

BaseActivity:

    //重写广播发送
    @Override
    public void sendBroadcast(Intent intent) {
        that.sendBroadcast(intent);
    }

也就是调用了ProxyActivity的sendBroadcast方法。

在ProxyActivity已经注册了广播接收者ProxyBroadCast,此时会调用ProxyBroadCast的onReceive方法,如下:
ProxyBroadCast:

  @Override
    public void onReceive(Context context, Intent intent) {
        payInterfaceBroadcast.onReceive(context, intent);
    }

payInterfaceBroadcast是一个MyReceiver对象,最终调用插件MyReceiver的onReceive方法。

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "-----插件收到广播-----", Toast.LENGTH_SHORT).show();context:ProxyActivity

    }

Github :AndroidPlugin/HxPlugin3Broadcast/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值