Participe do evento ⁠#Android11: apresentação de lançamento da versão Beta no dia 3 de junho.

Vincular o Gradle à biblioteca nativa

Para incluir seu projeto de biblioteca nativa como uma dependência de compilação do Gradle, é preciso que o Gradle tenha o caminho para seu arquivo de script CMake ou ndk-build. Quando você compila um app, o Gradle executa esse arquivo e empacota bibliotecas compartilhadas no APK. Além disso, ele usa o build script para saber quais arquivos serão incorporados ao projeto do Android Studio, para que eles possam ser acessados pela janela Project. Se você não tem um build script para as origens nativas, é necessário criar um build script do CMake antes de continuar.

Cada módulo do projeto Android pode vincular apenas um arquivo de script CMake ou ndk-build. Por exemplo, se você quiser compilar e empacotar saídas de vários projetos CMake, será necessário usar um arquivo CMakeLists.txt como seu build script CMake de nível superior, ao qual o Gradle será vinculado, e incluir outros projetos do CMake como dependências desse build script. Da mesma forma, se você estiver usando o ndk-build, será possível incluir outros Makefiles (link em inglês) ao arquivo de script Android.mk de nível superior.

Depois de vincular o Gradle a um projeto nativo, o Android Studio atualiza o painel Project para mostrar os arquivos de origem e as bibliotecas nativas no grupo cpp, e os build scripts externos no grupo External Build Files.

Observação: ao fazer mudanças na configuração do Gradle, aplique-as clicando em Sync Project na barra de ferramentas. Além disso, quando você mudar o arquivo de script do CMake ou do ndk-build após vinculá-lo ao Gradle, selecione Build > Refresh Linked C++ Projects na barra de menus para sincronizar o Android Studio com as mudanças.

Você pode usar a IU do Android Studio para vincular o Gradle a um projeto CMake ou ndk-build externo:

  1. Abra o painel Project à esquerda do ambiente de desenvolvimento integrado e selecione a visualização Android.
  2. Clique com o botão direito no módulo que você quer vincular à biblioteca nativa, por exemplo, o módulo app, e selecione {Link C++ Project with Gradle/0} no menu. Você deve ver uma caixa de diálogo semelhante à mostrada na figura 4.
  3. No menu suspenso, selecione CMake ou ndk-build.
    1. Se você selecionar CMake, use o campo ao lado de Project Path para especificar o CMakeLists.txt arquivo de script para o projeto CMake externo.
    2. Se você selecionar ndk-build, use o campo ao lado de Project Path para especificar o arquivo de script Android.mk para o projeto ndk-build externo. O Android Studio também incluirá o arquivo Application.mk se ele estiver no mesmo diretório que o arquivo Android.mk.

    Figura 4. Vincular um projeto C++ externo usando a caixa de diálogo do Android Studio.

  4. Clique em OK.

Configurar manualmente o Gradle

Para configurar o Gradle manualmente e vinculá-lo à sua biblioteca nativa, é necessário adicionar o bloco externalNativeBuild ao arquivo build.gradle do módulo e configurá-lo com o bloco cmake ou ndkBuild (links em inglês):

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

Observação: caso queira vincular o Gradle a um projeto existente do ndk-build, use o bloco ndkBuild em vez do bloco cmake (links em inglês) e informe um caminho relativo para o arquivo Android.mk. O Gradle também inclui o arquivo Application.mk se ele estiver localizado no mesmo diretório que o Android.mk.

Especificar configurações opcionais

Você pode especificar argumentos e sinalizações opcionais para o CMake ou ndk-build configurando outro bloco externalNativeBuild (link em inglês) no bloco defaultConfig do arquivo build.gradle do módulo. Assim como em outras propriedades no bloco defaultConfig, é possível modificar essas propriedades para cada variação de produto na sua configuração de compilação.

Por exemplo: se o projeto CMake ou ndk-build definir várias bibliotecas nativas e executáveis, você poderá usar a propriedade targets (link em inglês) para compilar e empacotar apenas um subconjunto desses artefatos para uma determinada variação de produto. A amostra de código a seguir descreve algumas das propriedades que podem ser configuradas:

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

Para saber mais sobre como configurar variações de produtos e de compilação, consulte Configurar variantes de compilação. Para ver uma lista de variáveis que podem ser configuradas para o CMake com a propriedade arguments, consulte Usar variáveis do CMake.

Incluir bibliotecas nativas pré-compiladas

Se você quiser que o Gradle empacote bibliotecas nativas pré-compiladas com seu APK, modifique as configurações do conjunto de origem padrão para incluir o diretório dos arquivos .so pré-compilados, conforme mostrado abaixo. Não é necessário fazer isso para incluir artefatos de scripts de compilação do CMake vinculados ao Gradle.

    android {
        ...
        sourceSets {
            main {
                jniLibs.srcDirs 'imported-lib/src/', 'more-imported-libs/src/'
            }
        }
    }
    

Especificar ABIs

Por padrão, o Gradle compila sua biblioteca nativa em arquivos .so separados para as Interfaces binárias de aplicativo (ABIs, na sigla em inglês) compatíveis com o NDK e inclui todas elas no APK. Caso queira que o Gradle compile e empacote somente determinadas configurações de ABI das suas bibliotecas nativas, especifique-as com a sinalização ndk.abiFilters no arquivo build.gradle de nível de módulo, conforme mostrado abaixo:

    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 APK.
          abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
                       'arm64-v8a'
        }
      }
      buildTypes {...}
      externalNativeBuild {...}
    }
    

Na maioria dos casos, basta especificar abiFilters no bloco ndk, conforme mostrado acima, porque isso instrui o Gradle a compilar e empacotar essas versões das suas bibliotecas nativas. No entanto, caso queira controlar o que o Gradle compilará, independentemente do que você quer que ele empacote no APK, configure outra sinalização abiFilters no bloco defaultConfig.externalNativeBuild.cmake (ou o bloco defaultConfig.externalNativeBuild.ndkBuild) (links em inglês). O Gradle compila essas configurações de ABI, mas só empacota as especificadas no bloco defaultConfig.ndk (link em inglês).

Para reduzir ainda mais o tamanho do APK, é possível configurar vários APKs baseados em ABIs. Em vez de criar um único APK grande com todas as versões das bibliotecas nativas, o Gradle cria um APK separado para cada ABI compatível e empacota apenas os arquivos necessários para cada ABI. Se você configurar vários APKs por ABI sem especificar a sinalização abiFilters, conforme mostrado na amostra de código acima, o Gradle compilará todas as versões de ABI compatíveis das bibliotecas nativas, mas empacotará somente aquelas especificadas na configuração de vários APKs. Para evitar a compilação de versões das bibliotecas nativas indesejadas, informe a mesma lista de ABIs para a sinalização abiFilters e para sua configuração de vários APKs por ABI.