Android插件化学习之路(九)之DynamicLoadApk 源码解析(下)

承接上一篇,继续分析DynamicLoadApk 源码。

Freedom框架,我个人手写的0反射插件化框架

4.2 DLPluginPackage
插件信息对应的实体类,主要属性如下:

public String packageName;
public String defaultActivity;
public DexClassLoader classLoader;
public AssetManager assetManager;
public Resources resources;
public PackageInfo packageInfo;

packageName为插件的包名;
defaultActivity为插件的 Launcher Main Activity;
classLoader为加载插件的 ClassLoader;
assetManager为加载插件资源的 AssetManager;
resources利用assetManager中已经加载的资源创建的Resources,代理组件中会从这个Resources中读取资源。
packageInfo被PackageManager解析后的插件信息。
这些信息都会在DLPluginManager#loadApk(…)时初始化。

4.3 DLAttachable.java/DLServiceAttachable.java
DLServiceAttachable 与 DLAttachable 类似,下面先分析 DLAttachable.java。
DLAttachable 是一个接口,主要作用是以统一所有不同类型的代理 Activity,如DLProxyActivity、DLProxyFragmentActivity,方便作为同一接口统一处理。
DLProxyActivity和DLProxyFragmentActivity都实现了这个类。

DLAttachable 目前只有一个接口

public interface DLAttachable {
    /**
     * when the proxy impl ( {@see DLProxyImpl#launchTargetActivity()} ) launch
     * the plugin activity , dl will call this method to attach the proxy activity
     * and pluginManager to the plugin activity. the proxy activity will load
     * the plugin's resource, so the proxy activity is a resource delegate for
     * plugin activity.
     * 
     * @param proxyActivity a instance of DLPlugin, {@see DLBasePluginActivity}
     *            and {@see DLBasePluginFragmentActivity}
     * @param pluginManager DLPluginManager instance, manager the plugins
     */
    public void attach(DLPlugin proxyActivity, DLPluginManager pluginManager);
}

抽象函数,表示将插件Activity和代理Activity绑定在一起,其中的proxyActivity参数就是指插件Activity。
同样 DLServiceAttachable 类似,作用是统一所有不同类型的代理 Service,实现插件Service和代理Service的绑定。虽然目前只有DLProxyService。

public interface DLServiceAttachable {
    
    public void attach(DLServicePlugin remoteService, DLPluginManager pluginManager);
}

4.4 DLPlugin.java/DLServicePlugin.java

DLPlugin 与 DLServicePlugin 类似,下面先分析 DLPlugin.java。
DLPlugin 是一个接口,包含Activity生命周期、触摸、菜单等抽象函数
DLBase*Activity 都实现了这个类,这样插件的 Activity 间接实现了此类。
主要作用是统一所有不同类型的插件 Activity,如Activity、FragmentActivity,方便作为同一接口统一处理,所以这个类叫DLPluginActivity更合适。

public interface DLPlugin {

    public void onCreate(Bundle savedInstanceState);
    public void onStart();
    public void onRestart();
    public void onActivityResult(int requestCode, int resultCode, Intent data);
    public void onResume();
    public void onPause();
    public void onStop();
    public void onDestroy();
    public void attach(Activity proxyActivity, DLPluginPackage pluginPackage);
    public void onSaveInstanceState(Bundle outState);
    public void onNewIntent(Intent intent);
    public void onRestoreInstanceState(Bundle savedInstanceState);
    public boolean onTouchEvent(MotionEvent event);
    public boolean onKeyUp(int keyCode, KeyEvent event);
    public void onWindowAttributesChanged(LayoutParams params);
    public void onWindowFocusChanged(boolean hasFocus);
    public void onBackPressed();
    public boolean onCreateOptionsMenu(Menu menu);
    public boolean onOptionsItemSelected(MenuItem item);
}


同样 DLServicePlugin 主要作用是统一所有不同类型的插件 Service,方便作为统一接口统一处理,目前包含Service生命周期等抽象函数。

public interface DLServicePlugin {

    public void onCreate(); 

    public void onStart(Intent intent, int startId); 
    
    public int onStartCommand(Intent intent, int flags, int startId);
    
    public void onDestroy();
    
    public void onConfigurationChanged(Configuration newConfig); 
    
    public void onLowMemory();
    
    public void onTrimMemory(int level);
    
    public IBinder onBind(Intent intent);
    
    public boolean onUnbind(Intent intent);
    
    public void onRebind(Intent intent);
    
    public void onTaskRemoved(Intent rootIntent); 
    
    public void attach(Service proxyService, DLPluginPackage pluginPackage);
}

4.5 DLProxyActivity.java/DLProxyFragmentActivity.java
代理 Activity,他们是在宿主 Manifest 中注册的组件,也是启动插件 Activity 时,真正被启动的 Activity,他们的内部会完成插件 Activity 的初始化和启动。
这两个类大同小异,所以这里只分析DLProxyActivity。
首先来看下它的成员变量。
(1). DLPlugin mRemoteActivity
表示真正需要启动的插件Activity。这个属性名应该叫做pluginActivity更合适。
上面我们已经介绍了,DLPlugin是所有插件Activity都间接实现了的接口。
接下来在代理Activity的生命周期、触摸、菜单等函数中我们都会同时调用 mRemoteActivity 的相关函数,模拟插件Activity的相关功能。

public class DLProxyActivity extends Activity implements DLAttachable {

    protected DLPlugin mRemoteActivity;
    private DLProxyImpl impl = new DLProxyImpl(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        impl.onCreate(getIntent());
    }

    @Override
    public void attach(DLPlugin remoteActivity, DLPluginManager pluginManager) {
        mRemoteActivity = remoteActivity;
    }

    @Override
    public AssetManager getAssets() {
        return impl.getAssets() == null ? super.getAssets() : impl.getAssets();
    }

    @Override
    public Resources getResources() {
        return impl.getResources() == null ? super.getResources() : impl.getResources();
    }

    @Override
    public Theme getTheme() {
        return impl.getTheme() == null ? super.getTheme() : impl.getTheme();
    }

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

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        mRemoteActivity.onActivityResult(requestCode, resultCode, data);
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    protected void onStart() {
        mRemoteActivity.onStart();
        super.onStart();
    }

    @Override
    protected void onRestart() {
        mRemoteActivity.onRestart();
        super.onRestart();
    }

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

    @Override
    protected void onPause() {
        mRemoteActivity.onPause();
        super.onPause();
    }

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

    @Override
    protected void onDestroy() {
        mRemoteActivity.onDestroy();
        super.onDestroy();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        mRemoteActivity.onSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        mRemoteActivity.onRestoreInstanceState(savedInstanceState);
        super.onRestoreInstanceState(savedInstanceState);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        mRemoteActivity.onNewIntent(intent);
        super.onNewIntent(intent);
    }

    @Override
    public void onBackPressed() {
        mRemoteActivity.onBackPressed();
        super.onBackPressed();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        return mRemoteActivity.onTouchEvent(event);
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        super.onKeyUp(keyCode, event);
        return mRemoteActivity.onKeyUp(keyCode, event);
    }

    @Override
    public void onWindowAttributesChanged(LayoutParams params) {
        mRemoteActivity.onWindowAttributesChanged(params);
        super.onWindowAttributesChanged(params);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        mRemoteActivity.onWindowFocusChanged(hasFocus);
        super.onWindowFocusChanged(hasFocus);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        mRemoteActivity.onCreateOptionsMenu(menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        mRemoteActivity.onOptionsItemSelected(item);
        return super.onOptionsItemSelected(item);
    }
    
    @Override
    public ComponentName startService(Intent service) {
        return super.startService(service);
    }

}

(2). DLProxyImpl impl
主要封装了插件Activity的公用逻辑,如初始化插件 Activity 并和代理 Activity 绑定、获取资源等。

DLProxyImpl 主要封装了插件Activity的公用逻辑,如初始化插件 Activity 并和代理 Activity 绑定、获取资源等,相当于把DLProxyActivity和DLProxyFragmentActivity的公共实现部分提出出来,核心逻辑位于下面介绍的 onCreate() 函数。
主要函数:

1) DLProxyImpl(Activity activity)
构造函数,参数为代理 Activity。

public DLProxyImpl(Activity activity) {
    mProxyActivity = activity;
}

2) public void onCreate(Intent intent)
onCreate 函数,会在代理 Activity onCreate 函数中被调用,流程图如下:
这里写图片描述

public void onCreate(Intent intent) {

    // set the extra's class loader
    //设置intent的ClassLoader
    intent.setExtrasClassLoader(DLConfigs.sPluginClassloader);
    //获取PackageName
    mPackageName = intent.getStringExtra(DLConstants.EXTRA_PACKAGE);
    //获得待启动Activity的ClassName
    mClass = intent.getStringExtra(DLConstants.EXTRA_CLASS);
    Log.d(TAG, "mClass=" + mClass + " mPackageName=" + mPackageName);

    mPluginManager = DLPluginManager.getInstance(mProxyActivity);
    //获得插件信息PluginPackage
    mPluginPackage = mPluginManager.getPackage(mPackageName);
    //从PluginPackage中获取AssetManager
    mAssetManager = mPluginPackage.assetManager;
    //从PluginPackage中获取Resources
    mResources = mPluginPackage.resources;
    
    initializeActivityInfo();
    handleActivityInfo();
    launchTargetActivity();
}

3) protected void launchTargetActivity()
加载待启动插件 Activity 完成初始化流程,并通过DLPlugin和DLAttachable接口的 attach 函数实现和代理 Activity 的双向绑定。流程图见上图虚线框部分。

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
protected void launchTargetActivity() {
    try {
        Class<?> localClass = getClassLoader().loadClass(mClass);
        Constructor<?> localConstructor = localClass.getConstructor(new Class[] {});
        Object instance = localConstructor.newInstance(new Object[] {});
        mPluginActivity = (DLPlugin) instance;
        ((DLAttachable) mProxyActivity).attach(mPluginActivity, mPluginManager);
        Log.d(TAG, "instance = " + instance);
        // attach the proxy activity and plugin package to the mPluginActivity
        mPluginActivity.attach(mProxyActivity, mPluginPackage);

        Bundle bundle = new Bundle();
        bundle.putInt(DLConstants.FROM, DLConstants.FROM_EXTERNAL);
        mPluginActivity.onCreate(bundle);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

4) private void initializeActivityInfo()
获得待启动插件的 ActivityInfo,其中对插件Activity的主题做了一些处理

private void initializeActivityInfo() {
    PackageInfo packageInfo = mPluginPackage.packageInfo;
    if ((packageInfo.activities != null) && (packageInfo.activities.length > 0)) {
        if (mClass == null) {
            mClass = packageInfo.activities[0].name;
        }

        //Finals 修复主题BUG
        int defaultTheme = packageInfo.applicationInfo.theme;
        for (ActivityInfo a : packageInfo.activities) {
            if (a.name.equals(mClass)) {
                mActivityInfo = a;
                // Finals ADD 修复主题没有配置的时候插件异常
                if (mActivityInfo.theme == 0) {
                    if (defaultTheme != 0) {
                        mActivityInfo.theme = defaultTheme;
                    } else {
                        if (Build.VERSION.SDK_INT >= 14) {
                            mActivityInfo.theme = android.R.style.Theme_DeviceDefault;
                        } else {
                            mActivityInfo.theme = android.R.style.Theme;
                        }
                    }
                }
            }
        }

    }
}


5) private void handleActivityInfo()
设置代理 Activity 的主题等信息。
其他的 get* 函数都是获取一些插件相关信息,会被代理 Activity 调用。
同样 DLServiceProxyImpl 主要封装了插件Service的公用逻辑,如初始化插件 Service 并和代理 Activity 绑定。

private void handleActivityInfo() {
    Log.d(TAG, "handleActivityInfo, theme=" + mActivityInfo.theme);
    if (mActivityInfo.theme > 0) {
        mProxyActivity.setTheme(mActivityInfo.theme);
    }
    Theme superTheme = mProxyActivity.getTheme();
    mTheme = mResources.newTheme();
    mTheme.setTo(superTheme);
    // Finals适配三星以及部分加载XML出现异常BUG
    try {
        mTheme.applyStyle(mActivityInfo.theme, true);
    } catch (Exception e) {
        e.printStackTrace();
    }

    // TODO: handle mActivityInfo.launchMode here in the future.
}

4.7 DLBasePluginActivity.java/DLBasePluginFragmentActivity.java
插件 Activity 基类,插件中的Activity都要继承 DLBasePluginActivity/DLBasePluginFragmentActivity 之一(目前尚不支持 ActionBarActivity)。

主要作用是根据是否被代理,确定一些函数直接走父类逻辑还是代理 Activity 或是空逻辑。

DLBasePluginActivity继承自Activity,同时实现了DLPlugin接口。这两个类大同小异,所以这里只分析DLBasePluginActivity。
主要变量:

/**
 * 代理activity,可以当作Context来使用,会根据需要来决定是否指向this
 */
protected Activity mProxyActivity;

/**
 * 等同于mProxyActivity,可以当作Context来使用,会根据需要来决定是否指向this<br/>
 * 可以当作this来使用
 */
protected Activity that;
protected DLPluginManager mPluginManager;
protected DLPluginPackage mPluginPackage;


mProxyActivity为代理 Activity,通过attach(…)函数绑定。
that与mProxyActivity等同,只是为了和this指针区分,表示真实的Context,这里真实指的是被代理情况下为代理 Activity,未被代理情况下等同于 this。

Attach方法,设置代理的Activity

@Override
public void attach(Activity proxyActivity, DLPluginPackage pluginPackage) {
    Log.d(TAG, "attach: proxyActivity= " + proxyActivity);
    mProxyActivity = (Activity) proxyActivity;
    that = mProxyActivity;
    mPluginPackage = pluginPackage;
}

根据是否被代理,确定一些函数直接走父类逻辑还是代理 Activity 或是空逻辑。(此处贴部分代码)

/**
 * @param dlIntent
 * @return may be {@link #START_RESULT_SUCCESS},
 *         {@link #START_RESULT_NO_PKG}, {@link #START_RESULT_NO_CLASS},
 *         {@link #START_RESULT_TYPE_ERROR}
 */
public int startPluginActivityForResult(DLIntent dlIntent, int requestCode) {
    if (mFrom == DLConstants.FROM_EXTERNAL) {
        if (dlIntent.getPluginPackage() == null) {
            dlIntent.setPluginPackage(mPluginPackage.packageName);
        }
    }
    return mPluginManager.startPluginActivityForResult(that, dlIntent, requestCode);
}

public int startPluginService(DLIntent dlIntent) {
    if (mFrom == DLConstants.FROM_EXTERNAL) {
        if (dlIntent.getPluginPackage() == null) {
            dlIntent.setPluginPackage(mPluginPackage.packageName);
        }
    }
    return mPluginManager.startPluginService(that, dlIntent);
}

4.8 DLBasePluginService.java
插件 Service 基类,插件中的 Service 要继承这个基类,主要作用是根据是否被代理,确定一些函数直接走父类逻辑还是代理 Service 或是空逻辑。
PS:截止目前这个类还是不完善的,至少和DLBasePluginActivity对比,还不支持非代理的情况(贴部分代码)

@Override
public void attach(Service proxyService, DLPluginPackage pluginPackage) {
    // TODO Auto-generated method stub
    LOG.d(TAG, TAG + " attach");
    mProxyService = proxyService;
    mPluginPackage = pluginPackage;
    that = mProxyService;
    mFrom = DLConstants.FROM_EXTERNAL;
}

protected boolean isInternalCall() {
    return mFrom == DLConstants.FROM_INTERNAL;
}

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    LOG.d(TAG, TAG + " onBind");
    return null;
}

@Override
public void onCreate() {
    // TODO Auto-generated method stub
    LOG.d(TAG, TAG + " onCreate");
}

4.9 DLIntent.java
继承自 Intent,封装了待启动组件的 PackageName 和 ClassName。

public class DLIntent extends Intent {
    
    

    private String mPluginPackage;
    private String mPluginClass;

    public DLIntent() {
        super();
    }

    public DLIntent(String pluginPackage) {
        super();
        this.mPluginPackage = pluginPackage;
    }

    public DLIntent(String pluginPackage, String pluginClass) {
        super();
        this.mPluginPackage = pluginPackage;
        this.mPluginClass = pluginClass;
    }

    public DLIntent(String pluginPackage, Class<?> clazz) {
        super();
        this.mPluginPackage = pluginPackage;
        this.mPluginClass = clazz.getName();
    }

    public String getPluginPackage() {
        return mPluginPackage;
    }

    public void setPluginPackage(String pluginPackage) {
        this.mPluginPackage = pluginPackage;
    }

    public String getPluginClass() {
        return mPluginClass;
    }

    public void setPluginClass(String pluginClass) {
        this.mPluginClass = pluginClass;
    }

    public void setPluginClass(Class<?> clazz) {
        this.mPluginClass = clazz.getName();
    }

    @Override
    public Intent putExtra(String name, Parcelable value) {
        setupExtraClassLoader(value);
        return super.putExtra(name, value);
    }

    @Override
    public Intent putExtra(String name, Serializable value) {
        setupExtraClassLoader(value);
        return super.putExtra(name, value);
    }

    private void setupExtraClassLoader(Object value) {
        ClassLoader pluginLoader = value.getClass().getClassLoader();
        DLConfigs.sPluginClassloader = pluginLoader;
        setExtrasClassLoader(pluginLoader);
    }

}

4.10 SoLibManager.java
调用SoLibManager拷贝 so 库到 Native Library 目录。
主要函数:
(1) copyPluginSoLib(Context context, String dexPath, String nativeLibDir)
函数中以ZipFile形式加载插件,循环读取其中的文件,如果为.so结尾文件、符合当前平台 CPU 类型且尚未拷贝过最新版,则新建Runnable拷贝 so 文件。

/**
 * copy so lib to specify directory(/data/data/host_pack_name/pluginlib)
 *
 * @param dexPath      plugin path
 * @param nativeLibDir nativeLibDir
 */
public void copyPluginSoLib(Context context, String dexPath, String nativeLibDir) {
    String cpuName = getCpuName();
    String cpuArchitect = getCpuArch(cpuName);

    sNativeLibDir = nativeLibDir;
    Log.d(TAG, "cpuArchitect: " + cpuArchitect);
    long start = System.currentTimeMillis();
    try {
        ZipFile zipFile = new ZipFile(dexPath);
        Enumeration<? extends ZipEntry> entries = zipFile.entries();
        while (entries.hasMoreElements()) {
            ZipEntry zipEntry = (ZipEntry) entries.nextElement();
            if (zipEntry.isDirectory()) {
                continue;
            }
            String zipEntryName = zipEntry.getName();
            if (zipEntryName.endsWith(".so") && zipEntryName.contains(cpuArchitect)) {
                final long lastModify = zipEntry.getTime();
                if (lastModify == DLConfigs.getSoLastModifiedTime(context, zipEntryName)) {
                    // exist and no change
                    Log.d(TAG, "skip copying, the so lib is exist and not change: " + zipEntryName);
                    continue;
                }
                mSoExecutor.execute(new CopySoTask(context, zipFile, zipEntry, lastModify));
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

    long end = System.currentTimeMillis();
    Log.d(TAG, "### copy so time : " + (end - start) + " ms");
}

获取CPU类型

/**
 * get cpu name, according cpu type parse relevant so lib
 *
 * @return ARM、ARMV7、X86、MIPS
 */
private String getCpuName() {
    try {
        FileReader fr = new FileReader("/proc/cpuinfo");
        BufferedReader br = new BufferedReader(fr);
        String text = br.readLine();
        br.close();
        String[] array = text.split(":\\s+", 2);
        if (array.length >= 2) {
            return array[1];
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return null;
}

获取CPU架构

@SuppressLint("DefaultLocale")
private String getCpuArch(String cpuName) {
    String cpuArchitect = DLConstants.CPU_ARMEABI;
    if (cpuName.toLowerCase().contains("arm")) {
        cpuArchitect = DLConstants.CPU_ARMEABI;
    } else if (cpuName.toLowerCase().contains("x86")) {
        cpuArchitect = DLConstants.CPU_X86;
    } else if (cpuName.toLowerCase().contains("mips")) {
        cpuArchitect = DLConstants.CPU_MIPS;
    }

    return cpuArchitect;
}


4.11 DLUtils.java
这个类中大都是无用或是不该放在这里的函数,也许是大版本升级及维护人过多后对工具函数的维护不够所致。

至此,DynamicLoadApk 源码已解析完毕。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的代码家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值