Android Gradle Добавление статической библиотеки
В старом традиционном андроиде ndk мы укажем статическую библиотеку, которая будет связана в файле Android.mk.
Android.mk
PLATFORM_PREFIX := /opt/android-ext/
LOCAL_PATH := $(PLATFORM_PREFIX)/lib
include $(CLEAR_VARS)
LOCAL_MODULE := library
LOCAL_SRC_FILES := library.a
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_STATIC_LIBRARIES := android_native_app_glue library
Вот мой вопрос
Я немного запутался при переключении на Gradle экспериментальный плагин для NDK. Поделитесь своими идеями о том, как связать статическую библиотеку в файле приложения build.gradle.
Я следил за последней Gradle экспериментальной плагиновой документацией приведенной здесь.
Ответы
Ответ 1
Посмотрите на этот образец.
-
Сообщите компилятору, где находятся заголовки (в android.ndk{}
):
CFlags += "-I${file("path/to/headers")}".toString()
cppFlags += CFlags
-
Сообщите компоновщику, где находится файл .a(в android.ndk {} или где
определение вкусов - обязательно добавьте abiFilter - например
abiFilters += "armeabi-v7"
)
ldFlags += "-L${file(path/to/library.a)}".toString()
ldLibs += ["nameOfLibrary"]
Обратите внимание, что имя библиотеки по соглашению является строкой после
"lib" в имени файла .a. Например, для файла с именем libNative.a
вы должны добавить ldLibs + = [ "native" ] в gradle.
- Создайте новый модуль и используйте
apply plugin: 'java'
для применения java-плагина. В build.gradle напишите необходимый код, чтобы получить и поместить файл .a в соответствующий каталог (где вы его получите из своего модуля, который его использует). Не забудьте добавить зависимость в модуле с помощью библиотеки (compile project(':libraryModule')
в dependencies{}
) и включить ее в проект в файле settings.gradle с помощью include ':libraryModule'
. Если вы хотите поместить модуль в указанную вами папку (например, где в настоящий момент находится ваш файл Android.mk), просто добавьте project(':libraryModule').projectDir = new File(settingsDir, 'path/to/module')
.
Это должно сделать это.
Ответ 2
Вышеупомянутые ответы работают вокруг gradle до недостаточной интеграции NDK. Этот ответ иллюстрирует новую интеграцию gradle с NDK.
Взгляните на предложенный sample, написанный против gradle 2.9 и плагин android 0.6.0-alpha1. В отличие от того, как задан вопрос, этот ответ содержит отдельный проект для библиотеки. Эта функциональность может быть исследована, чтобы позволить gradle создавать эту библиотеку до ее использования в проекте приложения. Другие ответы основываются на предположении, что библиотека уже построена.
The: secondlib com.android.model.application
строит libsecondlib.so(загружается в Java-код с помощью System.loadLibrary( "secondlib" ). Имя 'secondlib' плохо названо. Мне нравится думать об этом как .so "wrapper" для всех других родных библиотек, связанных для использования приложением.
Эта общая библиотека статически связана с firstlib.a как построенная по: firstlib com.android.model.native
.
Заголовки экспортируются из: firstlib в любые зависимые проекты (: secondlib в этом примере) в соответствии с предложением exportedHeaders
. Таким образом, зависимые проекты знают, как связываться с .so/.a. Это заменяет синтаксис CFlags + = "- I/path/to/headers" в предыдущем ответе.
: ссылки secondlib против: firstlib статически в соответствии со следующим предложением:
android.sources {
main {
jni {
dependencies {
project ":firstlib" buildType "debug" linkage "static"
}
}
// TODO(proppy): show jniLibs dependencies on .so
}
}
Как показано в комментарии, пример неполный. Финальный синтаксис показан в разделе "Зависимости NDK" экспериментальной документации по подключению к Android. Внутри этого документа синтаксис для статической ссылки вместо динамической ссылки должен быть ясным.
В настоящее время существуют некоторые недостатки (например, buildType зависимости, показанной выше, по умолчанию "debug", а не текущий построенный тип buildType).
EDIT: вот образец выполнения нового синтаксиса зависимостей в приложении /build.gradle, извлеченный из одного из моих проектов:
android.sources {
main {
jni {
//for exportedHeaders
dependencies { project ":libfoo" linkage "shared" }
}
jniLibs {
//Where the swig wrapped library .so is. I use swig to create code to interface with libfoo.so within :app
source { srcDirs 'libs' }
//for file in $(model.repositories.libs.libfoo)
dependencies { library "libfoo" }
}
}
}
repositories {
libs(PrebuiltLibraries) {
libevdev {
//headers already available from our libfoo project via exportedHeaders
//headers.srcDir "../libfoo/src/main/jni/"
binaries.withType(SharedLibraryBinary) {
sharedLibraryFile = file("../libfoo/build/intermediates/binaries/debug/lib/${targetPlatform.getName()}/libfoo.so")
}
}
}
}
Ответ 3
Концептуально apk - это zip манифеста, собственные файлы и библиотека классов.
Поэтому, если вы скопируете статическую библиотеку для вывода, она будет работать.
Поэтому в gradle вы должны использовать задачу копирования и сделать эту библиотеку частью процесса вывода.
Я просто использовал ниже для своих файлов, и это сработало.
task copyNativeLibs2h(type: Copy) {
from(new File(getProjectDir(), 'libs')) { include '**/*.so' }
into new File(buildDir, 'native-libs')
}
tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn copyNativeLibs2h }
Ответ 4
Вы не можете создать статическую библиотеку с gradle, даже с экспериментальным плагином. Вы можете использовать предварительно созданную библиотеку или создать ее с помощью ndk-build
и связать ее с общим объектом с помощью плагина gradle.
Вот пример:
Предположим, что мы имеем эту структуру каталогов:
- project (build.gradle, gradle.properties и т.д.)
- jni_static (Application.mk, Android.mk, файлы cpp для статического lib)
- app (build.gradle, src/main и т.д.)
- jni_shared (файлы cpp для общей библиотеки)
И вот соответствующие фрагменты project/app/build.gradle:
// look for NDK directory
import org.apache.tools.ant.taskdefs.condition.Os
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkBuild = properties.getProperty('ndk.dir') + '/ndk-build'
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
ndkBuild += '.cmd'
}
apply plugin: 'com.android.model.application'
... зависимости, model {compileOptions и т.д.
// static lib is built with ndk-build
def LOCAL_MODULE = "static"
def appAbi = "armeabi-v7a"
def ndkOut = "build/intermediates/$LOCAL_MODULE"
def staticLibPath = "$ndkOut/local/$appAbi/lib${LOCAL_MODULE}.a"
// To guarantee that the intermediates shared library is always refreshed,
// we delete it in gradle task rmSO.
task rmSO(type: Delete) {
delete 'build/intermediates/binaries/debug/lib/armeabi-v7a', 'libshared.so'
delete 'build/intermediates/binaries/debug/obj/armeabi-v7a', 'libshared.so'
}
// in file jni/Android.mk there is a section for LOCAL_MODULE=static
// which builds the static library
task buildStaticLib(type: Exec, description: 'Compile Static lib via NDK') {
commandLine "$ndkBuild", "$staticLibPath", "NDK_APPLICATION_MK=../jni_static/Application.mk",
"NDK_PROJECT_PATH=../jni_static", "NDK_OUT=$ndkOut"
dependsOn rmSO
}
task cleanNative(type: Exec, description: 'Clean JNI object files') {
commandLine "$ndkBuild", "clean", "NDK_APPLICATION_MK=../jni_static/Application.mk",
"NDK_PROJECT_PATH=../jni_static", "NDK_OUT=$ndkOut"
}
clean.dependsOn cleanNative
tasks.all {
task ->
// link of the shared library depends on build of the static lib
if (task.name.startsWith('link')) {
task.dependsOn buildStaticLib
}
// before build, make sure the intermediate so is not stuck there
if (task.name.startsWith('package')) {
task.dependsOn rmSO
}
}
// build the wrapper shared lib around the static lib using the experimental plugin
model {
android.ndk {
moduleName = "shared"
cppFlags += "-std=c++11"
ldFlags += "$staticLibPath".toString()
ldLibs += "log"
stl = "gnustl_static"
abiFilters += "$appAbi".toString()
}
android.sources {
main.jni.source {
srcDirs = ["jni_shared"]
}
}
}
Важно: источники для общей библиотеки должны быть в отдельном каталоге, так что источники статической библиотеки не находятся в ней или под ней. Это связано с тем, что экспериментальный плагин не может исключать некоторые файлы в srcDirs
.