注解工具是java代码生成及对象注入的强大工具。注解包括源码可见、字节码可见及运行时可见。目前比较流行的APT技术,也即时编译成字节码时可见。下面以Dagger2及ButterKnife两款注解工具讲解如何在Android.mk中使用这两款工具。
通过gradle编译时,在build.gradle文件中通过如下方式引入
api 'com.google.dagger:dagger:2.14.1'
annotationProcessor "com.google.dagger:dagger-compiler:2.14.1"
api 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
LOCAL_PATH:= $(call my-dir)
#######################################
# Create references to prebuilt libraries.
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_CERTIFICATE := platform
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
demo-dagger2-compiler:libs/dagger-compiler-2.14.1.jar \
demo-dagger2:libs/dagger-2.14.1.jar \
demo-dagger2-producers:libs/dagger-producers-2.14.1.jar \
demo-dagger2-spi:libs/dagger-spi-2.14.1.jar \
demo-butterknife:libs/butterknife-8.8.1.aar \
demo-butterknife-anno:libs/butterknife-annotations-8.8.1.jar \
demo-butterknife-compiler:libs/butterknife-compiler-8.8.1.jar \
demo-support-anno:libs/support-annotations-28.0.0.jar \
demo-javax-inject:libs/javax.inject-1.jar \
demo-guava:libs/guava-27.1-jre.jar \
demo-java-format:libs/google-java-format-1.4-all-deps.jar \
demo-javax-api:libs/jsr250-api-1.0.jar \
demo-javapoet:libs/javapoet-1.8.0.jar \
demo-auto-common:libs/auto-common-0.8.jar
include $(BUILD_MULTI_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_CERTIFICATE := platform
LOCAL_SRC_FILES := $(call all-java-files-under, java)
LOCAL_STATIC_JAVA_LIBRARIES := demo-dagger2 demo-butterknife demo-butterknife-anno \
demo-support-anno demo-javax-inject
LOCAL_JAVA_LIBRARIES := gsframework
# Libraries needed by the compiler (JACK) to generate code.
PROCESSOR_LIBRARIES_TARGET := \
demo-dagger2 \
demo-dagger2-compiler \
demo-dagger2-producers \
demo-butterknife \
demo-butterknife-anno \
demo-butterknife-compiler \
demo-javax-inject \
demo-guava \
demo-java-format \
demo-javax-api \
demo-dagger2-spi \
demo-javapoet \
demo-auto-common
# Libraries needed by the compiler (JACK) to generate code.
# Resolve the jar paths.
PROCESSOR_JARS := $(call java-lib-deps, $(PROCESSOR_LIBRARIES_TARGET))
# Necessary for annotation processors to work correctly.
LOCAL_ADDITIONAL_DEPENDENCIES += $(PROCESSOR_JARS)
LOCAL_JAVACFLAGS += -processorpath $(call normalize-path-list,$(PROCESSOR_JARS))
LOCAL_ANNOTATION_PROCESSOR_CLASSES := \
butterknife.compiler.ButterKnifeProcessor dagger.internal.codegen.ComponentProcessor
#LOCAL_JAVACFLAGS += $(foreach class,$(LOCAL_ANNOTATION_PROCESSOR_CLASSES),-processor $(class))
LOCAL_PACKAGE_NAME := InjectDemo
include $(BUILD_PACKAGE)
# Use the folloing include to make our test apk.
#include $(call all-makefiles-under,$(LOCAL_PATH))
可以看出,编译需要引入一堆jar包,包括编译时包和静态jar包,编译包只在编译时依赖,不会打入app中,而静态包则会打入APP中。
下面是针对Android6.0编译系统添加支持APT的patch,请注意 mm 模块编译时,请将JDK版本切换到1.8版本,否则无法生成注解代码。
Android build系统相关patch如下所示:
执行mm命令后,在编译之前会处理注解生成java源码,生成的源码路径:
out/target/common/obj/APPS/InjectDemo_intermediates/anno
在编译前处理注解的主要是通过—processorpath选项完成的,如下是javac选项使用帮助文档:
$ javac
用法: javac
在Android源码build系统中,javac编译是通过一个函数处理的,代码路径在
/build/core/definitions.mk
# Common definition to invoke javac on the host and target.
#
# Some historical notes:
# - below we write the list of java files to java-source-list to avoid argument
# list length problems with Cygwin
# - we filter out duplicate java file names because eclipse's compiler
# doesn't like them.
#
# $(1): javac
# $(2): bootclasspath
define compile-java
$(hide) rm -f $@
$(hide) rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) $(PRIVATE_ANNO_INTERMEDIATES_DIR)
$(hide) mkdir -p $(dir $@)
$(hide) mkdir -p $(PRIVATE_CLASS_INTERMEDIATES_DIR) $(PRIVATE_ANNO_INTERMEDIATES_DIR)
$(call unzip-jar-files,$(PRIVATE_STATIC_JAVA_LIBRARIES),$(PRIVATE_CLASS_INTERMEDIATES_DIR))
$(call dump-words-to-file,$(PRIVATE_JAVA_SOURCES),$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list)
$(hide) if [ -d "$(PRIVATE_SOURCE_INTERMEDIATES_DIR)" ]; then \
find $(PRIVATE_SOURCE_INTERMEDIATES_DIR) -name '*.java' >> $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list; \
fi
$(hide) tr ' ' '\n' < $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list \
| sort -u > $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq
$(hide) if [ -s $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq ] ; then \
$(1) -encoding UTF-8 \
$(strip $(PRIVATE_JAVAC_DEBUG_FLAGS)) \
$(if $(findstring true,$(PRIVATE_WARNINGS_ENABLE)),$(xlint_unchecked),) \
$(2) \
$(addprefix -classpath ,$(strip \
$(call normalize-path-list,$(PRIVATE_ALL_JAVA_LIBRARIES)))) \
$(if $(findstring true,$(PRIVATE_WARNINGS_ENABLE)),$(xlint_unchecked),) \
-extdirs "" -d $(PRIVATE_CLASS_INTERMEDIATES_DIR) -s $(PRIVATE_ANNO_INTERMEDIATES_DIR) \
$(PRIVATE_JAVACFLAGS) \
\@$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq \
|| ( rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) ; exit 41 ) \
fi
$(if $(PRIVATE_JAVA_LAYERS_FILE), $(hide) build/tools/java-layers.py \
$(PRIVATE_JAVA_LAYERS_FILE) \@$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq,)
#$(hide) rm -f $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list
#$(hide) rm -f $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq
$(if $(PRIVATE_JAR_EXCLUDE_FILES), $(hide) find $(PRIVATE_CLASS_INTERMEDIATES_DIR) \
-name $(word 1, $(PRIVATE_JAR_EXCLUDE_FILES)) \
$(addprefix -o -name , $(wordlist 2, 999, $(PRIVATE_JAR_EXCLUDE_FILES))) \
| xargs rm -rf)
$(if $(PRIVATE_JAR_PACKAGES), \
$(hide) find $(PRIVATE_CLASS_INTERMEDIATES_DIR) -mindepth 1 -type f \
$(foreach pkg, $(PRIVATE_JAR_PACKAGES), \
-not -path $(PRIVATE_CLASS_INTERMEDIATES_DIR)/$(subst .,/,$(pkg))/\*) -delete ; \
find $(PRIVATE_CLASS_INTERMEDIATES_DIR) -empty -delete)
$(if $(PRIVATE_JAR_EXCLUDE_PACKAGES), $(hide) rm -rf \
$(foreach pkg, $(PRIVATE_JAR_EXCLUDE_PACKAGES), \
$(PRIVATE_CLASS_INTERMEDIATES_DIR)/$(subst .,/,$(pkg))))
$(if $(PRIVATE_RMTYPEDEFS), $(hide) $(RMTYPEDEFS) -v $(PRIVATE_CLASS_INTERMEDIATES_DIR))
$(if $(PRIVATE_JAR_MANIFEST), \
$(hide) sed -e 's/%BUILD_NUMBER%/$(BUILD_NUMBER)/' \
$(PRIVATE_JAR_MANIFEST) > $(dir $@)/manifest.mf && \
jar -cfm $@ $(dir $@)/manifest.mf \
-C $(PRIVATE_CLASS_INTERMEDIATES_DIR) ., \
$(hide) jar -cf $@ -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) .)
$(if $(PRIVATE_EXTRA_JAR_ARGS),$(call add-java-resources-to,$@))
endef
define transform-java-to-classes.jar
@echo "--------------------start compile-java-------------------------"
@echo "class path = $(PRIVATE_CLASS_INTERMEDIATES_DIR), anno src path = $(PRIVATE_ANNO_INTERMEDIATES_DIR)"
@echo "private java libs = $(PRIVATE_ALL_JAVA_LIBRARIES)"
@echo "java layer files = $(PRIVATE_JAVA_LAYERS_FILE)"
@echo "private jar pkg = $(PRIVATE_JAR_MANIFEST)"
@echo -e ${CL_GRN}"target Java:"${CL_RST}" $(PRIVATE_MODULE) ($(PRIVATE_CLASS_INTERMEDIATES_DIR))"
$(call compile-java,$(TARGET_JAVAC),$(PRIVATE_BOOTCLASSPATH))
endef
有兴趣的话,可以通过echo打印调试。