將 Google Camera2 遷移為 Gradle 編譯

Youlou發表於2019-01-05

專案經驗,如需轉載,請註明作者:Yuloran (t.cn/EGU6c76)

前言

最近在研究 Google 的 Camera2 原始碼,因為該應用屬於 AOSP,所以是使用 Android.mk 編譯的。這就導致無法使用 Android Studio 來編譯和除錯,筆者便花了一番功夫,將其遷移為了 Gradle 編譯。

1. 原始碼下載

原始碼分為兩部分,一部分在 platform/packages/apps/Camer2 下:

將 Google Camera2 遷移為 Gradle 編譯

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

將 Google Camera2 遷移為 Gradle 編譯

下載完成後,新建 Camera2 資料夾,先把 app 的程式碼全複製進去,再在下面新建資料夾 src_frameworks,將 frameworks/ex/camera2 下程式碼也複製進去,像這樣:

將 Google Camera2 遷移為 Gradle 編譯

將 Google Camera2 遷移為 Gradle 編譯

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:

將 Google Camera2 遷移為 Gradle 編譯

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 開啟該專案:

將 Google Camera2 遷移為 Gradle 編譯

報錯:

將 Google Camera2 遷移為 Gradle 編譯

刪除:

將 Google Camera2 遷移為 Gradle 編譯

繼續報錯:

[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

名字重複了,重新命名一下,有類似錯誤的都重新命名,繼續編譯:

將 Google Camera2 遷移為 Gradle 編譯

不要高興,點選 :

將 Google Camera2 遷移為 Gradle 編譯

報錯:

將 Google Camera2 遷移為 Gradle 編譯

前面幾個,需要重新導包,因為我引用了 xmpcore 庫,包路徑變了 。最後一個是檔名有問題:

將 Google Camera2 遷移為 Gradle 編譯

這個應該是剛提的程式碼,我也是醉了...類似的問題,還有一個...所以 master 分支的程式碼還是謹慎下載。

繼續報錯:

將 Google Camera2 遷移為 Gradle 編譯

嗯,複雜的來了,遷移 native 程式碼...

2.4 使用 CMake 構建 Native 程式碼

啥也不說了,點選 Studio 給的 連結

將 Google Camera2 遷移為 Gradle 編譯

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”:

將 Google Camera2 遷移為 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 完整專案地址:點我

相關文章