转载:https://maven.google.com studio3.0问题
你必须知道的APT、annotationProcessor、android-apt、Provided、自定义注解
android gradle tools 3.X 中依赖,implement、api 和compile区别
前言
2017 年google 后,Android studio 版本更新至3.0,更新中,连带着com.android.tools.build:gradle 工具也升级到了3.0.0,在3.0.0中使用了最新的Gralde 4.0 里程碑版本作为gradle 的编译版本,该版本gradle编译速度有所加速,更加欣喜的是,完全支持Java8。当然,对于Kotlin的支持,在这个版本也有所体现,Kotlin插件默认是安装的。
在com.android.tools.build:gradle 3.0 以下版本依赖在gradle 中的声明写法
compile fileTree(dir: 'libs', include: ['*.jar'])
- 1
但在3.0后的写法为
implementation fileTree(dir: 'libs', include: ['*.jar'])
或
api fileTree(dir: 'libs', include: ['*.jar'])
- 1
- 2
- 3
在3.0版本中,compile 指令被标注为过时方法,而新增了两个依赖指令,一个是implement 和api,这两个都可以进行依赖添加,但是有什么区别呢?
api 指令
完全等同于compile指令,没区别,你将所有的compile改成api,完全没有错。
implement指令
这个指令的特点就是,对于使用了该命令编译的依赖,对该项目有依赖的项目将无法访问到使用该命令编译的依赖中的任何程序,也就是将该依赖隐藏在内部,而不对外部公开。
文不如图
用api指令编译,Glide依赖对app Module 是可见的
用implement指令编译依赖对app Module 是不可见的
建议
在Google IO 相关话题的中提到了一个建议,就是依赖首先应该设置为implement的,如果没有错,那就用implement,如果有错,那么使用api指令,这样会使编译速度有所增快。
参考资料
需要科学上网
Google I/O 2017 - How speed up Gradle builds (FULL VIDEO)
Google I/O 2017 - How speed up Gradle builds (NEW GRADLE PLUGIN 3.0.0 PART ONLY)
Google I/O 2017 - How speed up Gradle builds (reference to 1*)
最近发现Android Studio 3.0.0以上已经默认添加google()作为google的远程仓库了。
遇到问题的时候,我还是喜欢先去分析问题的出现,在更新之前是没有问题的,那么就是新版本的AS有问题,AS有问题,我一般都会先检查三个地方。
1、根目录的build.gradle,检查构建工具的版本,是否是正常的
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-beta6'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
- 1
- 2
- 3
- 4
- 5
- 6
2、gradle/wrapper/gradle-wrapper.properties里面gradle的版本
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
- 1
3、sdk版本,一般检查module下面的build.gradle文件,检查里面的sdk是否不存在,如果是,请下载。
compileSdkVersion 25
buildToolsVersion localBuildToolsVersion
aaptOptions.cruncherEnabled = false
aaptOptions.useNewCruncher = false
defaultConfig {
applicationId "com.voctex"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
// dex突破65535的限制
multiDexEnabled true
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
然后发现这一套下来,居然不管用。。。
AS还老是提示我添加google的远程仓库,没办法,就添加看看吧,结果还是一样的报错,代码如下
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-beta6'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
这个AS提示我添加的东西居然还是搞不定?这就让我对AS有点无语了,然后上网搜了一下,发现要改成google()才可以,这。。。
具体代码如下:
buildscript {
repositories {
jcenter()
google()
// maven {
// url 'https://maven.google.com/'
url 'https://dl.google.com/dl/android/maven2/'
// name 'Google'
// }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-beta6'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
google()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
你可能经常在build.gradle文件中看到,这样的字眼,annotationProcessor、android-apt、Provided,它们到底有什么作用?下面就一起来看看吧
1、什么是APT?
随着一些如ButterKnife,dagger等的开源注解框架的流行,APT的概念也越来越被熟知。
annotationProcessor和android-apt的功能是一样的,它们是替代关系,在认识它们之前,先来看看APT。
APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,根据注解自动生成代码。 Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。
APT的处理要素
注解处理器(AbstractProcess)+代码处理(javaPoet)+处理器注册(AutoService)+apt
使用APT来处理annotation的流程
1. 定义注解(如@automain)
2. 定义注解处理器,自定义需要生成代码
3.使用处理器
4.APT自动完成如下工作。
2、annotationProcessor
annotationProcessor是APT工具中的一种,他是google开发的内置框架,不需要引入,可以直接在build.gradle文件中使用,如下
dependencies {
annotationProcessor project(':xx')
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
}
- 1
- 2
- 3
- 4
3、android-apt
android-apt是由一位开发者自己开发的apt框架,源代码托管在这里,随着Android Gradle 插件 2.2 版本的发布,Android Gradle 插件提供了名为 annotationProcessor 的功能来完全代替 android-apt ,自此android-apt 作者在官网发表声明最新的Android Gradle插件现在已经支持annotationProcessor,并警告和或阻止android-apt ,并推荐大家使用 Android 官方插件annotationProcessor。
但是很多项目目前还是使用android-apt,如果想替换为annotationProcessor,那就要知道android-apt是如何使用的。下面就来介绍一下
3.1、添加android-apt到Project下的build.gradle中
//配置在Project下的build.gradle中
buildscript {
repositories {
mavenCentral()
}
dependencies {
//替换成最新的 gradle版本
classpath 'com.android.tools.build:gradle:1.3.0'
//替换成最新android-apt版本
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
3.2、在Module中build.gradle的配置
通常在使用的时候,使用apt声明注解用到的库文件。项目依赖可能分为多个部分。例如Dagger有两个组件Dagger-compiler和dagger。dagger-commpiler仅用于编译时,运行时必需使用dagger。
//配置到Module下的build.gradle中
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
apt 'com.squareup.dagger:dagger-compiler:1.1.0'
compile 'com.squareup.dagger:dagger:1.1.0'
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
基本使用就是上面这两点,想用annotationProcessor替代android-apt。删除和替换相应部分即可
android-apt文档翻译
4、Provided 和annotationProcessor区别
annotationProcessor
只在编译的时候执行依赖的库,但是库最终不打包到apk中,
编译库中的代码没有直接使用的意义,也没有提供开放的api调用,最终的目的是得到编译库中生成的文件,供我们调用。
Provided
Provided 虽然也是编译时执行,最终不会打包到apk中,但是跟apt/annotationProcessor有着根本的不同。
A 、B、C都是Library。
A依赖了C,B也依赖了C
App需要同时使用A和B
那么其中A(或者B)可以修改与C的依赖关系为Provided
- 1
- 2
- 3
- 4
A这个Library实际上还是要用到C的,只不过它知道B那里也有一个C,自己再带一个就显得多余了,等app开始运行的时候,A就可以通过B得到C,也就是两人公用这个C。所以自己就在和B汇合之前,假设自己有C。如果运行的时候没有C,肯定就要崩溃了。
总结一下,Provided是间接的得到了依赖的Library,运行的时候必须要保证这个Library的存在,否则就会崩溃,起到了避免依赖重复资源的作用。
5、使用APT的简单项目——自定义注解
5.1、新增一个java Library Module 名为apt-lib, 编写注解类:
@Target(ElementType.TYPE) //作用在类上
@Retention(RetentionPolicy.RUNTIME)//存活时间
public @interface AutoCreate {
}
- 1
- 2
- 3
- 4
- 5
5.2、新增一个java Library Module 名为apt-process,编写类来处理注解。以后使用上面的@AutoCreate,就会根据下面这个类生成指定的java文件
@AutoService(Processor.class)
public class TestProcess extends AbstractProcessor {
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(AutoCreat.class.getCanonicalName());
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
MethodSpec main = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, "args")
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.build();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder("com.songwenju.aptproject", helloWorld)
.build();
try {
javaFile.writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
5.2.1、需要使用的lib
dependencies {
compile project(':apt-lib')
compile 'com.squareup:javapoet:1.8.0'
compile 'com.google.auto.service:auto-service:1.0-rc2'
}
- 1
- 2
- 3
- 4
- 5
至此一个简单的自定义注解类,就完成了,只是生成了一个HelloWorld.java文件,里面只有一个main()函数
5.3、自定义注解类的使用
使用的话,更简单。在java文件中使用如下:
@AutoCreat
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
配置build.gradle文件
dependencies {
//添加下面这句就可以了
compile project(":apt-lib")
annotationProcessor project(':apt-process')
}
- 1
- 2
- 3
- 4
- 5
- 6
demo下载:https://github.com/JantHsueh/APTProject
参考:
android-apt
深入理解编译注解(二)annotationProcessor与android-apt
深入理解编译注解(三)依赖关系 apt/annotationProcessor与Provided的区别
android-apt切换为annotationProcessor
http://code.neenbedankt.com/
Android APT(编译时代码生成)最佳实践
Android APT及基于APT的简单应用