Android一键生成包含-程序员宅基地

技术标签: 程序员  python  pycharm  android  

  1. BaseDexClassLoader继承ClassLoader,是抽象类ClassLoader的具体实现类,PathClassLoader和DexClassLoader都继承它;

  2. PathClassLoader加载系统类和应用程序的类,如果是加载非系统应用程序类,则会加载data/app/目录下的dex文件以及包含dex的apk文件或jar文件;

  3. DexClassLoader可以加载自定义的dex文件以及包含dex的apk文件或jar文件,也支持从SD卡进行加载。

所以我们这里需要用到的就是 DexClassLoader 类,对比 PathClassLoader ,DexClassLoader 的不同点是它可以加载任意目录下的 jar | dex | apk | zip 文件,比PathClassLoader更加灵活,是实现热修复和插件化技术的重点,划重点,下次要考,源码如下图所示:

/**

  • DexClassLoader类参数含义

  • @param dexPath 待加载的dex文件路径,如果是外存路径,一定要加上读外存文件的权限

  • @param optimizedDirectory 解压后的.dex文件存储路径,不可为空,此位置一定要是可读写且仅该应用可读写

  • @param librarySearchPath 指向包含本地库(so)的文件夹路径,可以设为null

  • @param parent 父级类加载器,一般可以通过Context.getClassLoader获取到,也可通过ClassLoader.getSystemClassLoader()获取到

*/

public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent)

**注:**4.1以后不能够将第二个参数 optimizedDirectory 设置到sd卡目录, 否则抛出异常,强烈建议使用内部私有存储路径(即应用的data/data/xx包名/下面创建一个app_dex文件夹),不要放到sdcard上,代码容易被注入攻击。

下面我们将编译好的含有dex文件的 dexlibrary1_dex.jar 文件放到app下的assets目录下,当然也可以通过其他手段进行加载,例如放到服务器上Download下来 等等,下面演示通过放置到assets目录进行加载:

/**

  • 加载dex文件中的class,并调用其中的showMessage方法

*/

private void loadDexClass() {

File dexOutputDir = getDir(“dex”, 0);//在data/data/xx包名/下面创建一个app_dex文件夹

String internalPath = dexOutputDir.getAbsolutePath() + File.separator + “dexlibrary1_dex.jar”;

File dexFile = new File(internalPath);

try {

if (!dexFile.exists()) {

dexFile.createNewFile();

//将assets目录下的文件copy到app/data/cache目录

FileUtils.copyFiles(this, “dexlibrary1_dex.jar”, dexFile);

}

} catch (IOException e) {

e.printStackTrace();

}

//加载dex class

DexClassLoader dexClassLoader = new DexClassLoader(internalPath, dexOutputDir.getAbsolutePath(), null, getClassLoader());

try {

//该name就是internalPath路径下的dex文件里面的ShowMessageImpl_one这个类的包名+类名

Class<?> clz = dexClassLoader.loadClass(“org.gaochun.dexlibrary1.ShowMessageImpl_one”);

IMessage_one impl = (IMessage_one) clz.newInstance();//通过该方法得到IMessage_one类

if (impl != null) {

String value = impl.showMessage(this);//调用打开弹窗并获取值

mTextView.setText(value);

}

} catch (Exception e) {

e.printStackTrace();

}

}

划重点:Class<?> clz = dexClassLoader.loadClass(“org.gaochun.dexlibrary1.ShowMessageImpl_one”); 这个loadClass的包名必须保持一致,即app下的包名和 dexlibrary1 组件下的包名必须保持一致,不然会出现java.lang.ClassCastException或ClassNotFoundException 等错误,所以需要保持一致,如下图所示:

这里给个这样的建议,定义了一个Common的基类Module,里面存放各种interface接口文件,然后剥离出来的组件引用了Common且都implements了对应的接口,宿主app也同样引用了Common,这样在宿主app中加载dex包时就不会出现上面转换错误或者找不到类的错误了,也让项目变得更加清晰一些,画个粗糙的图吧,绿色箭头表示依赖,红色箭头表示对打包好的dex进行加载,大致是这么个意思:

ok,加载成功前后的效果图:

         

到此我们知识点和功能也都基本完善了,按照上面的操作流程,Demo也能正常的运行起来,用着用着,因为项目的需求,独立出来的module越来越多,每个module的build.gradle文件中都有一大坨clearJar、makeJar的任务代码,看着有些碍眼,这是其一,其二就是每次都需要将编译好的jar拷贝到指定目录通过命令再生成包含dex的jar,这重复机械性的工作做多了也是有点头皮发麻,所以针对这个下面做了一些优化。

优化编译脚本


优化的目的总结下来有以下几点:

Module统一版本管理

将clearJar/makeJar等任务抽离开,不要在每个module中都写一大堆

通过自定义的Task一键生成包含class.dex的jar,省去手动编译重复性的工作

上传到Git后确保让每个协同开发的小伙伴也能直接执行task任务进行编译,无需修改其他配置

下面分别来简单进行说明:

一、Module统一版本管理

首先可以在我们在项目的根目录创建一个 versionConfig.gradle 文件,该文件中定义的内容只做版本相关的定义和配置(也可以在根目录的build.gradle目录定义),例如:

ext {

versions = [

sdkMinVersion : 14,

sdkTargetVersion : 27,

sdkCompileSdkVersion: 27

//其他…

]

depVersion = [

appCompatVersion : “27.1.1”,

recyclerViewVersion : “27.1.1”,

constraintLayoutVersion: “1.1.0”

]

deps = [

suport: [

appcompat : “com.android.support:appcompat-v7:${depVersion.appCompatVersion}”,

recyclerview : “com.android.support:recyclerview-v7:${depVersion.recyclerViewVersion}”,

constraint_layout: “com.android.support.constraint:constraint-layout:${depVersion.constraintLayoutVersion}”

]

]

}

注意由于各个module都需要引用到该配置信息,所以该文件需要在 根目录build.gradle中apply:

接下来在各个module中使用:

apply plugin: ‘com.android.application’

android {

def versions = rootProject.ext.versions

compileSdkVersion versions.sdkCompileSdkVersion

defaultConfig {

minSdkVersion versions.sdkMinVersion

targetSdkVersion versions.sdkTargetVersion

versionCode 1

versionName “1.0”

applicationId “org.gaochun.dexlibrary”

}

buildTypes {

release {

minifyEnabled false

proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’

}

}

}

dependencies {

def dependencies = rootProject.ext.deps

implementation fileTree(dir: ‘libs’, include: [‘*.jar’])

implementation dependencies.suport.appcompat

implementation dependencies.suport.constraint_layout

//implementation ‘com.android.support.constraint:constraint-layout:1.1.0’

}

二、抽离clearJar/makeJar等编译任务并自定义Task任务执行编译dex任务

同样我们单独定义个文件:makeDexJar.gradle,将上面我们编译jar所定义的 clearJar/makeJar 任务放到这个文件中,如下图所示:

这个时候问题来了,如何引用这个文件;这个给多个module引用的打包编译任务有很多公共的属性,怎么封装成方法;另外生成包含class.dex的jar编译命令怎么写;下面是优化好的代码,根据注释可以清楚每一行代码的含义及作用,供大家参考:

//------------------------- 构建Jar和包含Dex的Jar ---------------------------------

ext {

readLocalSDKPropertiesToMakeDexJar = this.&readLocalSDKPropertiesToMakeDexJar

}

def readLocalSDKPropertiesToMakeDexJar(outputDexJarName, jarName, packagePath) {

//println(“我被调用了”)

//编译工具

//def buildingToolPath = ‘D:\Android\android-sdk\build-tools\28.0.0\dx.bat’

def dxbatVersion = ‘25.0.0’ //因为项目用的是25Level,所以此处用25.0.0的版本构建

def dxbat = ‘\build-tools\’ + dxbatVersion + ‘\dx.bat’

def buildingToolPath

//主要是为了读取local.properties文件中的sdk.dir路径,设置编译工具的位置

//这样其他成员拉取代码后打包就不用手动更改编译工具的路径了

File file = rootProject.file(‘local.properties’)

if (file.exists()) {

InputStream inputStream = rootProject.file(‘local.properties’).newDataInputStream();

Properties properties = new Properties()

properties.load(inputStream)

if (properties.containsKey(“sdk.dir”)) {

buildingToolPath = properties.getProperty(“sdk.dir”) + dxbat

}

}

//删除jar包任务

task clearJar(type: Delete) {

delete ‘build/libs/’ + jarName

}

//生成不带dex的jar

task makeJar(type: Jar) {

//baseName ‘SmartWebAPI’ //指定生成的jar名

archiveName = jarName //打包普通jar名称

from(‘build/intermediates/classes/debug/’ + packagePath) //从哪里打包class文件

into(packagePath) //打包到jar后的目录结构

exclude(‘test/’, ‘BuildConfig.class’, ‘R.class’) //去掉不需要打包的目录和文件

exclude { it.name.startsWith('RKaTeX parse error: Expected 'EOF', got '}' at position 4: ') }̲ //去掉R开头的文件

}

//执行makeJar任务时会在之前执行clearjar任务 和 build

makeJar.dependsOn(clearJar, build)

//执行此任务生成包含dex的jar

task makeDexJar(type: Exec) {

def mCommond = [

buildingToolPath, ‘–dex’,//输出包含dex的jar路径及名称

‘–output=build/libs/’ + outputDexJarName,

‘build/libs/’ + jarName //使用dx将jar中的代码优化成dex文件,该步骤也可以手动命令行完成

]

commandLine mCommond

}

//执行makeDexJar的时候会在之前执行makeJar

makeDexJar.dependsOn(makeJar)

}

上面代码中新增了一个task任务:task makeDexJar(type: Exec) ,这个任务就是将编译好的jar通过sdk中的编译工具再次打包为含有dex的jar包,这样就不用将jar拷贝到指定目录再手动用命令打包了。还有上面有一段去读取 local.properties 的操作,代码注释中有提到,主要是为了获取sdk下的编译工具路径,动态读取出来其他小伙伴也不用去单独修改这个文件的路径了,读取示例:

def readLocalProperties(){

File file = rootProject.file(‘local.properties’)

if(file.exists()){

InputStream inputStream = rootProject.file(‘local.properties’).newDataInputStream();

Properties properties = new Properties()

properties.load(inputStream)

if (properties.containsKey(“sdk.dir”)){

println properties.getProperty(“sdk.dir”)

}

}

}

三、多个Gradle文件中方法相互调用

这里要着重说明的是这一段代码:

ext {

readLocalSDKPropertiesToMakeDexJar = this.&readLocalSDKPropertiesToMakeDexJar

}

gradle提供了ext,所以我们可以很容易获取其他gradle的属性,例如 2.gradle 需要调用 1.gradle 文件中的方法,这个时候就需要像上面的写法一样,注意左右的方法名字是一样,this 后面多了一个 & 符号,其他Gradle文件如果想调用这个方法,一般可以这样:

def outputDexJarName = ‘Smart24Decode_dex.jar’

def jarName = ‘Smart24Decode.jar’

def packagePath = ‘com/ccn/Smart24Decode/’

//直接调用

readLocalSDKPropertiesToMakeDexJar(outputDexJarName, jarName, packagePath)

或者通过task调用:

task CustomTask << {

def outputDexJarName = ‘Smart24Decode_dex.jar’

def jarName = ‘Smart24Decode.jar’

def packagePath = ‘com/ccn/Smart24Decode/’

readLocalSDKPropertiesToMakeDexJar(outputDexJarName, jarName, packagePath)

}

CustomTask << ,是gradle的语法,如果不加 << 的话,每次编译时都会执行这个task,加了**<<** ,只有执行这个task的时候才会执行里面的代码。包括后面如果有用到构建打包自动上传到服务器或者第三方的蒲公英平台,也会运用到类似的方式。

OK 下面我们在 dexlibrary1 的build.gradle引用并调用打包方法,传递相关参数:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

img

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!
  • 我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

当我们在抱怨环境,抱怨怀才不遇的时候,没有别的原因,一定是你做的还不够好!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

[外链图片转存中…(img-JZwxAnMT-1713221621661)]

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!
  • 我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

当我们在抱怨环境,抱怨怀才不遇的时候,没有别的原因,一定是你做的还不够好!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/onghaha/article/details/137806025

智能推荐

艾美捷Epigentek DNA样品的超声能量处理方案-程序员宅基地

文章浏览阅读15次。空化气泡的大小和相应的空化能量可以通过调整完全标度的振幅水平来操纵和数字控制。通过强调超声技术中的更高通量处理和防止样品污染,Epigentek EpiSonic超声仪可以轻松集成到现有的实验室工作流程中,并且特别适合与表观遗传学和下一代应用的兼容性。Epigentek的EpiSonic已成为一种有效的剪切设备,用于在染色质免疫沉淀技术中制备染色质样品,以及用于下一代测序平台的DNA文库制备。该装置的经济性及其多重样品的能力使其成为每个实验室拥有的经济高效的工具,而不仅仅是核心设施。

11、合宙Air模块Luat开发:通过http协议获取天气信息_合宙获取天气-程序员宅基地

文章浏览阅读4.2k次,点赞3次,收藏14次。目录点击这里查看所有博文  本系列博客,理论上适用于合宙的Air202、Air268、Air720x、Air720S以及最近发布的Air720U(我还没拿到样机,应该也能支持)。  先不管支不支持,如果你用的是合宙的模块,那都不妨一试,也许会有意外收获。  我使用的是Air720SL模块,如果在其他模块上不能用,那就是底层core固件暂时还没有支持,这里的代码是没有问题的。例程仅供参考!..._合宙获取天气

EasyMesh和802.11s对比-程序员宅基地

文章浏览阅读7.7k次,点赞2次,收藏41次。1 关于meshMesh的意思是网状物,以前读书的时候,在自动化领域有传感器自组网,zigbee、蓝牙等无线方式实现各个网络节点消息通信,通过各种算法,保证整个网络中所有节点信息能经过多跳最终传递到目的地,用于数据采集。十多年过去了,在无线路由器领域又把这个mesh概念翻炒了一下,各大品牌都推出了mesh路由器,大多数是3个为一组,实现在面积较大的住宅里,增强wifi覆盖范围,智能在多热点之间切换,提升上网体验。因为节点基本上在3个以内,所以mesh的算法不必太复杂,组网形式比较简单。各厂家都自定义了组_802.11s

线程的几种状态_线程状态-程序员宅基地

文章浏览阅读5.2k次,点赞8次,收藏21次。线程的几种状态_线程状态

stack的常见用法详解_stack函数用法-程序员宅基地

文章浏览阅读4.2w次,点赞124次,收藏688次。stack翻译为栈,是STL中实现的一个后进先出的容器。要使用 stack,应先添加头文件include<stack>,并在头文件下面加上“ using namespacestd;"1. stack的定义其定义的写法和其他STL容器相同, typename可以任意基本数据类型或容器:stack<typename> name;2. stack容器内元素的访问..._stack函数用法

2018.11.16javascript课上随笔(DOM)-程序员宅基地

文章浏览阅读71次。<li> <a href = "“#”>-</a></li><li>子节点:文本节点(回车),元素节点,文本节点。不同节点树:  节点(各种类型节点)childNodes:返回子节点的所有子节点的集合,包含任何类型、元素节点(元素类型节点):child。node.getAttribute(at...

随便推点

layui.extend的一点知识 第三方模块base 路径_layui extend-程序员宅基地

文章浏览阅读3.4k次。//config的设置是全局的layui.config({ base: '/res/js/' //假设这是你存放拓展模块的根目录}).extend({ //设定模块别名 mymod: 'mymod' //如果 mymod.js 是在根目录,也可以不用设定别名 ,mod1: 'admin/mod1' //相对于上述 base 目录的子目录}); //你也可以忽略 base 设定的根目录,直接在 extend 指定路径(主要:该功能为 layui 2.2.0 新增)layui.exten_layui extend

5G云计算:5G网络的分层思想_5g分层结构-程序员宅基地

文章浏览阅读3.2k次,点赞6次,收藏13次。分层思想分层思想分层思想-1分层思想-2分层思想-2OSI七层参考模型物理层和数据链路层物理层数据链路层网络层传输层会话层表示层应用层OSI七层模型的分层结构TCP/IP协议族的组成数据封装过程数据解封装过程PDU设备与层的对应关系各层通信分层思想分层思想-1在现实生活种,我们在喝牛奶时,未必了解他的生产过程,我们所接触的或许只是从超时购买牛奶。分层思想-2平时我们在网络时也未必知道数据的传输过程我们的所考虑的就是可以传就可以,不用管他时怎么传输的分层思想-2将复杂的流程分解为几个功能_5g分层结构

基于二值化图像转GCode的单向扫描实现-程序员宅基地

文章浏览阅读191次。在激光雕刻中,单向扫描(Unidirectional Scanning)是一种雕刻技术,其中激光头只在一个方向上移动,而不是来回移动。这种移动方式主要应用于通过激光逐行扫描图像表面的过程。具体而言,单向扫描的过程通常包括以下步骤:横向移动(X轴): 激光头沿X轴方向移动到图像的一侧。纵向移动(Y轴): 激光头沿Y轴方向开始逐行移动,刻蚀图像表面。这一过程是单向的,即在每一行上激光头只在一个方向上移动。返回横向移动: 一旦一行完成,激光头返回到图像的一侧,准备进行下一行的刻蚀。

算法随笔:强连通分量-程序员宅基地

文章浏览阅读577次。强连通:在有向图G中,如果两个点u和v是互相可达的,即从u出发可以到达v,从v出发也可以到达u,则成u和v是强连通的。强连通分量:如果一个有向图G不是强连通图,那么可以把它分成躲个子图,其中每个子图的内部是强连通的,而且这些子图已经扩展到最大,不能与子图外的任一点强连通,成这样的一个“极大连通”子图是G的一个强连通分量(SCC)。强连通分量的一些性质:(1)一个点必须有出度和入度,才会与其他点强连通。(2)把一个SCC从图中挖掉,不影响其他点的强连通性。_强连通分量

Django(2)|templates模板+静态资源目录static_django templates-程序员宅基地

文章浏览阅读3.9k次,点赞5次,收藏18次。在做web开发,要给用户提供一个页面,页面包括静态页面+数据,两者结合起来就是完整的可视化的页面,django的模板系统支持这种功能,首先需要写一个静态页面,然后通过python的模板语法将数据渲染上去。1.创建一个templates目录2.配置。_django templates

linux下的GPU测试软件,Ubuntu等Linux系统显卡性能测试软件 Unigine 3D-程序员宅基地

文章浏览阅读1.7k次。Ubuntu等Linux系统显卡性能测试软件 Unigine 3DUbuntu Intel显卡驱动安装,请参考:ATI和NVIDIA显卡请在软件和更新中的附加驱动中安装。 这里推荐: 运行后,F9就可评分,已测试显卡有K2000 2GB 900+分,GT330m 1GB 340+ 分,GT620 1GB 340+ 分,四代i5核显340+ 分,还有写博客的小盒子100+ 分。relaybot@re...

推荐文章

热门文章

相关标签