博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android小知识-如何加载外部dex文件中的类
阅读量:6622 次
发布时间:2019-06-25

本文共 5462 字,大约阅读时间需要 18 分钟。

本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,包括年底前会更新kotlin由浅入深系列教程,目前计划在微信公众号进行首发,如果大家想获取最新教程,请关注微信公众

想要了解插件化,首先得知道如何加载外部的dex文件,这里的插件APK会存放在主APP的assets目录中,用于模拟服务器下载插件。

第一步:创建主项目和插件项目

先创建我们的主项目,并在项目中创建一个插件依赖库,取名为pluginlibrary,主项目依赖pluginlibrary。

主项目创建完毕后,接着创建插件项目,将项目中的app模块复制到主项目并重命名为plugin,同时也依赖pluginlibrary。

修改settings.gradle文件,如下:

include ':app',':plugin', ':pluginlibrary'复制代码

重新编译一下。

第二步:编译插件APK

将pluginlibrary依赖库编译成jar包,并放在插件项目plugin的lib目录下,不是libs目录,通过compileOnly引用pluginlibrary的jar包,compileOnly只会在编译时用到相应的jar,打包成APK后不会存在于APK中。

pluginlibrary编译jar包,在pluginlibrary的build.gradle的配置如下:

apply plugin: 'com.android.library'android {    compileSdkVersion 28    defaultConfig {        minSdkVersion 17        targetSdkVersion 28        versionCode 1        versionName "1.0"        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"    }    buildTypes {        release {            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }}dependencies {    implementation fileTree(dir: 'libs', include: ['*.jar'])}task clearJar(type: Delete){    delete 'build/outputs/pluginlibray.jar'}task makePluginLibraryJar(type: Copy){    from ('build/intermediates/packaged-classes/release/')    into ('build/outputs/')    include ('classes.jar')    rename ('classes.jar', 'pluginlibrary.jar')}makePluginLibraryJar.dependsOn(clearJar,build)复制代码

编译完成后可以从右侧的Gradle面板的other分组中找到makePluginLibraryJar命令:

双击makePluginLibraryJar命令进行编译,可以看到底部输出编译成功:

BUILD SUCCESSFUL in 4s50 actionable tasks: 2 executed, 48 up-to-date10:04:10: Task execution finished 'makePluginLibraryJar'.复制代码

在pluginlibrary/build/outputs/下看到pluginlibrary.jar:

在plugin项目中创建lib文件夹并将pluginlibrary.jar复制到lib目录下:

plugin项目的build.gradle修改如下:

    compileOnly files("lib/pluginlibrary.jar")复制代码

第三步:加载外部dex

在编译pluginlibrary.jar之前在项目中创建一个接口:

package com.plugin.administrator.pluginlibrary;public interface IPluginBean {    void setUserName(String name);    String getUserName();}复制代码

在插件plugin项目中就创建一个类:

package com.plugin.administrator.myapplication;import com.plugin.administrator.pluginlibrary.IPluginBean;public class UserInfo implements IPluginBean {    private String name="billgu";    @Override    public void setUserName(String s) {        this.name=s;    }    @Override    public String getUserName() {        return name;    }}复制代码

编译插件plugin项目,将生成的apk复制到主项目的assets目录下。

接下来就是主项目编写加载外部DEX文件了,需要把assets目录下的plugin-debug.apk复制到/data/data/files目录下,这步操作放在Activity的attachBaseContext方法中:

private String apkName = "plugin-debug.apk";    //apk名称    @Override    protected void attachBaseContext(Context newBase) {        super.attachBaseContext(newBase);        try {            extractAssets(newBase, apkName);        } catch (Throwable e) {            e.printStackTrace();        }    }    public static void extractAssets(Context context, String sourceName) {        AssetManager am = context.getAssets();        InputStream is = null;        FileOutputStream fos = null;        try {            is = am.open(sourceName);            File extractFile = context.getFileStreamPath(sourceName);            fos = new FileOutputStream(extractFile);            byte[] buffer = new byte[1024];            int count = 0;            while ((count = is.read(buffer)) > 0) {                fos.write(buffer, 0, count);            }            fos.flush();        } catch (IOException e) {            e.printStackTrace();        } finally {            closeSilently(is);            closeSilently(fos);        }    }    private static void closeSilently(Closeable closeable) {        if (closeable == null) {            return;        }        try {            closeable.close();        } catch (Throwable e) {        }    }复制代码

如何从APK中读取dex文件,需要借助于DexClassLoader ,声明如下:

   DexClassLoader (String dexPath,              String optimizedDirectory,             String libraryPath,               ClassLoader parent)复制代码
  • dexPath:  指目标类所在的jar/apk文件路径, 多个路径使用 File.pathSeparator分隔, Android里面默认为 “:”

  • optimizedDirectory: 解压出的dex文件的存放路径,以免被注入攻击,不可存放在外置存储。

  • libraryPath :目标类中的C/C++库存放路径。

  • parent: 父类装载器

在onCreate方法中进行初始化DexClassLoader:

     private String mDexPath = null;    //apk文件地址    private File mFileRelease = null;  //释放目录    private DexClassLoader mClassLoader = null;        private void initDexClassLoader(){        File extractFile = this.getFileStreamPath(apkName);        mDexPath = extractFile.getPath();        mFileRelease = getDir("dex", 0); //0 表示Context.MODE_PRIVATE        mClassLoader = new DexClassLoader(mDexPath,                mFileRelease.getAbsolutePath(), null, getClassLoader());    }复制代码

生成插件APK的classLoader后就可以加载插件plugin-debug.apk中的任何类了。

点击按钮事件如下:

buttonGet.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View arg0) {                Class mLoadClassBean;                try {                    mLoadClassBean = mClassLoader.loadClass("com.plugin.administrator.myapplication.UserInfo");                    Object beanObject = mLoadClassBean.newInstance();                    IPluginBean pluginBean= (IPluginBean) beanObject;                    pluginBean.setUserName("顾林海");                    Toast.makeText(getApplicationContext(), pluginBean.getUserName(), Toast.LENGTH_LONG).show();                } catch (Exception e) {                }            }        });复制代码

加载插件plugin中的UserInfo类,调用setUserName和getUserName方法,点击按钮Toast显示“顾林海”。至此加载外部dex文件中的类就结束了。

搜索微信“顾林海”公众号,定期推送优质文章。

转载地址:http://gvjpo.baihongyu.com/

你可能感兴趣的文章
Angular学习笔记(一) - 之安装教程
查看>>
Spring Websocket实现文本、图片、声音、文件下载及推送、接收及显示(集群模式)...
查看>>
Python学习
查看>>
ADHD的应对技术:大脑的Hack和升级
查看>>
阿里云文件存储NAS简介及应用场景
查看>>
“数据结构+算法”视角的Asprova
查看>>
最严新规发布 网络短视频平台该如何降低违规风险? ...
查看>>
云服务器ECS出现速度变慢 以及突然断开怎么办?
查看>>
208亿背后的“秘密”
查看>>
Android系统自带样式(android:theme)解析
查看>>
全志A33开发板Linux内核定时器编程
查看>>
全栈必备 敏捷估点
查看>>
一个爬虫小技巧
查看>>
作为一名合格的JAVA架构师需要点亮哪些技能树?
查看>>
为什么短视频会让人刷不停?背后也许用了这套技术
查看>>
Kubernetes 在知乎上的应用
查看>>
读C#开发实战1200例子记录-2017年8月14日11:20:38获取汉字编码值
查看>>
Fescar 发布 0.3.1 版本, 支持 ZooKeeper 注册中心
查看>>
网站优化中四个常见的优化难题及解决方法!
查看>>
【死磕 Spring】----- IOC 之解析 bean 标签:BeanDefinition
查看>>