Concepts

Avant de commencer

Ce guide suppose que vous connaissez déjà les concepts inhérents à la programmation native et au développement sur Android.

Introduction

Cette section explique brièvement le fonctionnement du NDK. Android NDK est un ensemble d'outils qui vous permet d'intégrer du code C ou C++ (code natif) dans vos applications Android. La possibilité d'utiliser du code natif dans les applications Android peut être particulièrement utile pour les développeurs qui souhaitent effectuer une ou plusieurs des actions suivantes :

  • Assurer la portabilité de leurs applications entre différentes plates-formes
  • Réutiliser des bibliothèques existantes ou fournir leurs propres bibliothèques en vue de les réutiliser
  • Améliorer les performances dans certains cas, en particulier pour les applications nécessitant d'importantes ressources de calcul comme les jeux

Fonctionnement

Cette section présente les principaux composants utilisés pour créer une application native pour Android, puis décrit le processus de compilation et de packaging.

Principaux composants

Pour créer votre application, vous devez connaître les composants suivants :

  • Bibliothèques partagées natives : le NDK crée ces bibliothèques, ou fichiers .so, à partir de votre code source C/C++.

  • Bibliothèques statiques natives : le NDK peut également créer des bibliothèques statiques, ou fichiers .a, que vous pouvez associer à d'autres bibliothèques.

  • Java Native Interface (JNI) : cette interface permet aux composants Java et C++ de communiquer entre eux. Ce guide suppose que vous connaissez JNI. Pour en savoir plus, consultez la page Java Native Interface Specification.

  • Interface binaire d'application (ABI, Application Binary Interface) : l'ABI définit précisément la manière dont le code machine de votre application est censé interagir avec le système lors de l'exécution. Le NDK crée des fichiers .so conformément à ces définitions. Différentes ABI correspondent à différentes architectures : le NDK est compatible avec les ABI destinées à ARM 32 bits, AArch64, x86 et x86-64. Pour en savoir plus, consultez ABI Android.

  • Fichier manifeste : si vous codez une application sans composant Java, vous devez déclarer la classe NativeActivity dans le fichier manifeste. Pour connaître la procédure à suivre, consultez Utiliser l'interface native_activity.h.

Procédure

La procédure générale à suivre pour développer une application native pour Android est la suivante :

  1. Concevez votre application en déterminant quelles parties créer en Java et quelles parties créer sous forme de code natif.

  2. Créez un projet d'application Android comme vous le feriez pour tout autre projet Android.

  3. Si vous codez une application entièrement native, déclarez la classe NativeActivity dans AndroidManifest.xml. Pour en savoir plus, consultez Activités et applications natives.

  4. Créez un fichier Android.mk décrivant la bibliothèque native, y compris son nom, les options, les bibliothèques associées et les fichiers sources à compiler dans le répertoire JNI.

  5. Si vous le souhaitez, vous pouvez créer un fichier Application.mk qui configure les ABI cibles, la chaîne d'outils, le mode publication/débogage et la STL. Pour celles de ces informations que vous ne spécifiez pas, les valeurs par défaut suivantes sont utilisées :

    • ABI : toutes les ABI non obsolètes
    • Mode : publication
    • STL : système
  6. Placez votre source native dans le répertoire jni du projet.

  7. Compilez les bibliothèques natives (.so et .a) à l'aide de ndk-build.

  8. Créez le composant Java générant le fichier exécutable .dex.

  9. Packagez le tout dans un fichier APK contenant les fichiers .so et .dex, ainsi que les autres fichiers nécessaires à l'exécution de votre application.

Activités et applications natives

Le SDK Android fournit une classe d'assistance, NativeActivity, qui vous permet de coder une activité entièrement native. NativeActivity gère la communication entre le framework Android et votre code natif. Vous n'avez donc pas besoin de le placer dans une sous-classe ni d'appeler ses méthodes. Il vous suffit de déclarer votre application comme native dans votre fichier AndroidManifest.xml, puis de commencer à créer votre application native.

Une application Android utilisant NativeActivity s'exécute tout de même sur sa propre machine virtuelle, dans un bac à sable qui l'isole des autres applications. Par conséquent, vous pouvez toujours accéder aux API du framework Android via JNI. Dans certains cas, par exemple pour les capteurs, les événements d'entrée et les éléments, le NDK fournit des interfaces natives que vous pouvez utiliser au lieu d'effectuer un appel via JNI. Pour plus d'informations sur ce sujet, consultez API natives.

Que vous développiez ou non une activité native, nous vous recommandons de créer vos projets avec les outils de compilation Android traditionnels. Cela permet de garantir que la compilation et le packaging des applications Android respectent la structure appropriée.

Android NDK vous propose deux options pour ajouter votre activité native :

  • L'en-tête native_activity.h définit la version native de la classe NativeActivity. Il contient l'interface de rappel et les structures de données dont vous avez besoin pour créer votre activité native. Étant donné que le thread principal de votre application gère les rappels, vos insertions de rappels ne doivent pas être bloquantes. Si elles le sont, vous pouvez recevoir des erreurs ANR (l'application ne répond pas), car votre thread principal cesse de répondre jusqu'au retour du rappel.
  • Le fichier android_native_app_glue.h définit une bibliothèque d'aide statique basée sur l'interface native_activity.h. Il génère un autre thread qui gère des tâches telles que les rappels ou les événements d'entrée dans une boucle d'événements. Le fait de déplacer ces événements vers un thread distinct empêche les rappels de bloquer le thread principal.

La source <ndk_root>/sources/android/native_app_glue/android_native_app_glue.c est également disponible, ce qui vous permet de modifier l'implémentation.

Pour en savoir plus sur l'utilisation de cette bibliothèque statique, consultez l'application exemple native-activity et sa documentation. Des informations complémentaires sont également disponibles dans les commentaires du fichier <ndk_root>/sources/android/native_app_glue/android_native_app_glue.h.

Utiliser l'interface native_activity.h

Pour ajouter une activité native avec l'interface native_activity.h :

  1. Créez un répertoire jni/ dans le répertoire racine de votre projet. Ce répertoire stocke l'ensemble de votre code natif.

  2. Déclarez votre activité native dans le fichier AndroidManifest.xml.

    Comme votre application ne contient pas de code Java, définissez android:hasCode sur false.

    <application android:label="@string/app_name" android:hasCode="false">
    

    Vous devez définir l'attribut android:name de la balise d'activité sur NativeActivity.

    <activity android:name="android.app.NativeActivity"
              android:label="@string/app_name">
    

    L'attribut android:value de la balise meta-data spécifie le nom de la bibliothèque partagée contenant le point d'entrée de l'application (par exemple, C/C++ main), en omettant le préfixe lib et le suffixe .so de ce nom.

    <manifest>
      <application>
        <activity>
          <meta-data android:name="android.app.lib_name"
                     android:value="native-activity" />
          <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
        </activity>
      </application>
    </manifest>
    
  3. Créez un fichier pour votre activité native et ajoutez la fonction nommée dans la variable ANativeActivity_onCreate. L'application appelle cette fonction lorsque l'activité native démarre. Cette fonction, semblable à main en C/C++, reçoit un pointeur vers une structure ANativeActivity qui contient des pointeurs de fonction vers les différents rappels que vous devez insérer. Définissez les pointeurs de fonction de rappel applicables dans ANativeActivity->callbacks vers vos insertions de rappels.

  4. Définissez le champ ANativeActivity->instance sur l'adresse de toute instance de données spécifiques que vous souhaitez utiliser.

  5. Ajoutez toute autre action que l'activité doit réaliser lorsqu'elle démarre.

  6. Insérez les autres rappels que vous avez définis dans ANativeActivity->callbacks. Pour en savoir plus sur le moment où les rappels sont appelés, consultez Gérer le cycle de vie d'une activité.

  7. Développez le reste de votre application.

  8. Créez un fichier Android.mk file dans le répertoire jni/ de votre projet pour décrire votre module natif au système de compilation. Pour en savoir plus, consultez Android.mk.

  9. Une fois que vous disposez d'un fichier Android.mk, compilez votre code natif à l'aide de la commande ndk-build.

    cd <path>/<to>/<project>
    $NDK/ndk-build
    
  10. Compilez et installez votre projet Android comme d'habitude. Si votre code natif se trouve dans le répertoire jni/, le script de compilation package automatiquement le ou les fichiers .so créés à partir de celui-ci dans l'APK.

Exemples de code supplémentaires

Pour télécharger des exemples de NDK, consultez Exemples de NDK.