Android面试之插件化开发

前面谈到了Hook技术,那么今天来说说Hook的应用场景之一插件化开发技术。

为什么要插件化?插件化的好处有什么?

为了业务灵活解耦,减小apk的体积,方便各业务开发管理以及更新维护,同时也为了避免65535问题,我们需要插件化。

那么插件化是怎么的一个流程?

首先,用户会安装我们的app,这里叫做宿主apk,然后当用户点击使用某个业务功能时,我们就可以从我们的服务器端下载对应的插件apk,下载完之后加载进去,就可以跳转业务功能页面了。大体如下图

了解插件化目的和流程之后,接下来就是我们的重点——技术实现原理

重点

虽然市面上有很多插件化框架,如VirtualAPK,但是这里我们讲讲实现原理。分加载和页面跳转两部分讲。

一、加载文件

从服务器下载到存储插件apk这里不再赘述,主要讲加载到宿主里。我们知道app安装启动这过程就会把相应文件加载到虚拟机,所以我们要处理的就是把插件也加载到我们的宿主虚拟机,达到文件可用。因为我们打开activity页面主要涉及到class类和布局或图片等文件,所以这里我主要以class文件和资源文件作描述。

public class PluginManager {
    private static PluginManager instance;
    private Context context;
    private DexClassLoader classLoader;
    private Resources resources;
    public static PluginManager getInstance(){
        if (instance == null){
            instance = new PluginManager();
        }
        return instance;
    }

    /**
     * 加载插件apk
     * @param path 插件apk路径
     */
    public void loadPlugin(String path){
        File dexOutFile = context.getDir("dex",Context.MODE_PRIVATE);
        if (Build.VERSION.SDK_INT> Build.VERSION_CODES.CUPCAKE) {
            //初始化classLoader
            classLoader = new DexClassLoader(path, dexOutFile.getAbsolutePath(), null, context.getClassLoader());
        }

        try {
            //初始化assetManager
            AssetManager assetManager = AssetManager.class.newInstance();
            Method method = AssetManager.class.getMethod("addAssetPath",String.class);
            method.invoke(assetManager,path);
            //初始化resources
            resources = new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
        }catch (InstantiationException ine){

        }catch (IllegalAccessException ile){

        }catch (NoSuchMethodException noe){

        }catch (InvocationTargetException inve){

        }
    }

    public DexClassLoader getClassLoader() {
        return classLoader;
    }

    public Resources getResources() {
        return resources;
    }

    public void setContext(Context context) {
        this.context = context.getApplicationContext();
    }
}

这样我们就基本完成了插件加入宿主虚拟机的过程,然后我们只要把这里的classLoader和resources供插件及加载插件class类使用就行了(具体如何设计架构这里不细说),接下来我们看实现页面跳转的方案

二、打开插件Activity

如何打卡没有在Manifest.xml文件种注册的Activity网上有很多资料,大致思路相似,都是通过Hook技术,“占坑”然后替换的方式,这里也不再赘述。这再跟大家分享另一种方式,不用Hook技术,我使用一个“代理”Activity,然后再把生命周期方法“嫁接”到目标Activity上。以下是“代理”Activity的实现

/**
 * 代理activity
 */
public class ProxyActivity extends Activity {
    private ActivityInterface activityInterface;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //接收到目标activity
        String className = getIntent().getStringExtra("className");
        try {
            //实例化目标activity并开始生命周期
            Class activityClass = getClassLoader().loadClass(className);
            Constructor activityConstructor = activityClass.getConstructor(new Class[]{});
            Object obj = activityConstructor.newInstance(new Object[]{});
            activityInterface = (ActivityInterface) obj;
            activityInterface.onCreate(savedInstanceState);
        }catch (ClassNotFoundException ce){

        }catch (NoSuchMethodException ne){

        }catch (InvocationTargetException ive){

        }catch (InstantiationException inse){

        }catch (IllegalAccessException ile){

        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        activityInterface.onResume();
    }

    @Override
    protected void onStop() {
        super.onStop();
        activityInterface.onStop();
    }

    @Override
    public ClassLoader getClassLoader() {
        return PluginManager.getInstance().getClassLoader();
    }

    @Override
    public Resources getResources() {
        return PluginManager.getInstance().getResources();
    }
}

需要注意的是在插件的开发过程中必须使用宿主的上下文、resource等,所以要把这些对象传到插件中引用,具体实现这里不再赘述。如Service,BroadcastReceiver等其他组件类似,到此插件开发讲解结束。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值