compile

在Gradle升级到4.+版本的时候,已经会提示compile被废弃掉了,替换它的是api指令

Implementation

“访问隔离”作用于编译器,好处是,编译速度快,比如,我在一个library中使用implementation依赖了gson库,然后我的主项目依赖了library,那么,我的主项目就无法访问gson库中的方法。我换了一个版本的Gson库,但只要library的代码不改动,就不会重新编译主项目的代码。

坏处是,我们可能要写更多的implementation,但是阅读性更好,同时如果我们的library依赖了Gson的1.0版本,同时主工程依赖了Gson的2.0版本,但最终打到apk中的是2.0版本(通过依赖树可看到)。所以对运行并不影响。

compileOnly

等同于provided,只在编译时有效,不会参与打包,不会包含到apk文件中。可以用来解决重复导入库的冲突

annotationProcessor

编译期注解的依赖
用过butterknife或者Dagger的同学可能对这种annotationProcessor引入方式有所印象,这种方式是只在编译的时候执行依赖的库,但是库最终不打包到apk中。结合编译期注解的作用,他是用来生成代码的,本身在运行时是不需要的。

apk(runtimeOnly)

只在生成apk的时候参与打包,编译时不会参与,很少用。

testCompile(testImplementation)

testCompile 只在单元测试代码的编译以及最终打包测试apk时有效。

debugCompile(debugImplementation)

debugCompile 只在debug模式的编译和最终的debug apk打包时有效

releaseCompile(releaseImplementation)

Release compile 仅仅针对Release 模式的编译和最终的Release apk打包。

本地依赖

jar包依赖

jar包依赖的导入还是比较简单的:

  • implementation files(‘hibernate.jar’,’libs/spring.jar’)//列出每个jar包的相对路径
  • implementation fileTree(dir: ‘libs’, include: [‘*.jar’])//列出包含jar包的文件夹路径

但和远程仓库依赖引入方式不同,如果本地同时存在两个不同的jar包,或者本地已有jar包,再去远程依赖不同版本的jar包,就会报错。

解决方式:将其中的一个采用compileOnly替换implementation。顾名思义,compileOnly只在编译时起作用,不会包含到APK里面,在运行时也就避免找到重复的类了。

aar包依赖
生成aar包,rebuild一下就可以的,生成目录在library工程的build->outputs->aar下。aar和jar不同的地方在于aar文件可以打包进去资源文件
和jar包不同,aar包存放的路径声明和依赖引入是分开的:

repositories {
    flatDir {
        dir "../${project.name}/libs"
    }
}
dependencies {  
    implementation(name: 'aar名字', ext: 'aar')  
}

如果aar包有很多,也可以一样象jar包统一添加一个文件夹下的所有包:

def dir = new File('app/libs')
dir.traverse(
        nameFilter: ~/.*\.aar/
) { file ->
    def name = file.getName().replace('.aar', '')
    implementation(name: name, ext: 'aar')
}

当一个library类型的module需要引用aar文件时,也要在所在模块的build.gradle文件中加入上面的话,但是当其他 Module引用此library的module时,也需要在他的build.gradle中加入如下配置,否则会提示找不到文件:

repositories {  
    flatDir {  
        dirs 'libs', '../包含aar包的模块名/libs'  
    }  
}

即如果当前Module需要一个aar包内容,不论aar包是不是在当前Module中,都需要在build.gradle中声明它所在的路径。如果项目中这样的Module比较多,每个都需要声明路径,不便于管理的话,推荐在项目的根build.gradle中统一添加,将所有包含aar包的模块名列出,这样不论是本Module或其他Module都不需要单独配置路径了:

allprojects {
    repositories {
        jcenter()
        google()
        flatDir {
             dirs "../moudle-A/libs,../moudle-B/libs,../moudle-C/libs".split(",")
        }
    }
}

.so文件依赖
这个和jar包差不多,声明下so文件的存放路径就行了:

sourceSets {
    main {
        jniLibs.srcDirs = ['libs']
    }
}

或者直接在main目录下新建jniLibs目录,这是so文件默认的放置目录,不过不常用。值得一提的是aar包里面也可以包含so文件,但依赖这种包含so文件的aar包时不需要做特定的配置,编译时so文件会自动包含到引用AAR压缩包的APK中。

但比较特殊的一点是,so文件需要放到具体的ABI目录下,不能直接放libs目录下所以你见到的结果可能是这样的:

android依赖libjsoncpp_android依赖libjsoncpp


所有的x86/x86_64/armeabi-v7a/arm64-v8a设备都支持armeabi架构的so文件。所以为了减小包体积,为了减小 apk 体积,可以只保留 armeabi 一个文件夹。但如果你想引入多个平台的,那么需要保持 so 文件的数量一致,就是说 armeabi 文件下的每个so文件都要在armeabi-v7a下找到对应的so文件,但这样apk包的体积就会增大。

还有一种做法是生成指定ABI版本的APK,然后按需上传到应用商店,让用户自己选择下载适合自己手机的版本,这个可能更多的用在安卓游戏APP上,build.gradle配置如下:

android {
    ... 
    splits {
        abi {
            enable true  //启用ABI拆分机制
            reset()  //重置ABI列表为只包含一个空字符串
            include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //与include一起使用来可以表示要使用哪一个ABI
            universalApk
            true//是否打包一个通用版本(包含所有的ABI)。默认值为 false。
        }
    }

    // ABI的code码
    project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
    android.applicationVariants.all { variant ->
        // 最终标记
        variant.outputs.each { output ->
            output.versionCodeOverride =
                    project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
        }
    }
 }