Połącz Gradle z biblioteką natywną

Aby uwzględnić projekt biblioteki natywnej jako zależność kompilacji w Gradle, musisz spełnić te warunki: , aby udostępnić Gradle ścieżkę do pliku skryptu CMake lub ndk-build. Kiedy kompilujesz aplikację, Gradle uruchamia CMake lub ndk-build oraz udostępnia pakiety biblioteki. Gradle używa też skryptu kompilacji, aby określić, które pliki do projektu Android Studio. Dzięki temu masz do nich dostęp Okno Projekt. Jeśli nie masz skryptu kompilacji musisz utworzyć Zanim przejdziesz dalej,utwórz skrypt kompilacji.

Każdy moduł w projekcie Androida może być połączony tylko z jedną domeną CMake lub ndk-build skrypt. Jeśli na przykład chcesz skompilować i pakietować dane wyjściowe wiele projektów CMake, musisz użyć 1 pliku CMakeLists.txt jako skrypt kompilacji najwyższego poziomu CMake (z którym następnie łączysz Gradle), dodaj inne projekty CMake jako i zależności tego skryptu. Podobnie, jeśli używasz polecenia ndk-build, dołączać inne pliki Makefiles Android.mk skryptu.

Gdy połączysz Gradle z projektem natywnym, Android Studio zaktualizuje Panel projektu, w którym wyświetlają się pliki źródłowe i biblioteki natywne w grupie cpp, a zewnętrzne skrypty kompilacji w Grupa Zewnętrzne pliki kompilacji.

Uwaga: podczas wprowadzania zmian w konfiguracji Gradle pamiętaj, aby wykonać zastosuj zmiany, klikając Synchronizuj projekt . na pasku narzędzi. Dodatkowo podczas wprowadzania zmian w narzędziu CMake lub ndk-build po połączeniu go z Gradle, należy zsynchronizować Android Studio ze zmianami przez wybranie Build > > Odśwież połączony C++ Projekty na pasku menu.

Możesz połączyć Gradle z zewnętrznym projektem CMake lub ndk-build za pomocą Interfejs Android Studio:

  1. Otwórz panel Projekt po lewej stronie IDE i wybierz widok Android.
  2. Kliknij prawym przyciskiem myszy moduł, który chcesz połączyć z biblioteką natywną. na przykład moduł aplikacji i wybierz Połącz projekt C++ za pomocą Gradle w menu. Zobaczysz okno podobne do widoczna na ilustracji 4.
  3. W menu wybierz CMake lub . ndk-build
    1. Jeśli wybierzesz CMake, użyj pola obok Ścieżka projektu, aby określić skrypt CMakeLists.txt zewnętrznego projektu CMake.
    2. Jeśli wybierzesz ndk-build, użyj pola obok Ścieżka projektu, aby określić plik skryptu Android.mk do zewnętrznego projektu ndk-build. Android Studio zawiera też Application.mk , jeśli znajduje się on w tym samym katalogu Android.mk.

    Rysunek 4. Łączenie zewnętrznego projektu w C++ za pomocą Okno Android Studio.

  4. Kliknij OK.

Ręczne konfigurowanie Gradle

Aby ręcznie skonfigurować połączenie Gradle z Twoją biblioteką natywną, musisz dodać externalNativeBuild na poziomie modułu build.gradle i skonfiguruj go za pomocą cmake lub Blokada ndkBuild:

Odlotowe

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ącą kompilacją ndk-build projektu, użyj funkcji blok ndkBuild zamiast cmake i podaj ścieżkę względną do pliku Android.mk. Także Gradle zawiera plik Application.mk, jeśli znajduje się w tym samym katalogu co plik Android.mk.

Określ konfiguracje opcjonalne

Opcjonalne argumenty i flagi możesz określić dla CMake lub ndk-build przez konfigurowanie innego urządzenia externalNativeBuild w defaultConfig blok na poziomie modułu build.gradle. Podobnie jak w przypadku innych obiektów w defaultConfig, możesz zastąpić te właściwości w każdym z nich rodzaj usługi w konfiguracji kompilacji.

Jeśli na przykład projekt CMake lub ndk-build definiuje wiele reklam natywnych bibliotek i plików wykonywalnych, możesz użyć funkcji targets, aby tworzyć i pakować tylko ich podzbiór. artefaktów danego rodzaju produktów. Poniższy przykładowy kod opisuje właściwości, które możesz skonfigurować:

Odlotowe

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 typów produktów i tworzeniu wersji produktów znajdziesz na stronie Skonfiguruj warianty kompilacji. Dla: listę zmiennych, które można skonfigurować pod kątem CMake za pomocą arguments – zapoznaj się z sekcją Używanie zmiennych CMake.

Dołącz gotowe biblioteki natywne

Jeśli chcesz, aby Gradle pakowała gotowe biblioteki natywne, które nie są używane zewnętrzną kompilację reklam natywnych, dodaj ją do src/main/jniLibs/ABI do katalogu modułu.

Wymagane są wersje wtyczki Androida do obsługi Gradle starsze niż 4.0, w tym CMake IMPORTED celów w katalogu jniLibs, aby zostały uwzględnione w . Jeśli przeprowadzasz migrację z wcześniejszej wersji wtyczki, pojawi się błąd podobny do tego:

* 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 Aby uniknąć tego błędu, utwórz elementy docelowe poza katalogiem jniLibs.

Określ interfejsy ABI

Domyślnie Gradle kompiluje Twoją natywną bibliotekę w osobne zasoby .so pliki interfejsów binarnych aplikacji NDK obsługuje i umieszcza je w aplikacji w formie pakietu (ABI). Jeśli chcesz Gradle do tworzenia i pakowania tylko niektórych konfiguracji ABI interfejsu natywnego można określić za pomocą funkcji ndk.abiFilters w pliku build.gradle na poziomie modułu, jak pokazano poniżej:

Odlotowe

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 określić abiFilters tylko w Blok ndk, jak pokazano powyżej, ponieważ informuje Gradle, aby kompilowały i zapakuj te wersje bibliotek natywnych. Jeśli jednak chcesz kontrolować, co Gradle ma skompilować niezależnie od tego, co ma do aplikacji, skonfiguruj inną flagę abiFilters w Blokuj defaultConfig.externalNativeBuild.cmake (lub defaultConfig.externalNativeBuild.ndkBuild). Gradle tworzy te konfiguracje ABI, ale łączy tylko te konfiguracje defaultConfig.ndk.

Zalecamy publikowanie przy użyciu pakietów Android App Bundle, aby jeszcze bardziej ograniczyć rozmiaru Twojej aplikacji, ponieważ tylko biblioteki natywne zgodne z interfejsem ABI urządzenie zostanie dostarczone wraz z pobranym plikiem.

W przypadku starszych aplikacji publikowanych z użyciem plików APK (utworzonych przed sierpniem 2021 r.): konfigurowanie wiele plików APK opartych na ABI – zamiast tworzyć jeden duży plik APK ze wszystkimi Twoich bibliotek natywnych, Gradle utworzy oddzielny plik APK dla każdego interfejsu ABI które chcesz obsługiwać, i tworzy pakiet tylko dla plików, których wymaga poszczególne interfejsy ABI. Jeśli skonfigurować wiele plików APK dla każdego interfejsu ABI bez określania Flaga abiFilters jak w przykładowym kodzie powyżej, kompilacje Gradle wszystkich obsługiwanych wersji ABI bibliotek natywnych, ale pakuje tylko określone w konfiguracji z wieloma plikami APK. Aby uniknąć tworzenia wersji bibliotek natywnych, których nie potrzebujesz, podaj tę samą listę interfejsów ABI zarówno flaga abiFilters, jak i kilku plików APK dla każdego ABI. konfiguracji.