前言:
2018转眼已经过去一快小半年,堕落了很长一段时间,觉得回到家乡小地方,没有了追求技术的热情。直到前段时间跟以前的同事聊的过程中发现自己已经脱离正轨了。虽然不再北上广深了,但是技术还是得靠自己去折腾。也许有一天回过头来看看,自己曾经那么爱android是吧。哈哈。废话不多扯了,直接进入今天要给大家带来的唠嗑。
正题:
大家都知道Android已经到android8了,开发工具也持续更新到Android Studio3.1了,gradle也更新到4.4了,也许你可能要问,我为啥要更新,用原来的2.×的版本不行么?行,怎么会不行呢,只是很多技术是向前看的,工具也是要跟上时代,才能达到事半功倍的效果,这几天我也是折腾很久,才升级好,那么我把我踩过的坑分享给大家是希望大家能避免我的折腾路。
1.Gradle Plugin升级到3.0.0
及以上,修改project/build.gradle
文件:
buildscript {
repositories {
...
// You need to add the following repository to download the
// new plugin.
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'//这里知道是3.0.0以上就可以
}
}
2.Gradle升级到4.1
及以上,修改project/gradle/gradle-wrapper.properties
文件:
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
3.生成APK文件名属性outputFile
变为只读
改完第一步后,编译会报如下错误:这个是生成APK的打包文件
Error:(88, 0) Cannot set the value of read-only property ‘outputFile’ for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=appDebug, filters=[]}} of type com.android.build.gradle.internal.api.ApkVariantOutputImpl.
之前的Apk打包文件类似这样:
// 自定义导出apk名称
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
if (variant.buildType.name.equals('release')) {
def fileName = "mobiletianya-v${defaultConfig.versionName}-${defaultConfig.versionCode}-release.apk"
output.outputFile = new File(outputFile.parent, fileName)
}
if (variant.buildType.name.equals('debug')) {
def fileName = "mobiletianya-v${defaultConfig.versionName}-${defaultConfig.versionCode}-debug.apk"
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
}
而升级后由于outputFile
属性变为只读,需要进行如下修改,直接对outputFileName
属性赋值即可:
applicationVariants.all { variant ->
variant.outputs.all { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
if (variant.buildType.name.equals('release')) {
def fileName = "mobiletianya-v${defaultConfig.versionName}-${defaultConfig.versionCode}-release.apk"
outputFileName = fileName
}
if (variant.buildType.name.equals('debug')) {
def fileName = "mobiletianya-v${defaultConfig.versionName}-${defaultConfig.versionCode}-debug.apk"
outputFileName = fileName
}
}
}
}
4.关键字的依赖传递
- api: 对应之前的
compile
关键字,功能一模一样。会传递依赖,导致gradle编译的时候遍历整颗依赖树 - implementation: 对应之前的
compile
,与api
类似,关键区别是不会有依赖传递 - compileOnly: 对应之前的
provided
,依赖仅用于编译期不会打包进最终的apk中 - runtimeOnly: 对应之前的’apk’,与上面的
compileOnly
相反
关于implementation
与api
的区别,主要在依赖是否会传递上。如:A依赖B,B依赖C,若使用api
则A可以引用C,而implementation
则不能引用。
这里更推荐用implementation
,一是不会间接的暴露引用,清晰知道目前项目的依赖情况;二是可以提高编译时依赖树的查找速度,进而提升编译速度。详见SO的这个回答,讲得非常详细了:https://stackoverflow.com/questions/44413952/gradle-implementation-vs-api-configuration
以上四点是最基本的,实际应用中一写lib包的依赖关系主要也是围绕这几点来修改
注明:下面是一些遇到的小问题:
1.Aapt2异常
升级到3.0.0版本,编译之前正常的项目后报错Error:com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for
上面是官方的文档介绍,我们可以看到在gradle3.0.0中AAPT2是默认打开的,在项目的gradle.properties中添加android.enableAapt2=false,sync后就编译通过了
这几个是比较公用的,剩下那些是跟自己项目相关的,具体项目具体分析,后续继续更新