Associer Gradle à votre bibliothèque native

Pour inclure votre projet de bibliothèque native en tant que dépendance de compilation Gradle, vous devez indiquer à Gradle le chemin d'accès à votre fichier de script CMake ou ndk-build. Lorsque vous compilez votre application, Gradle exécute CMake ou ndk-build, puis crée des packages à partir de bibliothèques partagées avec votre application. Gradle utilise également le script de compilation pour savoir quels fichiers importer dans votre projet Android Studio. Vous pouvez ainsi y accéder à partir de la fenêtre Project (Projet). Si vous n'avez pas de script de compilation pour vos sources natives, vous devez créer un script de compilation CMake avant de continuer.

Chaque module de votre projet Android ne peut être associé qu'à un seul fichier de script CMake ou ndk-build. Par exemple, si vous souhaitez compiler et créer des packages à partir des sorties de plusieurs projets CMake, vous devez utiliser un fichier CMakeLists.txt en tant que script de compilation CMake de premier niveau (auquel vous associez ensuite Gradle) et ajouter d'autres projets CMake en tant que dépendances de ce script de compilation. De même, si vous utilisez ndk-build, vous pouvez inclure d'autres fichiers makefile dans votre fichier de script Android.mk de premier niveau.

Une fois que vous avez lié Gradle à un projet natif, Android Studio met à jour le volet Project pour afficher vos fichiers source et bibliothèques natives dans le groupe cpp et vos scripts de compilation externes dans le groupe External Build Files (Fichiers de compilation externes).

Remarque : lorsque vous apportez des modifications à la configuration Gradle, veillez à les appliquer en cliquant sur Sync Project (Synchroniser le projet) dans la barre d'outils. En outre, lorsque vous apportez des modifications à votre fichier de script CMake ou ndk-build après l'avoir déjà associé à Gradle, vous devez synchroniser Android Studio avec vos modifications en sélectionnant Build > Refresh Linked C++ (Compilation > Actualiser les projets C++ associés) dans la barre de menu.

Vous pouvez associer Gradle à un projet CMake ou ndk-build externe à l'aide de l'interface utilisateur Android Studio :

  1. Ouvrez le volet Project (Projet) à gauche de l'IDE et sélectionnez la vue Android.
  2. Effectuez un clic droit sur le module que vous souhaitez associer à votre bibliothèque native, par exemple le module app, puis sélectionnez Link C++ Project with Gradle (Associer un projet C++ avec Gradle) dans le menu. Une boîte de dialogue semblable à celle illustrée dans la figure 4 doit s'afficher.
  3. Dans le menu déroulant, sélectionnez CMake ou ndk-build.
    1. Si vous sélectionnez CMake, renseignez le champ à côté de Project Path (Chemin d'accès au projet) pour spécifier le fichier de script CMakeLists.txt de votre projet CMake externe.
    2. Si vous sélectionnez ndk-build, renseignez le champ à côté de Project Path (Chemin d'accès au projet) pour spécifier le fichier de script Android.mk de votre projet ndk-build externe. Android Studio inclut également le fichier Application.mk s'il se trouve dans le même répertoire que votre fichier Android.mk.

    Figure 4. Associer un projet C++ externe à l'aide de la boîte de dialogue Android Studio

  4. Cliquez sur OK.

Configurer manuellement Gradle

Pour associer manuellement Gradle à votre bibliothèque native, vous devez ajouter le bloc externalNativeBuild à votre fichier build.gradle au niveau du module et le configurer avec le bloc cmake ou ndkBuild :

Groovy

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")
    }
  }
}

Remarque : si vous souhaitez associer Gradle à un projet ndk-build existant, utilisez le bloc ndkBuild au lieu du bloc cmake et fournissez un chemin d'accès à votre fichier Android.mk. Gradle inclut également le fichier Application.mk s'il se trouve dans le même répertoire que votre fichier Android.mk.

Spécifier des configurations facultatives

Vous pouvez spécifier des options et des arguments facultatifs pour CMake ou ndk-build en configurant un autre bloc externalNativeBuild dans le bloc defaultConfig de votre fichier build.gradle au niveau du module. Comme pour les autres propriétés du bloc defaultConfig, vous pouvez remplacer ces propriétés pour chaque type de produit de votre configuration de compilation.

Par exemple, si votre projet CMake ou ndk-build définit plusieurs bibliothèques natives et exécutables, vous pouvez utiliser la propriété targets pour compiler et créer des packages uniquement à partir d'un sous-ensemble de ces artefacts pour un type de produit donné. L'exemple de code suivant décrit certaines des propriétés que vous pouvez configurer :

Groovy

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 {...}
  }
}

Pour en savoir plus sur la configuration des types de produit et sur les variantes de compilation, consultez l'article Configurer des variantes de compilation. Pour obtenir la liste des variables que vous pouvez configurer pour CMake avec la propriété arguments, consultez la section Utiliser des variables CMake.

Inclure les bibliothèques natives prédéfinies

Si vous souhaitez que Gradle crée des packages à partir des bibliothèques natives prédéfinies qui ne sont utilisées dans aucune compilation native externe, ajoutez-les au répertoire src/main/jniLibs/ABI de votre module.

Pour qu'elles soient incluses dans votre application, vous devez inclure les cibles CMake IMPORTED dans votre répertoire jniLibs pour les versions du plug-in Android Gradle antérieures à la version 4.0. Si vous migrez depuis une version antérieure du plug-in, vous pouvez rencontrer une erreur semblable à celle-ci :

* 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'

Si vous utilisez la version 4.0 du plug-in Android Gradle, sortez les bibliothèques utilisées par les cibles CMake IMPORTED de votre répertoire jniLibs pour éviter cette erreur.

Spécifier des ABI

Par défaut, Gradle compile votre bibliothèque native dans des fichiers .so distincts pour les interfaces binaires d'application (ABI) compatibles avec le NDK et les met dans des packages dans votre application. Si vous souhaitez que Gradle compile et crée des package uniquement à partir de certaines configurations d'ABI de vos bibliothèques natives, vous pouvez les spécifier avec l'option ndk.abiFilters dans votre fichier build.gradle au niveau du module, comme illustré ci-dessous :

Groovy

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 {...}
}

Dans la plupart des cas, il vous suffit de spécifier abiFilters dans le bloc ndk, comme indiqué ci-dessus, car il indique à Gradle de compiler et de créer des packages à partir de ces versions de vos bibliothèques natives. Toutefois, si vous souhaitez contrôler ce que Gradle doit compiler, indépendamment des éléments à mettre dans des packages dans votre application, configurez une autre option abiFilters dans le bloc defaultConfig.externalNativeBuild.cmake (ou le bloc defaultConfig.externalNativeBuild.ndkBuild). Gradle compile ces configurations d'ABI, mais ne crée des packages qu'à partir de celles que vous spécifiez dans le bloc defaultConfig.ndk.

Nous vous recommandons d'utiliser le format Android App Bundle pour réduire davantage la taille de votre application, car seules les bibliothèques natives correspondant à l'ABI de l'appareil de l'utilisateur seront fournies avec le téléchargement.

Concernant la publication d'anciennes applications à l'aide d'APK (créés avant août 2021), envisagez de configurer plusieurs APK en fonction de l'ABI plutôt que de créer un APK volumineux avec toutes les versions de vos bibliothèques natives. Gradle crée un APK distinct pour chaque ABI que vous souhaitez prendre en charge et ne crée des packages qu'à partir des fichiers dont chaque ABI a besoin. Si vous configurez plusieurs APK par ABI sans spécifier l'option abiFilters, comme indiqué dans l'exemple de code ci-dessus, Gradle compile toutes les versions d'ABI prises en charge de vos bibliothèques natives, mais ne crée des packages qu'à partir de celles que vous spécifiez dans votre configuration à plusieurs APK. Pour éviter de compiler des versions de vos bibliothèques natives dont vous n'avez pas besoin, fournissez la même liste d'ABI pour l'option abiFilters et votre configuration à plusieurs APK par ABI.