项目经验,如需转载,请注明作者: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 完整项目地址:点我