Aby uwzględnić projekt biblioteki natywnej jako zależność kompilacji Gradle, musisz podać Gradle ścieżkę do pliku skryptu kompilacji CMake lub ndk. Gdy tworzysz aplikację, Gradle uruchamia CMake lub ndk-build i pakuje biblioteki udostępnione Twojej aplikacji. Gradle korzysta również ze skryptu kompilacji, aby wiedzieć, które pliki pobrać do projektu Android Studio, dzięki czemu masz do nich dostęp w oknie Project (Projekt). Jeśli nie masz skryptu kompilacji dla źródeł natywnych, musisz najpierw utworzyć skrypt kompilacji CMake.
Każdy moduł w projekcie na Androida może być połączony tylko z jednym plikiem skryptu CMake lub ndk-build. Jeśli na przykład chcesz kompilować i spakować dane wyjściowe z wielu projektów CMake, musisz użyć 1 pliku CMakeLists.txt
jako skryptu kompilacji CMake najwyższego poziomu (który następnie połączysz z Gradle) i
dodać inne projekty CMake jako zależności tego skryptu. Podobnie, jeśli używasz ndk-build, możesz dołączyć inne pliki Makefiles w pliku skryptu Android.mk
najwyższego poziomu.
Gdy połączysz Gradle z projektem natywnym, Android Studio zaktualizuje panel Projekt, aby wyświetlać pliki źródłowe i biblioteki natywne w grupie cpp, a zewnętrzne skrypty kompilacji w grupie Zewnętrzne pliki kompilacji.
Uwaga: gdy wprowadzasz zmiany w konfiguracji Gradle, pamiętaj, aby zastosować zmiany, klikając Synchronizuj projekt na pasku narzędzi. Dodatkowo w przypadku wprowadzania zmian w pliku skryptu CMake lub ndk-build już po połączeniu go z Gradle, należy zsynchronizować Android Studio ze zmianami, wybierając Build > Odśwież połączone projekty C++ z paska menu.
Korzystanie z interfejsu Android Studio
Możesz połączyć Gradle z zewnętrznym projektem CMake lub ndk-build za pomocą interfejsu Android Studio:
- Otwórz panel Projekt z lewej strony IDE i wybierz widok Android.
- Kliknij prawym przyciskiem myszy moduł, który chcesz połączyć z biblioteką natywną, na przykład moduł aplikacji, i z menu wybierz Połącz projekt C++ z Gradle. Powinno wyświetlić się okno podobne do pokazanego na rys. 4.
- Z menu wybierz CMake lub ndk-build.
- Jeśli wybierzesz CMake, w polu obok opcji Ścieżka projektu określ plik skryptu
CMakeLists.txt
dla zewnętrznego projektu CMake. - Jeśli wybierzesz ndk-build, w polu obok opcji Ścieżka projektu podaj plik skryptu
Android.mk
dla zewnętrznego projektu ndk-build. Android Studio zawiera też plikApplication.mk
, jeśli znajduje się w tym samym katalogu co plikAndroid.mk
.
- Jeśli wybierzesz CMake, w polu obok opcji Ścieżka projektu określ plik skryptu
- Kliknij OK.
Ręczne konfigurowanie Gradle
Aby ręcznie skonfigurować połączenie Gradle z biblioteką natywną, musisz dodać blok
externalNativeBuild
do pliku build.gradle
na poziomie modułu i skonfigurować go za pomocą bloku
cmake
lub
ndkBuild
:
Odlotowy
android { ... defaultConfig {...} buildTypes {...} // Encapsulates your external native build configurations. externalNativeBuild { // Encapsulates your CMake build configurations. cmake { // Provides a relative path to your CMake build script. path "CMakeLists.txt" } } }
Kotlin
android { ... defaultConfig {...} buildTypes {...} // Encapsulates your external native build configurations. externalNativeBuild { // Encapsulates your CMake build configurations. cmake { // Provides a relative path to your CMake build script. path = file("CMakeLists.txt") } } }
Uwaga: jeśli chcesz połączyć Gradle z istniejącym projektem kompilacji ndk, użyj bloku
ndkBuild
zamiast bloku
cmake
i podaj względną ścieżkę do pliku Android.mk
. Gradle zawiera też plik Application.mk
, jeśli znajduje się w tym samym katalogu co plik Android.mk
.
Podaj konfiguracje opcjonalne
Możesz określić opcjonalne argumenty i flagi dla CMake lub ndk-build, konfigurując kolejny blok
externalNativeBuild
w bloku defaultConfig
w pliku build.gradle
na poziomie modułu. Podobnie jak w przypadku innych właściwości w bloku defaultConfig
, możesz zastąpić te właściwości dla każdego rodzaju usługi w konfiguracji kompilacji.
Jeśli na przykład Twój projekt CMake lub ndk-build definiuje wiele bibliotek natywnych i plików wykonywalnych, możesz użyć właściwości
targets
, aby skompilować i spakować tylko podzbiór tych artefaktów dla danego rodzaju usługi. Ten przykładowy kod opisuje niektóre właściwości, które możesz skonfigurować:
Odlotowy
android { ... defaultConfig { ... // This block is different from the one you use to link Gradle // to your CMake or ndk-build script. externalNativeBuild { // For ndk-build, instead use the ndkBuild block. cmake { // Passes optional arguments to CMake. arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang" // Sets a flag to enable format macro constants for the C compiler. cFlags "-D__STDC_FORMAT_MACROS" // Sets optional flags for the C++ compiler. cppFlags "-fexceptions", "-frtti" } } } buildTypes {...} productFlavors { ... demo { ... externalNativeBuild { cmake { ... // Specifies which native libraries or executables to build and package // for this product flavor. The following tells Gradle to build only the // "native-lib-demo" and "my-executible-demo" outputs from the linked // CMake project. If you don't configure this property, Gradle builds all // executables and shared object libraries that you define in your CMake // (or ndk-build) project. However, by default, Gradle packages only the // shared libraries in your app. targets "native-lib-demo", // You need to specify this executable and its sources in your CMakeLists.txt // using the add_executable() command. However, building executables from your // native sources is optional, and building native libraries to package into // your app satisfies most project requirements. "my-executible-demo" } } } paid { ... externalNativeBuild { cmake { ... targets "native-lib-paid", "my-executible-paid" } } } } // Use this block to link Gradle to your CMake or ndk-build script. externalNativeBuild { cmake {...} // or ndkBuild {...} } }
Kotlin
android { ... defaultConfig { ... // This block is different from the one you use to link Gradle // to your CMake or ndk-build script. externalNativeBuild { // For ndk-build, instead use the ndkBuild block. cmake { // Passes optional arguments to CMake. arguments += listOf("-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang") // Sets a flag to enable format macro constants for the C compiler. cFlags += listOf("-D__STDC_FORMAT_MACROS") // Sets optional flags for the C++ compiler. cppFlags += listOf("-fexceptions", "-frtti") } } } buildTypes {...} productFlavors { ... create("demo") { ... externalNativeBuild { cmake { ... // Specifies which native libraries or executables to build and package // for this product flavor. The following tells Gradle to build only the // "native-lib-demo" and "my-executible-demo" outputs from the linked // CMake project. If you don't configure this property, Gradle builds all // executables and shared object libraries that you define in your CMake // (or ndk-build) project. However, by default, Gradle packages only the // shared libraries in your app. targets += listOf("native-lib-demo", // You need to specify this executable and its sources in your CMakeLists.txt // using the add_executable() command. However, building executables from your // native sources is optional, and building native libraries to package into // your app satisfies most project requirements. "my-executible-demo") } } } create("paid") { ... externalNativeBuild { cmake { ... targets += listOf("native-lib-paid", "my-executible-paid") } } } } // Use this block to link Gradle to your CMake or ndk-build script. externalNativeBuild { cmake {...} // or ndkBuild {...} } }
Więcej informacji o konfigurowaniu rodzajów usług i wersji kompilacji znajdziesz w artykule o konfigurowaniu wersji kompilacji. Listę zmiennych, które możesz skonfigurować pod kątem CMake, za pomocą właściwości arguments
znajdziesz w artykule Używanie zmiennych CMake.
Uwzględnij gotowe biblioteki natywne
Jeśli chcesz, by Gradle umieszczała w pakiecie gotowe biblioteki natywne, które nie są używane w żadnej zewnętrznej kompilacji natywnej, dodaj je do katalogu src/main/jniLibs/ABI
swojego modułu.
Aby można było uwzględnić je w aplikacji, wymagane są wersje wtyczki Androida do obsługi Gradle starsze niż 4.0, w tym cele CMake IMPORTED
w katalogu jniLibs
. Jeśli przeprowadzasz migrację z wcześniejszej wersji wtyczki, może pojawić się następujący błąd:
* What went wrong:
Execution failed for task ':app:mergeDebugNativeLibs'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
> More than one file was found with OS independent path 'lib/x86/libprebuilt.so'
Jeśli używasz wtyczki Androida do obsługi Gradle w wersji 4.0, przenieś wszystkie biblioteki używane przez IMPORTED
elementy docelowe CMake poza katalog jniLibs
, aby uniknąć tego błędu.
Określ interfejsy ABI
Domyślnie Gradle kompiluje bibliotekę natywną w osobne pliki .so
dla interfejsów binarnych aplikacji (ABI) obsługiwanych przez NDK i pakuje je wszystkie do aplikacji. Jeśli chcesz, by Gradle skompilowała i spakowała tylko określone konfiguracje ABI bibliotek natywnych, możesz je określić za pomocą flagi ndk.abiFilters
w pliku build.gradle
na poziomie modułu, jak pokazano poniżej:
Odlotowy
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {...}
// or ndkBuild {...}
}
// Similar to other properties in the defaultConfig
block,
// you can configure the ndk block for each product flavor
// in your build configuration.
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your app.
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
'arm64-v8a'
}
}
buildTypes {...}
externalNativeBuild {...}
}
Kotlin
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {...}
// or ndkBuild {...}
}
// Similar to other properties in the defaultConfig
block,
// you can configure the ndk block for each product flavor
// in your build configuration.
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your app.
abiFilters += listOf("x86", "x86_64", "armeabi", "armeabi-v7a",
"arm64-v8a")
}
}
buildTypes {...}
externalNativeBuild {...}
}
W większości przypadków wystarczy podać w bloku ndk
tylko abiFilters
, jak pokazano powyżej, ponieważ informuje to Gradle o kompilowanie i pakowanie tych wersji bibliotek natywnych. Jeśli jednak chcesz kontrolować, co ma kompilować Gradle, niezależnie od tego, co ma zostać spakowane do aplikacji, skonfiguruj kolejną flagę abiFilters
w bloku
defaultConfig.externalNativeBuild.cmake
(lub bloku
defaultConfig.externalNativeBuild.ndkBuild
). Gradle kompiluje te konfiguracje ABI, ale pakuje tylko te określone w bloku
defaultConfig.ndk
.
Zalecamy publikowanie aplikacji za pomocą pakietów Android App Bundle, aby jeszcze bardziej zmniejszyć jej rozmiar, ponieważ pobierane są tylko biblioteki natywne pasujące do interfejsu ABI urządzenia użytkownika.
W przypadku starszych aplikacji publikowanych za pomocą plików APK (utworzonych przed sierpniem 2021 r.) rozważ skonfigurowanie wielu plików APK opartych na interfejsie ABI. Zamiast tworzyć jeden duży plik ze wszystkimi wersjami bibliotek natywnych, Gradle tworzy oddzielny plik APK dla każdego obsługiwanego interfejsu ABI i pakuje tylko te pliki, których potrzebuje dany interfejs ABI. Jeśli skonfigurujesz wiele plików APK dla jednego interfejsu ABI bez określania flagi abiFilters
, jak pokazano w przykładzie powyżej, Gradle skompiluje wszystkie obsługiwane wersje ABI bibliotek natywnych, ale pakuje tylko te określone w konfiguracji z wieloma plikami APK. Aby uniknąć tworzenia wersji bibliotek natywnych, które są niepotrzebne, podaj tę samą listę interfejsów ABI dla flagi abiFilters
i konfiguracji wielu plików APK dla poszczególnych interfejsów ABI.