將 Google Camera2 遷移為 Gradle 編譯
專案經驗,如需轉載,請註明作者: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))
複製程式碼
原專案引用了 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)
複製程式碼
該專案會生成 libjni_tinyplanet.so
,libjni_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”:
完整的 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 完整專案地址:點我