Android插件化完美实现代码资源加载及原理讲解 附可运行demo

本文详细介绍了Android插件化的实现,包括代码动态加载的两种方法,重点讲解了如何通过DexClassLoader加载插件apk,如何处理类加载、Activity启动和资源加载。文章提供了一个可运行的demo,演示了插件Activity的启动过程,讨论了插件Activity的生命周期管理。
摘要由CSDN通过智能技术生成

*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 。

我们通过前4篇的分解,分别将插件化设计到的知识点全部梳理了一遍,如果没有看过的,建议先看前面4篇

1. Binder机制

2. 插件化知识详细分解及原理 之代理,hook,反射

3. 类加载及dex加载

4. 应用启动过程及类加载过程

5. Android插件化完美实现代码资源加载及原理讲解 附可运行demo

6. 插件化资源的使用及动态加载 附demo
好了上面介绍了之前准备的知识点后今天我们做一个真正的可运行的启动插件demo,要知道一个插件可能是随时从网上下载下来的,那么也就是说其实这个apk不会被安装,那么如果不被安装,怎么能被加载呢,
又如何管理插件中四大组件的生命周期呢,没有生命周期的四大组件是没有意义的。而且Activity是必须要在AndroidManifest中注册的,不注册就会抛出异常,那么怎么能绕过这个限制呢,还有,一个apk中肯定会用过各种资源,那么又该如何动态的加载资源呢。下面我们就带着这些问问一一的来解决,实现插件化,或者或是模块化。

先来看一下最终的运行结果
这里写图片描述 这里写图片描述这里写图片描述

分析思路:

代码的动态加载:

apk被安装之后,apk的文件代码以及资源会被系统存放在固定的目录比如/data/app/package_name/base-1.apk)中,系统在进行类加载的时候,会自动去这一个或者几个特定的路径来寻找这个类

但是要知道插件apk是不会被安装的,那么系统也就不会讲我们的代理及资源存在在这个目录下,换句话说系统并不知道我们插件apk中的任何信息,也就根本不可能加载我们插件中的类。我们之前分析过应用的启动过程,其实就是启动了我们的主Activity,然后在ActivityThread的performLaunchActivity方法中创建的Activity对象并回调了attch和onCreate方法,我们再来看一下创建Activity对象时的代码(没看过应用启动过程的建议先看看 插件化知识详细分解及原理 之应用的启动过程),

    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    StrictMode.incrementExpectedActivityCount(activity.getClass());
    r.intent.setExtrasClassLoader(cl);

系统通过待启动的Activity的类名className,然后使用ClassLoader对象cl把这个类加载,最后使用反射创建了这个Activity类的实例对象。我们看一下这个cl对象是通过r.packageInfo.getClassLoader()被赋值的,这个r.packageInfo是一个LoadedApk类型的对象,我们看看这个LoadedApk是什么东西。

/**
 * Local state maintained about a currently loaded .apk.
 * @hide
 */
public final class LoadedApk {
      private static final String TAG = "LoadedApk";

    private final ActivityThread mActivityThread;
    private ApplicationInfo mApplicationInfo;
    final String mPackageName;
    private final String mAppDir;
    private final String mResDir;
    private final String[] mSplitAppDirs;
    private final String[] mSplitResDirs;
    private final String[] mOverlayDirs;
    private final String[] mSharedLibraries;
    private final String mDataDir;
    private final String mLibDir;
    private final File mDataDirFile;
    private final ClassLoader mBaseClassLoader;
    private final boolean mSecurityViolation;
    private final boolean mIncludeCode;
    private final boolean mRegisterPackage;
    private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
    Resources mResources;
    private ClassLoader mClassLoader;
    private Application mApplication;

    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
        = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
        = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
    private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
        = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
    private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
        = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();

    。。。
}
  • 20
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 29
    评论
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值