将 Google Camera2 迁移为 Gradle 编译

4,714 阅读4分钟

项目经验,如需转载,请注明作者:Yuloran (t.cn/EGU6c76)

前言

最近在研究 Google 的 Camera2 源码,因为该应用属于 AOSP,所以是使用 Android.mk 编译的。这就导致无法使用 Android Studio 来编译和调试,笔者便花了一番功夫,将其迁移为了 Gradle 编译。

1. 源码下载

源码分为两部分,一部分在 platform/packages/apps/Camer2 下:

另一部分在 platform/frameworks/ex/camera2 下:

下载完成后,新建 Camera2 文件夹,先把 app 的代码全复制进去,再在下面新建文件夹 src_frameworks,将 frameworks/ex/camera2 下代码也复制进去,像这样:

2. 迁移为 Gradle 编译

官方迁移指南:Migrating to Android Studio,按照 通过创建自定义 Gradle 构建文件进行迁移 小节,进行迁移。

2.1 分析 Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_STATIC_ANDROID_LIBRARIES := \
    android-support-v13 \
    android-support-v4 \
    android-support-compat

LOCAL_STATIC_JAVA_LIBRARIES := android-ex-camera2-portability
LOCAL_STATIC_JAVA_LIBRARIES += xmp_toolkit
LOCAL_STATIC_JAVA_LIBRARIES += glide
LOCAL_STATIC_JAVA_LIBRARIES += guava
LOCAL_STATIC_JAVA_LIBRARIES += jsr305

LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-java-files-under, src_pd)
LOCAL_SRC_FILES += $(call all-java-files-under, src_pd_gcam)

LOCAL_RESOURCE_DIR += \
	$(LOCAL_PATH)/res \
	$(LOCAL_PATH)/res_p

include $(LOCAL_PATH)/version.mk

LOCAL_AAPT_FLAGS := \
        --auto-add-overlay \
        --version-name "$(version_name_package)" \
        --version-code $(version_code_package) \

LOCAL_USE_AAPT2 := true

LOCAL_PACKAGE_NAME := Camera2

LOCAL_SDK_VERSION := current

LOCAL_PROGUARD_FLAG_FILES := proguard.flags

# Guava uses deprecated org.apache.http.legacy classes.
LOCAL_JAVA_LIBRARIES += org.apache.http.legacy

LOCAL_JNI_SHARED_LIBRARIES := libjni_tinyplanet libjni_jpegutil

include $(BUILD_PACKAGE)

include $(call all-makefiles-under, $(LOCAL_PATH))

Android.mk 语法

原项目引用了 support-v13,support-v4,support-compat,xmp_toolkit,glide,guava,jsr305 共 7 个库,其中 glide,guava 版本较老,需要从 mavenCentral() 下载,jsr305 需要单独下载 jar:

2.2 编写 build.gradle

在 Camera2 目录下,新建 build.gradle 文件,用记事本打开,根据对 Android.mk 的分析,build.gradle 编写如下:

// This buildscript{} block configures the code driving the build
buildscript {
    /**
     * The nested repositories{} block declares that this build uses the
     * jcenter repository.
     */
    repositories {
        // fix aapt cannot found error
        google()
        // download old version for somme jars
        mavenCentral()
        jcenter()
    }

    /**
     * This block declares a dependency on the 3.2.1 version
     * of the Gradle plugin for the buildscript.
     */
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
    }
}

allprojects {
    repositories {
        // fix aapt cannot found error
        google()
        // download old version for somme jars
        jcenter()
    }
}

/**
 * This line applies the com.android.application plugin. Note that you should
 * only apply the com.android.application plugin. Applying the Java plugin as
 * well will result in a build error.
 */
apply plugin: 'com.android.application'

/**
 * The android{} block configures all of the parameters for the Android build.
 * You must provide values for at least the build tools version and the
 * compilation target.
 */
android {
    compileSdkVersion 28
    buildToolsVersion "28.0.3"

    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 28

        // 10,00,000 major-minor-dev
        versionCode 1000000
        versionName '1.0.0'
    }

    /**
     * This nested sourceSets block points the source code directories to the
     * existing folders in the project, instead of using the default new
     * organization.
     */
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src', 'src_pd', 'src_pd_gcam', 'src_frameworks/camera2/portability/src', 'src_frameworks/camera2/public/src', 'src_frameworks/camera2/utils/src']
            jni.srcDirs = ['jni']
            jniLibs.srcDirs = ['jniLibs']
            // renderscript.srcDirs = ['src/main/renderscript']
            // aidl.srcDirs = ['src/main/aidl']
            // resources.srcDirs = ['src/main/resources']
            res.srcDirs = ['res', 'res_p']
            assets.srcDirs = ['assets']
        }

        // Move the tests to tests/java, tests/res, etc...
        androidTest.setRoot('tests')

        /**
         * Move the build types to build-types/<type>
         * For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
         * This moves them out of them default location under src/<type>/... which would
         * conflict with src/ being used by the main source set.
         * Adding new build types or product flavors should be accompanied
         * by a similar customization.
         */
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }

    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
    }
}

/**
 * This dependencies block includes any dependencies for the project itself. The
 * following line includes all the JAR files in the libs directory.
 */
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    // Add other library dependencies here (see the next step)
    implementation 'com.github.bumptech.glide:glide:3.8.0'
    implementation 'com.android.support:support-v4:28.0.0'
    implementation 'com.android.support:support-v13:28.0.0'
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.google.guava:guava:18.0'
    implementation 'com.adobe.xmp:xmpcore:6.1.10'
}

2.3 报错修复

在 Camera2 下新建 libs 文件夹,将下载的 jsr305-3.0.2.jar 复制进去,然后用 Android Studio 打开该项目:

报错:

删除:

继续报错:

[drawable-xxhdpi-v4/ic_refocus_disabled] C:\Users\xxx\Desktop\Camera2\res\drawable-xxhdpi\ic_refocus_disabled.png [drawable-xxhdpi-v4/ic_refocus_disabled] C:\Users\xxx\Desktop\Camera2\res_p\drawable-xxhdpi\ic_refocus_disabled.png: Error: Duplicate resources [drawable-xxhdpi-v4/ic_refocus_normal] C:\Users\xxx\Desktop\Camera2\res\drawable-xxhdpi\ic_refocus_normal.png [drawable-xxhdpi-v4/ic_refocus_normal] C:\Users\xxx\Desktop\Camera2\res_p\drawable-xxhdpi\ic_refocus_normal.png: Error: Duplicate resources

名字重复了,重命名一下,有类似错误的都重命名,继续编译:

不要高兴,点击 :

报错:

前面几个,需要重新导包,因为我引用了 xmpcore 库,包路径变了 。最后一个是文件名有问题:

这个应该是刚提的代码,我也是醉了...类似的问题,还有一个...所以 master 分支的代码还是谨慎下载。

继续报错:

嗯,复杂的来了,迁移 native 代码...

2.4 使用 CMake 构建 Native 代码

啥也不说了,点击 Studio 给的 链接

2.4.1 分析 jni/Android.mk

LOCAL_PATH:= $(call my-dir)

# TinyPlanet
include $(CLEAR_VARS)

LOCAL_CPP_EXTENSION := .cc
LOCAL_LDFLAGS   := -llog -ljnigraphics
LOCAL_SDK_VERSION := 17
LOCAL_MODULE    := libjni_tinyplanet
LOCAL_SRC_FILES := tinyplanet.cc

LOCAL_CFLAGS += -ffast-math -O3 -funroll-loops
LOCAL_CFLAGS += -Wall -Wextra -Werror
LOCAL_ARM_MODE := arm

include $(BUILD_SHARED_LIBRARY)

# JpegUtil
include $(CLEAR_VARS)

LOCAL_NDK_STL_VARIANT := c++_static
LOCAL_LDFLAGS   := -llog -ldl -ljnigraphics
LOCAL_SDK_VERSION := 17
LOCAL_MODULE    := libjni_jpegutil
LOCAL_SRC_FILES := jpegutil.cpp jpegutilnative.cpp

LOCAL_STATIC_LIBRARIES := libjpeg_static_ndk

LOCAL_CFLAGS += -ffast-math -O3 -funroll-loops
LOCAL_CFLAGS += -Wall -Wextra -Werror
LOCAL_ARM_MODE := arm

# Remove when libjpeg_static_ndk is XOM compatible.
LOCAL_XOM := false

include $(BUILD_SHARED_LIBRARY)

Android.mk 语法

该项目会生成 libjni_tinyplanet.solibjni_jpegutil.so。同时,编译这两个库时,都引用了原生 API /system/lib64/liblog.so/system/lib64/libjnigraphics.so 。编译 libjni_jpegutil.so 时,还引用了原生 API /system/lib64/libdl.so 和 静态库 libjpeg.a

原生 API 列表:点我

2.4.2 编写 CMakeLists.txt

在 Camera2 目录下,新建 CMakeLists.txt 文件,用记事本打开,根据对 Android.mk 的分析,CMakeLists.txt 编写如下:

# Sets the minimum version of CMake required to build your native library.
# This ensures that a certain set of CMake features is available to
# your build.

cmake_minimum_required(VERSION 3.4.1)

# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
# define multiple libraries by adding multiple add.library() commands,
# and CMake builds them for you. When you build your app, Gradle
# automatically packages shared libraries with your APK.

##################################################
###              NDK built-in libs             ###
##################################################
find_library( # Defines the name of the path variable that stores the
        # location of the NDK library.
        jnigraphics-lib

        # Specifies the name of the NDK library that
        # CMake needs to locate.
        jnigraphics)

find_library( # Defines the name of the path variable that stores the
        # location of the NDK library.
        log-lib

        # Specifies the name of the NDK library that
        # CMake needs to locate.
        log)

##################################################
###          Prebuilt libs: libjpeg            ###
##################################################
add_library( # Specifies the target library.
        libjpeg

        # Sets the library as a shared library.
        SHARED

        # Sets the library as a imported library.
        IMPORTED)

set_target_properties( # Specifies the target library.
        libjpeg

        # Specifies the parameter you want to define.
        PROPERTIES IMPORTED_LOCATION

        # Provides the path to the library you want to import.
        # Must be Absolute Path, relative path is Not Support!
        ${PROJECT_SOURCE_DIR}/jni/libs/${ANDROID_ABI}/libjpeg.so)

##################################################
###       App libs: libjni_tinyplanet          ###
##################################################
add_library( # Specifies the name of the library.
        jni_tinyplanet

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        jni/tinyplanet/tinyplanet.cc)

# Links your native library against one or more other native libraries.
target_link_libraries( # Specifies the target library.
        jni_tinyplanet

        # Links the log library to the target library.
        ${jnigraphics-lib}
        ${log-lib})

##################################################
###          App libs: libjni_jpegutil         ###
##################################################
add_library( # Specifies the name of the library.
        jni_jpegutil

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        jni/jpegutil/jpegutil.cpp jni/jpegutil/jpegutilnative.cpp)

# Links your native library against one or more other native libraries.
target_link_libraries( # Specifies the target library.
        jni_jpegutil

        # Links the log library to the target library.
        libjpeg
        ${jnigraphics-lib}
        ${log-lib})

##################################################
###           Include Headers                  ###
##################################################
# Optinal, CMake tookit recoganizes *.h automatically
#include_directories(jni)

时间关系,native code 的编译排错就不写了,以下列出相关参考资料:

2.4.3 修改 build.gradle,关联 CMakeLists.txt

在调用共享库的模块上右击,选择“Link C++ Project with Gradle”:

Gradle 中 CMake 支持的属性

完整的 build.gradle 如下:

// This buildscript{} block configures the code driving the build
buildscript {
    /**
     * The nested repositories{} block declares that this build uses the
     * jcenter repository.
     */
    repositories {
        // fix aapt cannot found error
        google()
        // download old version for somme jars
        mavenCentral()
        jcenter()
    }

    /**
     * This block declares a dependency on the 3.2.1 version
     * of the Gradle plugin for the buildscript.
     */
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
    }
}

allprojects {
    repositories {
        // fix aapt cannot found error
        google()
        // download old version for somme jars
        jcenter()
    }
}

/**
 * This line applies the com.android.application plugin. Note that you should
 * only apply the com.android.application plugin. Applying the Java plugin as
 * well will result in a build error.
 */
apply plugin: 'com.android.application'

/**
 * The android{} block configures all of the parameters for the Android build.
 * You must provide values for at least the build tools version and the
 * compilation target.
 */
android {
    compileSdkVersion 28
    buildToolsVersion "28.0.3"

    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 28

        // 10,00,000 major-minor-dev
        versionCode 1000000
        versionName '1.0.0'

        ndk {
            abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
        }
    }

    /**
     * This nested sourceSets block points the source code directories to the
     * existing folders in the project, instead of using the default new
     * organization.
     */
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src', 'src_pd', 'src_pd_gcam', 'src_frameworks/camera2/portability/src', 'src_frameworks/camera2/public/src', 'src_frameworks/camera2/utils/src']
            jni.srcDirs = ['jni']
            jniLibs.srcDirs = ['jniLibs']
            // renderscript.srcDirs = ['src/main/renderscript']
            // aidl.srcDirs = ['src/main/aidl']
            // resources.srcDirs = ['src/main/resources']
            res.srcDirs = ['res', 'res_p']
            assets.srcDirs = ['assets']
        }

        // Move the tests to tests/java, tests/res, etc...
        androidTest.setRoot('tests')

        /**
         * Move the build types to build-types/<type>
         * For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
         * This moves them out of them default location under src/<type>/... which would
         * conflict with src/ being used by the main source set.
         * Adding new build types or product flavors should be accompanied
         * by a similar customization.
         */
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }

    externalNativeBuild {
        cmake {
            path file('CMakeLists.txt')
        }
    }

    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
    }
}

/**
 * This dependencies block includes any dependencies for the project itself. The
 * following line includes all the JAR files in the libs directory.
 */
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    // Add other library dependencies here (see the next step)
    implementation 'com.github.bumptech.glide:glide:3.8.0'
    implementation 'com.android.support:support-v4:28.0.0'
    implementation 'com.android.support:support-v13:28.0.0'
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.google.guava:guava:18.0'
    implementation 'com.adobe.xmp:xmpcore:6.1.10'
}

3. 项目地址

Camera2 完整项目地址:点我