Guida al wrapper libreria

Questa guida descrive come utilizzare il wrapper della libreria API Android. La biblioteca lo strumento a riga di comando wrapper genera un codice wrapper C-lingua per Java Android che ti consentono di integrare librerie Java nelle app per Android C/C++ native. Per maggiori dettagli sul wrapper libreria, consulta Wrapper libreria per le API Android.

Questa guida passo passo illustra come utilizzare lo strumento wrapper per integrare una libreria Java in un'app Android nativa. Ad esempio, questa guida tratta integrando la libreria di notifica del pacchetto androidx.core.app. Per scoprire di più su questa raccolta, consulta l'articolo Create a Notification (Crea una notifica).

Prerequisiti

Questa guida presuppone che tu abbia un progetto Android nativo esistente. Inoltre, utilizza il sistema di compilazione Gradle. Se non hai già un progetto, crea un una nuova in Android Studio utilizzando il modello C++ nativo.

Il codice di esempio in questa guida utilizza la directory radice my_project/. Nativi si trova in my_project/app/src/main/cpp/, la directory predefinita progetti Android Studio.

Se non hai ancora lo strumento per il wrapper libreria, scarica e decomprimi nella directory che preferisci. Questo strumento di interfaccia a riga di comando richiede il runtime Java Ambiente (JRE).

Genera codice nativo

Durante l'integrazione di una libreria Java, utilizza lo strumento wrapper generare un wrapper di codice nativo. Il primo passaggio prevede la configurazione del wrapper.

Crea la configurazione del wrapper

Devi creare file di configurazione del wrapper libreria per controllare dell'output del generatore di codice nativo. Una funzionalità di questo file ti consente di specificare le classi e i metodi per generare il codice wrapper.

Poiché non sono disponibili molti metodi per il wrapping della raccolta delle notifiche, puoi puoi definirli direttamente nella sezione custom_classes. Crea un nuovo elemento config.json risorsa in qualsiasi punto del progetto per definire i metodi. Ad esempio: puoi creare my_project/library_wrapper/config.json e incollare quanto segue configurazione di esempio:

{
  "custom_classes": [
    {
      "class_name": "class java.lang.CharSequence"
    },
    {
      "class_name": "class java.lang.Object",
      "methods": [
        "java.lang.String toString()"
      ]
    },
    {
      "class_name": "class java.lang.String"
    },
    {
      "class_name": "class android.content.Context",
      "methods": [
        "java.lang.Object getSystemService(java.lang.String name)"
      ]
    },
    {
      "class_name": "class android.app.Notification"
    },
    {
      "class_name": "class android.app.NotificationManager",
      "methods": [
        "void createNotificationChannel(android.app.NotificationChannel channel)"
      ]
    },
    {
      "class_name": "class android.app.NotificationChannel",
      "methods": [
        "NotificationChannel(java.lang.String id, java.lang.CharSequence name, int importance)",
        "void setDescription(java.lang.String description)"
      ]
    },
    {
      "class_name": "class androidx.core.app.NotificationCompat"
    },
    {
      "class_name": "class androidx.core.app.NotificationCompat$Builder",
      "methods": [
        "Builder(android.content.Context context, java.lang.String channelId)",
        "androidx.core.app.NotificationCompat$Builder setContentText(java.lang.CharSequence text)",
        "androidx.core.app.NotificationCompat$Builder setContentTitle(java.lang.CharSequence title)",
        "androidx.core.app.NotificationCompat$Builder setSmallIcon(int icon)",
        "androidx.core.app.NotificationCompat$Builder setPriority(int pri)",
        "android.app.Notification build()"
      ]
    },
    {
      "class_name": "class androidx.core.app.NotificationManagerCompat",
      "methods": [
        "static androidx.core.app.NotificationManagerCompat from(android.content.Context context)",
        "void notify(int id, android.app.Notification notification)"
      ]
    }
  ]
}

Nell'esempio precedente, dichiari direttamente le classi e i metodi Java che richiedono un codice wrapper nativo.

Esegui il wrapper libreria

Una volta definito il file di configurazione del wrapper puoi utilizzare lo strumento per generare il codice wrapper nativo. Apri un terminale da cui hai estratto il wrapper della libreria ed esegui questo comando:

java -jar lw.jar \
  -o "my_project/app/src/main/cpp/native_wrappers" \
  -c "my_project/library_wrapper/config.json"

Nell'esempio precedente, utilizzi il parametro -c per specificare il wrapper della configurazione e il parametro -o per definire la directory del codice generata. Dopo aver eseguito lo strumento, dovresti avere il codice generato necessario per chiamare la funzione L'API di notifica basata su Java dalla tua app nativa.

Implementare le notifiche native

In questa sezione, integri la libreria delle notifiche di Android nel tuo utilizzando il codice wrapper generato. Il primo passaggio consiste nell'aggiornare risorsa gradle.build a livello di app del progetto (my_project/app/gradle.build).

Aggiorna gradle.build

  1. GNI è una libreria di supporto richiesta dal codice wrapper generato. Tutti i progetti che utilizza il codice generato deve fare riferimento a questa libreria. Per fare riferimento a questa libreria, aggiungi la seguente riga alla sezione dependencies di build.gradle:

    implementation 'com.google.android.gms:play-services-gni-native-c:1.0.0-beta2'
    
  2. Per attivare il supporto prefab, aggiungi il seguente codice alla sezione android:

    buildFeatures {
      prefab true
    }
    
  3. Per configurare cmake, utilizza la seguente configurazione di cmake nel Sezione android/defaultConfig:

    externalNativeBuild {
      cmake {
          arguments '-DANDROID_STL=c++_shared'
      }
    }
    

La configurazione di build.gradle completata dovrebbe essere simile alla seguente:

android {
    ...

    buildFeatures {
        prefab true
    }

    defaultConfig {
        ...

        externalNativeBuild {
            cmake {
                arguments '-DANDROID_STL=c++_shared'
            }
        }
    }
}

dependencies {
    ...
    implementation 'com.google.android.gms:play-services-gni-native-c:1.0.0-beta2'
    ...
}

Modifica CMakeLists

  1. Aggiungi la libreria GNI a CMakeLists.txt del tuo progetto (my_project/app/src/main/cpp/CMakeLists.txt) aggiungendo la seguente riga alla al livello superiore del file:

    find_package(com.google.android.gms.gni.c REQUIRED CONFIG)
    
  2. Aggiungi la seguente riga alla sezione target_link_libraries:

    PUBLIC com.google.android.gms.gni.c::gni_shared
    
  3. Aggiungi un riferimento al codice generato aggiungendo la riga seguente alla livello superiore del file:

    file(GLOB_RECURSE native_wrappers CONFIGURE_DEPENDS "native_wrappers/*.cpp" "native_wrappers/*.cc")
    
  4. Aggiungi queste righe verso la fine del file:

    include_directories(./native_wrappers/c)
    include_directories(./native_wrappers/cpp)
    

La risorsa CMakeLists.txt aggiornata dovrebbe essere simile al seguente esempio:

cmake_minimum_required(VERSION 3.18.1)

project("my_project")

file(GLOB_RECURSE native_wrappers CONFIGURE_DEPENDS "native_wrappers/*.cpp" "native_wrappers/*.cc")

add_library(
        my_project
        SHARED
        native-lib.cpp
        ${native_wrappers}
        )

find_library(
        log-lib
        log)

find_package(com.google.android.gms.gni.c REQUIRED CONFIG)

target_link_libraries(
        my_project
        PUBLIC com.google.android.gms.gni.c::gni_shared
        ${log-lib})

include_directories(./native_wrappers/c)
include_directories(./native_wrappers/cpp)

Implementa la logica di notifica

  1. Apri o crea il file di origine in cui implementare la notifica le funzionalità di machine learning. In questo file, includi il file di intestazione gni.h e definisci un'istanza nuova funzione ShowNativeNotification():

    #include "gni/gni.h"
    
    void ShowNativeNotification(JNIEnv *env, jobject main_activity, int icon_id) {
      // Get the JavaVM from the JNIEnv.
      JavaVM *java_vm;
      env->GetJavaVM(&java_vm);
    
      // Initialize the GNI runtime. This function needs to be called before any
      // call to the generated code.
      GniCore_init(java_vm, main_activity);
    }
    
  2. Definisci i valori costanti specifici per la notifica e la notifica le funzioni di gestore CharSequenceFromCString() e CreateNotification():

    C

    const int32_t IMPORTANCE_HIGH = 4;  // NotificationManager.IMPORTANCE_HIGH
    const int32_t PRIORITY_MAX = 2;  // NotificationCompat.PRIORITY_MAX
    const int32_t NOTIFICATION_ID = 123;  // User defined notification id.
    
    // Convert a C string into CharSequence.
    CharSequence *CharSequenceFromCString(const char *text) {
       String *string = String_fromCString(text);
       // Cast String to CharSequence. In Java, a String implements CharSequence.
       CharSequence *result = GNI_CAST(CharSequence, String, string);
       // Casting creates a new object, so it needs to be destroyed as normal.
       String_destroy(string);
       return result;
    }
    
    // Create a notification.
    Notification *
    CreateNotification(Context *context, String *channel_id,
                       const char *title, const char *content,
                       int32_t icon_id) {
       // Convert C strings to CharSequence.
       CharSequence *title_chars = CharSequenceFromCString(title);
       CharSequence *content_chars = CharSequenceFromCString(content);
    
       // Create a NotificationCompat.Builder and set all required properties.
       NotificationCompat_Builder *notification_builder =
           NotificationCompat_Builder_construct(context, channel_id);
       NotificationCompat_Builder_setContentTitle(notification_builder,
                                                  title_chars);
       NotificationCompat_Builder_setContentText(notification_builder,
                                                 content_chars);
       NotificationCompat_Builder_setSmallIcon(notification_builder, icon_id);
       NotificationCompat_Builder_setPriority(notification_builder,
                                              PRIORITY_MAX);
    
       // Build a notification.
       Notification *notification =
           NotificationCompat_Builder_build(notification_builder);
    
       // Clean up allocated objects.
       NotificationCompat_Builder_destroy(notification_builder);
       CharSequence_destroy(title_chars);
       CharSequence_destroy(content_chars);
    
       return notification;
    }
    

    C++

    const int32_t IMPORTANCE_HIGH = 4;  // NotificationManager.IMPORTANCE_HIGH
    const int32_t PRIORITY_MAX = 2;  // NotificationCompat.PRIORITY_MAX
    const int32_t NOTIFICATION_ID = 123;  // User defined notification id.
    
    // Convert a C string into CharSequence.
    CharSequence *CharSequenceFromCString(const char *text) {
       String *string = String_fromCString(text);
       // Cast String to CharSequence. In Java, a String implements CharSequence.
       CharSequence *result = new CharSequence(string->GetImpl());
       // Casting creates a new object, so it needs to be destroyed as normal.
       String::destroy(string);
       return result;
    }
    
    // Create a notification.
    Notification&
    CreateNotification(Context *context, String *channel_id, const char *title,
                       const char *content, int32_t icon_id) {
       // Convert C strings to CharSequence.
       CharSequence *title_chars = CharSequenceFromCString(title);
       CharSequence *content_chars = CharSequenceFromCString(content);
    
       // Create a NotificationCompat.Builder and set all required properties.
    
       NotificationCompat::Builder *notification_builder = new NotificationCompat::Builder(*context, *channel_id);
       notification_builder->setContentTitle(*title_chars);
       notification_builder->setContentText(*content_chars);
       notification_builder->setSmallIcon(icon_id);
       notification_builder->setPriority(PRIORITY_MAX);
    
       // Build a notification.
       Notification& notification = notification_builder->build();
    
       // Clean up allocated objects.
       NotificationCompat::Builder::destroy(notification_builder);
       CharSequence::destroy(title_chars);
       CharSequence::destroy(content_chars);
    
       return notification;
    }
    

    Alcune funzioni della raccolta delle notifiche utilizzano CharSequence anziché String. La funzione CharSequenceFromCString() consente la conversione tra di questi oggetti. La funzione CreateNotification() utilizza la versione con wrapping di Java NotificationCompat.Builder per creare una notifica.

  3. Aggiungi una logica per creare un canale di notifica incollando quanto segue funzione, CreateNotificationChannel():

    C

    void CreateNotificationChannel(Context *context, String *channel_id) {
       CharSequence *channel_name = CharSequenceFromCString("channel name");
       String *channel_description = String_fromCString("channel description");
       String *system_service_name = String_fromCString("notification");
       NotificationChannel *channel =
           NotificationChannel_construct(channel_id, channel_name,
                                         IMPORTANCE_HIGH);
       NotificationChannel_setDescription(channel, channel_description);
    
       Object *notification_manager_as_object =
           Context_getSystemService(context, system_service_name);
       NotificationManager *notification_manager =
           GNI_CAST(NotificationManager, Object,
                    notification_manager_as_object);
    
       NotificationManager_createNotificationChannel(notification_manager,
                                                     channel);
    
       CharSequence_destroy(channel_name);
       String_destroy(channel_description);
       String_destroy(system_service_name);
       NotificationChannel_destroy(channel);
       Object_destroy(notification_manager_as_object);
       NotificationManager_destroy(notification_manager);
    }
    

    C++

    void CreateNotificationChannel(Context *context, String *channel_id) {
       CharSequence *channel_name = CharSequenceFromCString("channel name");
       String *channel_description = String_fromCString("channel description");
       String *system_service_name = String_fromCString("notification");
       NotificationChannel *channel =
           new NotificationChannel(*channel_id, *channel_name, IMPORTANCE_HIGH);
       channel->setDescription(*channel_description);
    
       Object& notification_manager_as_object =
           context->getSystemService(*system_service_name);
       NotificationManager *notification_manager =
           new NotificationManager(notification_manager_as_object.GetImpl());
    
       notification_manager->createNotificationChannel(*channel);
    
       CharSequence::destroy(channel_name);
       String::destroy(channel_description);
       String::destroy(system_service_name);
       NotificationChannel::destroy(channel);
       Object::destroy(&notification_manager_as_object);
       NotificationManager::destroy(notification_manager);
    }
    
  4. Aggiorna la funzione ShowNativeNotification() creata in precedenza in chiama CreateNotificationChannel(). Aggiungi il seguente codice alla fine di ShowNativeNotification():

    C

    void ShowNativeNotification(JNIEnv *env, jobject main_activity, int icon_id) {
     // ...
    
     // Create a Context object by wrapping an existing JNI reference.
     Context *context = Context_wrapJniReference(main_activity);
    
     // Create a String object.
     String *channel_id = String_fromCString("new_messages");
    
     // Create a notification channel.
     CreateNotificationChannel(context, channel_id);
    
     // Create a notification with a given title, content, and icon.
     Notification *notification =
         CreateNotification(context, channel_id, "My Native Notification",
                            "Hello!", icon_id);
    
     // Create a notification manager and use it to show the notification.
     NotificationManagerCompat *notification_manager =
         NotificationManagerCompat_from(context);
     NotificationManagerCompat_notify(notification_manager, NOTIFICATION_ID,
                                      notification);
    
     // Destroy all objects.
     Context_destroy(context);
     String_destroy(channel_id);
     Notification_destroy(notification);
     NotificationManagerCompat_destroy(notification_manager);
    }
    

    C++

    void ShowNativeNotification(JNIEnv *env, jobject main_activity, int icon_id) {
       // Get the JavaVM from the JNIEnv.
       JavaVM *java_vm;
       env->GetJavaVM(&java_vm);
    
       // Initialize the GNI runtime. This function needs to be called before any
       // call to the generated code.
       GniCore::Init(java_vm, main_activity);
    
       // Create a Context object by wrapping an existing JNI reference.
       Context *context = new Context(main_activity);
    
       // Create a String object.
       String *channel_id = String_fromCString("new_messages");
    
       // Create a notification channel.
       CreateNotificationChannel(context, channel_id);
    
       // Create a notification with a given title, content, and icon.
       Notification& notification =
           CreateNotification(context, channel_id, "My Native Notification",
                              "Hello!", icon_id);
    
       // Create a notification manager and use it to show the notification.
       NotificationManagerCompat& notification_manager =
           NotificationManagerCompat::from(*context);
       notification_manager.notify(NOTIFICATION_ID, notification);
    
       // Destroy all objects.
       Context::destroy(context);
       String::destroy(channel_id);
       Notification::destroy(&notification);
       NotificationManagerCompat::destroy(&notification_manager);
    }   
  5. Con la logica definita, attiva una notifica chiamando ShowNativeNotification() in una posizione appropriata nel tuo progetto.

Esegui l'app

Compila ed esegui il codice che chiama ShowNativeNotification(). Un semplice dovrebbe essere visualizzata nella parte superiore dello schermo del dispositivo di test.

Genera wrapper dai JAR

Nell'esempio precedente, hai definito manualmente le classi Java e che richiedono codice nativo in un file di configurazione wrapper. Per scenari in cui accedere a grandi sezioni di un'API, è più efficiente fornire uno più JAR di libreria allo strumento wrapper. Il wrapper genera quindi wrapper per tutti i simboli pubblici che trova nel JAR.

L'esempio seguente aggrega l'intera API Notifications fornendo una libreria JAR.

Recupera i JAR richiesti

L'API Notification fa parte del pacchetto androidx.core, disponibile da nel Repository Google Maven. Scarica il file aar della libreria e aprilo in una directory di tua scelta. Individua il file classes.jar.

Il file classes.jar contiene molti corsi oltre alle notifiche obbligatorie libreria. Se fornisci il wrapper libreria solo con classes.jar, lo strumento genera codice nativo per ogni classe nel file JAR, che è inefficiente inutili per il nostro progetto. Per risolvere il problema, fornisci un file di filtro alla configurazione del wrapper per limitare la generazione del codice alla notifica del JAR .

Definisci un filtro di autorizzazione

I file filtro sono file di testo normale che fornisci al wrapper della raccolta configurazione. Consentono di definire quali classi includere (o escludere) dai file JAR forniti al wrapper della libreria.

Nel tuo progetto, crea un file denominato allowed-symbols.txt e incollalo nel riga seguente:

androidx.core.app.NotificationCompat*

Quando utilizzato come filtro di autorizzazione, il codice precedente specifica che solo i simboli il cui nome inizia con androidx.core.app.NotificationCompat è aggregato.

Esegui il wrapper libreria

Apri un terminale nella directory JAR ed esegui questo comando:

java -jar lw.jar \
 -i classes.jar \
 -o "./generated-jar" \
 -c "./config.json" \
 -fa allowed-symbols.txt \
 --skip_deprecated_symbols

Il comando di esempio precedente genera il codice wrapper per le classi filtrate alla directory generated-jar/.

Assistenza

Se riscontri un problema con il wrapper della biblioteca, faccelo sapere.

Sfoglia i bug Segnala un bug
Ingegneria
Documentazione