android组件化打包module遇到的问题总结(打包成aar)
在⼀开始接触APICLoud平台的时候我是拒绝的,因为对于⼀个有着熟练的java技能,掌握着⽼旧设计模式的⼈来说,这种平台简直就是对于程序员这个职业的侮辱。第⼀个原因是APICLoud平台剥离了原⽣开发和html+js开发的职责,使得原⽣开发的职业⽅向越来越窄,开发中的地位也逐渐下降;第⼆个原因是,这个平台完全是⽆脑式开发,所有的js框架都是封装好的,只需要像jQuery⼀样直接调⽤就好
了,APICLoud框架的设计使得前端开发者开发起来特别简单,前端如果转apicloud开发成本会很低,完全⽤不着设计模式。
现在想想之前的想法过于偏激,社会就是越来越现代化,开发语⾔只是⼀种⼯具,⼈都说君欲善其事,必先利器。我觉得很有道理,这些平台的发展就是为了减少开发⼈员的代码编写⼯作,集中注意⼒在业务逻辑上,也可以使得企业能够快速迭代产品,从⽽减少运⾏成本,安卓/ios开发⼀直都饱受着混合开发和RN开发的折磨,现在这个APICLoud平台的出现我觉得是混合开发平台成熟的标志,因为该平台不仅仅是混合开发的框架,⽽且包含着混合开发的所有安卓/ios的第三⽅sdk的商店,也就是api服务商业化模式,这种模式对于开发⼈员的冲击是相当⼤的,当sdk商店中已经集齐了所有满⾜⽇常的sdk的时候,原⽣⼈员也就失业了,因为所有的基础功能商店已经有,前端只需要配置进apicloud框架就可以了,企业的开发⼈员根本不需要重复造轮⼦,可以把⼤量的时间放在业务逻辑上。
在学习安卓原⽣的过程中,让我明⽩了很多道理,那就是这个世界唯⼀不变的是改变,唯有不断的改变和学习才能跟的上时代的步伐,授⼈以鱼不如授⼈以渔,学习过程中也积累了很多学习经验,学习效率明显得到了提⾼,现在我马上要转到⼩程序和⽹页编写了,想想也有点⼩激动呢!经过⼀个礼拜的学习,基本上可以做⼀些页⾯了,路漫漫其修远兮,吾将上下⽽求索。
在⾃定义模块的时候出现的问题
APICLoud的平台⾃定义模块上传需要的是aar包,⽽aar包的特点就是内部会打包jar和jni⾥⾯的so⽂件,但是不会把gradle的远程依赖下载并且打包进aar⽂件中,这就需要⼿动下载complie所引⽤的远程库了。
什么是gradle?##
Gradle是⼀个基于Apache Ant和Apache Maven概念的项⽬⾃动化构建⼯具。它使⽤⼀种基于Groovy的特定领域语⾔(DSL)来声明项⽬设置,抛弃了基于XML的各种繁琐配置。⾯向Java应⽤为主。当前其⽀持的语⾔限于Java、Groovy、Kotlin和Scala。
他的功能是根据编写的gradle task来完成项⽬构建任务的,我们android studio中的gradle⽂件就是⽤来编译我们的安卓项⽬的,其中包含插件导⼊,利⽤插件辅助编译,多个编译⽂件合并操作,引⼊远程仓库等等,gradle的功能⾮常强⼤。
利⽤gradle来完成打包任务
1、下载远程库
电脑上安装⼀个gradle软件,配置好环境变量。
接下来就可以进⾏下载任务了。
参考:
使⽤此⽅法下载Jar包的前提是已经配置好了Gradle的环境了,配置好的标志是在终端输⼊gradle不提⽰command not found。
1. 编写adle⽂件代码:
apply plugin: 'java'
repositories {
mavenCentral()
jcenter()
google()
}
dependencies {
compile 'java2:rxjava:2.1.3'
}
task copyJars(type: Copy) {
from configurations.runtime
into 'lib' // ⽬标位置
}
2. 执⾏下载的指令
gradle copyJars
如果上述代码运⾏之后,发现不能下载成功,那么更换仓库地址,使⽤国内镜像下载:
maven { url 'maven.aliyun/nexus/content/groups/public/' }  //阿⾥镜像
maven{ url 'maven.aliyun/nexus/content/repositories/jcenter'}  //阿⾥镜像
mavenCentral()
jcenter()
google()
2、合并依赖包
1> libs下⾯的包合并
⼀般我都是⽤代码编写⼀个task,把所有dependencies{}括号包含的语句拆解成⼀句⼀句,因为可能引⽤⾥⾯版本不⼀致,就会导致下载下来的重名的jar或者aar会相互覆盖,这个需要⾃⼰⼿动去排查版本,⽐如说support包需要版本⼀致,⽽okhttp和io-socket都引⽤了oki.jar包,就是⽤代码让每⼀个依赖下载下来的⽂件都放在单独的⼀个⽂件夹,然后⾃⼰⼿动去合并这些包到libs中,这⾥⼀定要细⼼和耐⼼,也要做到版本就低不就⾼。
如果出现什么mutilclass , duplicate resource等等都是重复引⽤的导致的问题。
2> so⽂件的合并问题
so⽂件也需要⼿动去合并,因为你⾃定义的module可能会和其他的module的so⽂件冲突,这个就需要在android{}标签内加⼊
packagingOptions {
//jni包重复编译,那么在这⾥配置包包含或者不包含
exclude 'lib/mips/librsjni.so'
exclude 'lib/armeabi-v7a/libRSSupport.so'
exclude 'lib/arm64-v8a/librsjni.so'
exclude 'lib/arm64-v8a/libRSSupport.so'
exclude 'lib/x86_64/libRSSupport.so'
exclude 'lib/mips/libRSSupport.so'
exclude 'lib/x86/librsjni.so'
exclude 'lib/x86_64/librsjni.so'
exclude 'lib/armeabi-v7a/librsjni.so'
exclude 'lib/x86/libRSSupport.so'
}
还要⼀个就是其他module有的兼容版本,你没有,那么就需要⼿动复制兼容版本⽂件夹,把对应的⽂件导⼊,⽐如,APICLOUD平台只有
⽽你的module有x86 armeabi64 armeabi和armeabi-v7a cpu版本兼容,那么在编译的时候就会包含四个⽂件夹,⽽其他module只有两个,那么就会运⾏时就会缺包,如果是这种情况,那么就把⾃⼰的包x86 armeabi64 删掉,或者在 defaultConfig{}标签内加⼊
ndk {
abiFilters  "armeabi-v7a", "armeabi"
}
这样编译的时候就只会保留 “armeabi-v7a”, "armeabi"⽂件夹。
关于so⽂件兼容请看:
3> 插件导⼊
插件是gradle运⾏的环境,前提条件,⽐如说
apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'
这⾥的意思就是说当前gradle的任务是把这个module当成是library来编译,在运⾏gradle之前加载butterknife插件,⾄于如何配置butterknife的话,这⾥不细说,但是要把module打包成aar的话,加载butterknife插件必须本地加载,因为aar不会⾃动下载远程依赖的,同理使⽤第⼀步所说的下载butterknife所需要的jar包将它们放⼊lib(注意是新建的)⽂件夹。然后在gradle的根部添加如下代码:
/
/展开libs⽂件夹⾥⾯的⽂件,aar⽂件依赖必须的配置
repositories{
flatDir{
dirs 'libs'
}
}
/* buildscript这是gradle环境本⾝所依赖的库,⼀般是链接
maven和git,Jcenter的仓库加载插件的,但是这⾥必须本地加载,
下⾯是把所有的lib⽂件中的⽂件加载进去*/
buildscript {
dependencies {
classpath fileTree(include: ['*.jar'], dir: 'lib')
}
}
2、项⽬合并
上⾯只是仅仅把module中所有的jar和aar都合并进去了,接下来还要考虑,不同的module直接依赖冲突的问题,先来了解下gradle依赖的⼏个关键字:
Android Studio引⽤第三⽅库很⽅便,只需要⼀句代码就可以搞定,⼏种引⽤第三⽅库的⽅式,总结⼀下:
⽅式:1:它就会⾃动把这个包下载下来,并且引⽤它。节省git空间,⽽且修改版本也很⽅便。
compile 'com.android.support:support-v4:23.3.0'
⽅式2:引⽤libs下所有jar包
compile fileTree(dir: 'libs', include: ['*.jar'])
⽅式3:引⽤⼀个jar
compile files('libs/fastjson-1.1.53.android.jar')
⽅式4:引⽤⼀个aar⽂件,注意并不能像⽅式2 那样⾃动引⽤全部的aar,⽽需要对每个aar分别进⾏引⽤。
compile(name: 'aar_file_name', ext: 'aar')
⽅式5:引⽤库类型的项⽬
compile project(':xxxsdk')
⽅式6:仅仅在编译时使⽤,但最终不会被编译到apk或aar⾥
provided files('libs/glide-3.7.0.jar')
经过本⼈实验,貌似是资源⽂件在打包编译的时候如果重名就会覆盖,⽽class⽂件重名就是直接编译报错,所以资源⽂件冲突是隐形的,class冲突⽐较明显。
jar冲突的话,让主module依赖这个jar,其他次module使⽤provided 关键字依赖这个jar包,这样编译
的时候就只有⼀份。
aar冲突⽐较⿇烦了,因为aar中可能会包含jar⽂件,这样的话就需要查看官⽅⽂档或者⾃⼰解压缩⽂件去查看这个aar⾥⾯究竟包含着那些jar⽂件,利⽤ exclude group:"", module:"" 语句来排除jar被编译进aar包中。例如:
最后如果是资源⽂件冲突,最常见的的错误就是:
no resource id found
或者是
java.lang.NoSuchFieldError: No static field xxx of
type I in class Lcom/XX/R$id; or its superclasses
要么就是多个module的资源⽂件重名,导致相互覆盖,那么就不到指定的资源,要么就是指定的控
件ID重名,多个重名控件导致不到控件,解决办法也很简单就是改⽂件或者控件名字。
⽐如说我在APICLOUD云平台编译的时候出现以下错误,
What went wrong:
Execution failed for task ':app:transformClassesWithJarMergingForRelease'
.> com.android.ansform.TransformException: java.util.zip.ZipException: duplicate entry: android/support/v4/app/BaseFragmentActivityDonut.cla ss
意思就是class⽂件重复,原因就是apicloud的框架本⾝⾃带v4包,⽽我的module也有v4包,在引⼊我的⾃定义模块后,打包的时候就会出现相同的两个class⽂件,这样就出现了以上错误,解决的办法,上⾯已经说了使⽤exclude语法,将相应的部分排除,这个⽅法只能排除⽹络库,本地的还没发现能够有效起到作⽤,因此,我在想,既然apicloud框架本⾝⾃带v4的class⽂件,⽽我⾃定义模块打包成aar⽂件⼜不会把v4.aar打包进去,还是要⼿动将v4.aar放到和module.aar同⽬录下,那么,我可以不将v4.aar放⼊,⽽是使⽤apicloud框架⾃带的v4.aar,这样就巧妙的将重复问题解决了。记录下这个问题。
新版gradle的新语法:
Gradle 3.4 引⼊了新的依赖配置,
maven打包本地jar包新增
api 和 implementation 来代替 compile 依赖配置。
其中 api 和以前的 compile 依赖配置是⼀样的。
使⽤ implementation 依赖配置,会显著提升构建时间,因为implementation只会依赖直接引⽤的资源,⽽资源本⾝所依赖的资源是不会去深度依赖,这样就减少了,依赖编译所消耗的时间。
⽐如A依赖B ,B依赖C 。A implementation B,只会将B加⼊编译。⽽ A api B或者A compile B就不仅仅只编译B也会将C加⼊编译。
所以在使⽤implementation 依赖的时候,不要惊讶不到类,不到资源之类的事情,因为他的原理就是不深度依赖。要么使⽤api(在⾼版本建议使⽤这个)和complie(低版本)。要么⾃⼰⼿动在A中将所需要的资源都依赖过来。
implementation和api的区别还有就是在,moduleB中如果使⽤implementation来引⽤⽹络或者本地资源,moduleA 依赖 moduleB这样写的话,还是不到,如果moduleB api来依赖⽹络或者本地资源,那么这些资源就可以被moduleA到,并使⽤。
新增
compileOnly provided gradle 添加依赖到编译路径,编译时使⽤。(不会打包到APK)
runtimeOnly apk gradle 添加依赖只打包到 APK,运⾏时使⽤。(不会添加到编译路径)
经常会出现,merge task失败的问题 ,Task [App] not found in root project [project_name] 这种问题,⼀般可以去查aar资源包内是否有重复的jar依赖,导致合并编译出来的jar失败,但是aar重复并不会导致这个问题,不知道⾕歌是哪根经出了问题。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。