【问题标题】:aar support in Android.mk. Dependencies are not picked up by AOSP buildAndroid.mk 中的 aar 支持。 AOSP 构建不拾取依赖项
【发布时间】:2021-07-29 05:27:38
【问题描述】:

应用程序(在 Android Studio 中开发)使用 AAR 作为库。我需要在 AOSP 树中构建这个应用程序。所以我创建了 Android.mk:

LOCAL_STATIC_JAVA_AAR_LIBRARIES:= <aar alias>

include $(BUILD_PACKAGE)

include $(CLEAR_VARS)

LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := <aar alias>:libs/<lib file>.aar

include $(BUILD_MULTI_PREBUILT)

构建成功完成,但问题是AAR 在其“libs”目录中包含多个 JAR 文件。而且这些 JAR 似乎没有包含在构建中,因此应用程序会因NoClassDefFoundError 而崩溃。

AOSP 是否缺少对AAR 的全面支持?还是我错过了什么?谢谢。我使用的是 Android 6.0.1。

【问题讨论】:

    标签: android android-source aar


    【解决方案1】:

    你的做法是正确的。并且 aar 中包含的 jar 文件也会包含在其中。我认为您错过了在其中包含 aapt 标志。

    LOCAL_AAPT_FLAGS += --extra-packages your.package.name 
    

    【讨论】:

    • 这没有帮助。为了验证 --extra-packages 行为,我创建了带有垃圾内容的新 mylib.jar 文件并将其放入 AAR 的 libs 文件夹中。如果 libs 内容包含在构建中,我相信构建应该会因为不正确的 .jar 文件而失败。但是构建成功完成。我传递包名称,因为它在 AAR 文件的 AndroidManifest.xml 中定义。对吗?
    • 我没有说包含 aapt 标志将包含 jar 文件,同时它使您的构建正确。请检查我的cmets:“你的做法是正确的。并且aar中包含的jar文件也会被包含在内。”尝试使用包含 aapt 标志的正确构建,如果仍然无法正常工作,请在此处分享您的 mk 文件。
    • 当然我添加了 LOCAL_AAPT_FLAGS += --extra-packages your.package.name 因为没有来自 AAR 的这些资源不包含在构建中。当然,来自 aar 的 classes.jar 也包含在构建中。问题是 AAR 中的 libs/*.jar 不会自动包含在构建中。
    • 它应该被这个过程添加。你一定做错了什么。你能把你的 mk 文件贴在这里吗,这样可以更清楚地调查。
    【解决方案2】:

    在这里复活死者,我也经历过同样的行为。 ./jni/ 下的 *.so 文件也是如此。和 aar 资产。 查看 $(BUILD_MULTI_PREBUILT),我发现它只查找类 jar 和 res 文件。

    我最终提取了所有这些组件(*.so、*.jar、资产),并将它们显式添加到我的应用的 Android.mk 中。

    【讨论】:

      【解决方案3】:

      我最终得到了以下结果:

      -在应用程序的Android.mk中:

      LOCAL_STATIC_JAVA_AAR_LIBRARIES += coollibrary
      
      include $(LOCAL_PATH)/java-static-lib-from-aar.mk
      

      -java-static-lib-from-aar.mk:

      define list-jar-libs-from-aar
        $(foreach f, $(2), $(shell if [ -f $(LOCAL_PATH)/$(f)/$(1).aar ]; then unzip -Z1 $(LOCAL_PATH)/$(f)/$(1).aar libs/*.jar | sed 's/libs\///g; s/\.jar//g'; fi))
      endef
      
      define build-jar-lib-from-aar
      $(2): $(1)
          -mkdir -p $(dir $2);\
          cp -fp $1 $2
      endef
      
      MY_STATIC_JAVA_LIBS := $(foreach aar,$(LOCAL_STATIC_JAVA_AAR_LIBRARIES),\
          $(foreach jar, $(call list-jar-libs-from-aar,$(aar), libs aosplibs),\
              $(aar)_$(jar)))
      
          $(info Adding following java libraries from AAR(s) into LOCAL_STATIC_JAVA_LIBRARIES: $(MY_STATIC_JAVA_LIBS))
      LOCAL_STATIC_JAVA_LIBRARIES += $(MY_STATIC_JAVA_LIBS)
      
      $(foreach aar,$(LOCAL_STATIC_JAVA_AAR_LIBRARIES),\
          $(foreach jar, $(call list-jar-libs-from-aar,$(aar), libs aosplibs),\
              $(eval $(call build-jar-lib-from-aar,$(call intermediates-dir-for,JAVA_LIBRARIES,$(aar),,COMMON)/aar/libs/$(jar).jar,$(call intermediates-dir-for,JAVA_LIBRARIES,$(aar)_$(jar),,COMMON)/javalib.jar))))   
      

      java-static-lib-from-aar.mk 假定 AAR 位于 ./libs 和 aosplibs 目录中。

      【讨论】:

      • 如果 aar 里面有 jni 库怎么办?
      • 不再需要上述解决方法,请在此处查看我的答案:stackoverflow.com/a/53412156/6851796 TL;DR:mk 文件中存在错误。 AAPT2 不支持 LOCAL_STATIC_JAVA_AAR_LIBRARIES。已在 android 9 中修复,您可以将此修复移植到以前的版本中。
      【解决方案4】:

      我找到了一种完全自动执行此操作的方法。我会过一遍,然后完成的 Android.mk 在这篇文章的底部。

      首先,让我们创建一些变量,其中包含将在您的实例中更改的部分,以便您可以复制/粘贴其余部分。您可以手动解压缩 .aar 文件一次以检查文件结构和内容。相对路径是从我当前的目标目录回到 Android 构建树的根目录('out' 所在的位置)。

      LOCAL_PATH := $(call my-dir)
      #####################################
      # Definitions for extracting .so files from .aar
      AAR_WITH_JNI=lib/whatever-your.aar
      AAR_ALIAS=MakeThisMeaningfullToYou
      AAR_JNI_FLAVOR=arm64-v8a
      AAR_ROOT_EXTRACT_PATH=out/target/common/obj/JAVA_LIBRARIES/$(AAR_ALIAS)_intermediates/aar/jni/$(AAR_JNI_FLAVOR)
      AAR_RELATIVE_EXTRACT_PATH=../../../../$(AAR_ROOT_EXTRACT_PATH)
      

      接下来,我们要使用“解压缩”来使用 shell 命令查询 .aar 文件中的 jni 内容,标准输出通过 grep 和 sed 管道进行清理。这是有效的,因为 .aar 文件已签入并出现在干净的“make”开始时。因此,将其添加到您的变量定义之后的 Android.mk 顶部。

      AAR_JNI_SO_FILE_LIST := $(shell \
            unzip -l $(LOCAL_PATH)/$(AAR_WITH_JNI) | \
            grep -e jni/$(AAR_JNI_FLAVOR)/lib\.*.so | \
            sed 's?^.*jni/$(AAR_JNI_FLAVOR)/??g')
      

      现在我们遵循aar support in Android.mk 中的模式,通过将 LOCAL_STATIC_JAVA_AAR_LIBRARIES 添加到您的 BUILD_PACKAGE 并使用 3 行 BUILD_MULTI_PREBUILT 之后为提取的 AAR 定义别名,将 AAR 库添加到您的包中。

      include $(CLEAR_VARS)
      # your LOCAL_SRC_FILES and whatever else you need here
      LOCAL_STATIC_JAVA_AAR_LIBRARIES:= $(AAR_ALIAS)
      LOCAL_AAPT_FLAGS := --auto-add-overlay
      include $(BUILD_PACKAGE)
      
      include $(CLEAR_VARS)
      LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := $(AAR_ALIAS):$(AAR_WITH_JNI)
      include $(BUILD_MULTI_PREBUILT)
      

      现在我们通过将 .so 文件的引用添加到 BUILD_PACKAGE 来扩充该解决方案。我使用 addprefix 使用相对路径来做到这一点。

      LOCAL_PREBUILT_JNI_LIBS := \
       $(addprefix $(AAR_RELATIVE_EXTRACT_PATH)/,$(AAR_JNI_SO_FILE_LIST))
      

      此时,如果您在干净的工作区执行此操作,则每个 .so 文件都会出现错误,因为它们尚不存在。解决方案是为每个 .so 文件创建一个Empty Recipe,并以我们的别名为先决条件。我们可以使用evalcall 函数组合的foreach 循环来做到这一点,如Generate dynamically Makefile rules 中所述。由于这些规则,'make' 将知道.so 文件不会出现在文件系统上,直到BUILD_MULTIPLE_PREBUILT 步骤的结束。

      define fake-so-rule-from-aar
      $(1): $(AAR_ALIAS) ;
      endef
      $(foreach soFile,$(addprefix $(AAR_ROOT_EXTRACT_PATH)/,$(AAR_JNI_SO_FILE_LIST)),$(eval $(call fake-so-rule-from-aar,$(soFile))))
      

      因此,当您将所有这些放在一起时,您不需要从 .aar 文件中预提取 .so 文件。您可以简单地“rm -rf out”,构建系统将提取所需的所有内容并将 .so 文件正确复制到您的库中。

      完成的 Android.mk 文件:

      LOCAL_PATH := $(call my-dir)
      
      #####################################
      # Definitions for extracting .so files from .aar
      AAR_WITH_JNI=lib/my.aar
      AAR_ALIAS=MyAarFile
      AAR_JNI_FLAVOR=arm64-v8a
      AAR_ROOT_EXTRACT_PATH=out/target/common/obj/JAVA_LIBRARIES/$(AAR_ALIAS)_intermediates/aar/jni/$(AAR_JNI_FLAVOR)
      AAR_RELATIVE_EXTRACT_PATH=../../../../$(AAR_ROOT_EXTRACT_PATH)
      # We cannot look in the driectory at the extracted files on a clean build, so we peek at the .aar contents to know what filenames we'll end up extracting
      AAR_JNI_SO_FILE_LIST := $(shell unzip -l $(LOCAL_PATH)/$(AAR_WITH_JNI) | grep -e jni/$(AAR_JNI_FLAVOR)/lib\.*.so | sed 's?^.*jni/$(AAR_JNI_FLAVOR)/??g')
      #$(info AAR_JNI_SO_FILE_LIST = $(AAR_JNI_SO_FILE_LIST))
      
      #####################################
      # java package
      include $(CLEAR_VARS)
      LOCAL_MULTILIB := 64
      LOCAL_SRC_FILES := $(call all-java-files-under, src)
      LOCAL_PACKAGE_NAME := AlsoMine    
      LOCAL_STATIC_JAVA_AAR_LIBRARIES := $(AAR_ALIAS)
      LOCAL_PREBUILT_JNI_LIBS := $(addprefix $(AAR_RELATIVE_EXTRACT_PATH)/,$(AAR_JNI_SO_FILE_LIST))
      #$(info LOCAL_PREBUILT_JNI_LIBS = $(LOCAL_PREBUILT_JNI_LIBS))
      LOCAL_AAPT_FLAGS := --auto-add-overlay
      # Build an APK
      include $(BUILD_PACKAGE)
      
      #####################################
      # Create an alias to the extracted library from the .aar
      include $(CLEAR_VARS)
      LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := $(AAR_ALIAS):$(AAR_WITH_JNI)
      include $(BUILD_MULTI_PREBUILT)
      
      #####################################
      # Create empty recipes so Make thinks it knows the so files are created
      # by the BUILD_MULTI_PREBUILT above
      define fake-so-rule-from-aar
      $(1): $(AAR_ALIAS) ;
      #$(info Created empty recipe for $(1): $(AAR_ALIAS))
      endef
      #$(foreach soFile,$(addprefix $(AAR_ROOT_EXTRACT_PATH)/,$(AAR_JNI_SO_FILE_LIST)), $(info $(soFile)))
      $(foreach soFile,$(addprefix $(AAR_ROOT_EXTRACT_PATH)/,$(AAR_JNI_SO_FILE_LIST)),$(eval $(call fake-so-rule-from-aar,$(soFile))))
      

      我在我的文件中留下了很多 cmets 和 $info 调用,以便为下一个需要调试它的人打印各种状态。享受吧!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-07-07
        • 2021-09-23
        • 1970-01-01
        • 1970-01-01
        • 2020-07-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多