In diesem Leitfaden wird die Verwendung des Wrappers der Android API-Bibliothek beschrieben. Bibliothek Wrapper-Befehlszeilentool generiert Wrapper-Code in C-Sprache für Java Android APIs, mit denen Sie Java-Bibliotheken in native C/C++ Android-Apps integrieren können. Weitere Informationen zum Bibliotheks-Wrapper finden Sie unter Bibliotheks-Wrapper für Android APIs
In dieser detaillierten Anleitung wird gezeigt, wie Sie mit dem Wrapper-Tool ein
Java-Bibliothek in eine native Android-App einbinden. In diesem Leitfaden geht es beispielsweise um
Integrieren der Benachrichtigungsbibliothek des Pakets androidx.core.app
.
Weitere Informationen zu dieser Bibliothek findest du unter Benachrichtigung erstellen.
Voraussetzungen
In diesem Leitfaden wird davon ausgegangen, dass Sie bereits ein natives Android-Projekt haben. Außerdem verwendet das Gradle-Build-System. Wenn Sie noch kein Projekt haben, erstellen Sie ein in Android Studio mit der Vorlage Native C++ ein.
Für den Beispielcode in diesem Leitfaden wird der Verzeichnisstamm my_project/
verwendet. Nativ
Code befindet sich in my_project/app/src/main/cpp/
, dem Standardverzeichnis für
Android Studio-Projekte
Wenn Sie das Bibliotheks-Wrapper-Tool noch nicht haben, laden Sie die Datei herunter und entpacken Sie sie. -Paket in das Verzeichnis Ihrer Wahl. Dieses CLI-Tool erfordert die Java-Laufzeit Umgebung (JRE):
Nativen Code generieren
Verwenden Sie bei der Integration einer Java-Bibliothek das Wrapper-Tool, um einen nativen Code-Wrapper zu generieren. Der erste Schritt besteht darin, den Wrapper zu konfigurieren.
Wrapper-Konfiguration erstellen
Sie erstellen Bibliotheks-Wrapper-Konfigurationsdateien, um die Ausgabe des nativen Codegenerators. Mit einer Funktion dieser Datei können Sie die Klassen und Methoden zum Generieren von Wrapper-Code.
Da es nicht viele Zusammenfassungsmethoden für die Benachrichtigungsbibliothek gibt, können Sie
definieren Sie sie direkt im Abschnitt custom_classes
. Erstellen Sie ein neues
config.json
an einer beliebigen Stelle in Ihrem Projekt, um die Methoden zu definieren. Beispiel:
können Sie my_project/library_wrapper/config.json
erstellen und Folgendes einfügen:
Beispielkonfiguration:
{
"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)"
]
}
]
}
Im vorherigen Beispiel deklarieren Sie direkt die Java-Klassen und -Methoden, die der native Wrapper-Code erforderlich ist.
Bibliotheks-Wrapper ausführen
Nachdem Sie die Wrapper-Konfigurationsdatei definiert haben, können Sie das Tool verwenden, um des nativen Wrapper-Codes. Terminal öffnen, in das Sie den Bibliotheks-Wrapper extrahiert haben und führen Sie den folgenden Befehl aus:
java -jar lw.jar \
-o "my_project/app/src/main/cpp/native_wrappers" \
-c "my_project/library_wrapper/config.json"
Im vorherigen Beispiel verwenden Sie den Parameter -c
, um den Wrapper anzugeben.
Konfigurationsspeicherort und den Parameter -o
, um das generierte Codeverzeichnis zu definieren.
Nachdem Sie das Tool ausgeführt haben, sollten Sie über den generierten Code verfügen, der zum Aufrufen der
Java-basierte Notifications API aus deiner nativen App.
Native Benachrichtigungen implementieren
In diesem Abschnitt binden Sie die Android-Benachrichtigungsbibliothek in Ihr
nativen App mithilfe des generierten Wrapper-Codes. Der erste Schritt besteht darin,
Die Ressource vom Typ gradle.build
auf App-Ebene (my_project/app/gradle.build
) des Projekts.
gradle.build
aktualisieren
GNI ist eine Supportbibliothek, die für den generierten Wrapper-Code erforderlich ist. Alle Projekte mit generierten Code sollten auf diese Bibliothek verweisen. Um auf diese Bibliothek zu verweisen, Fügen Sie die folgende Zeile in den Abschnitt
dependencies
vonbuild.gradle
ein:implementation 'com.google.android.gms:play-services-gni-native-c:1.0.0-beta2'
Fügen Sie dem Abschnitt
android
den folgenden Code hinzu, um die Unterstützung von prefab zu aktivieren:buildFeatures { prefab true }
Verwenden Sie zum Konfigurieren von
cmake
die folgendecmake
-Konfiguration im Abschnittandroid/defaultConfig
:externalNativeBuild { cmake { arguments '-DANDROID_STL=c++_shared' } }
Die fertige build.gradle
-Konfiguration sollte in etwa so aussehen:
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'
...
}
CMakeLists
ändern
Fügen Sie die GNI-Bibliothek zur Datei
CMakeLists.txt
Ihres Projekts hinzu. (my_project/app/src/main/cpp/CMakeLists.txt
) durch Hinzufügen der folgenden Zeile unter auf der obersten Ebene der Datei:find_package(com.google.android.gms.gni.c REQUIRED CONFIG)
Fügen Sie dem Abschnitt
target_link_libraries
die folgende Zeile hinzu:PUBLIC com.google.android.gms.gni.c::gni_shared
Fügen Sie dem generierten Code einen Verweis hinzu, indem Sie die folgende Zeile am auf der obersten Ebene der Datei:
file(GLOB_RECURSE native_wrappers CONFIGURE_DEPENDS "native_wrappers/*.cpp" "native_wrappers/*.cc")
Fügen Sie am Ende der Datei die folgenden Zeilen hinzu:
include_directories(./native_wrappers/c) include_directories(./native_wrappers/cpp)
Die aktualisierte CMakeLists.txt
-Ressource sollte in etwa so aussehen:
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)
Benachrichtigungslogik implementieren
Öffnen oder erstellen Sie die Quelldatei, in der Sie die Benachrichtigung implementieren möchten. Funktionen. Fügen Sie in diese Datei die Headerdatei
gni.h
ein und definieren Sie neueShowNativeNotification()
-Funktion:#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); }
Benachrichtigungsspezifische konstante Werte und die Benachrichtigung Handler-Funktionen
CharSequenceFromCString()
undCreateNotification()
: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; }
Einige Funktionen der Benachrichtigungsbibliothek verwenden
CharSequence
anstelle vonString
. Die FunktionCharSequenceFromCString()
ermöglicht die Konvertierung zwischen für diese Objekte. Die FunktionCreateNotification()
verwendet die umschlossene Version von JavaNotificationCompat.Builder
zum Erstellen einer Benachrichtigung.Fügen Sie Logik zum Erstellen eines Benachrichtigungskanals hinzu, indem Sie Folgendes einfügen:
CreateNotificationChannel()
-Funktion: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(¬ification_manager_as_object); NotificationManager::destroy(notification_manager); }
Aktualisieren Sie die zuvor erstellte Funktion
ShowNativeNotification()
auf Rufen SieCreateNotificationChannel()
an. Fügen Sie den folgenden Code am Ende derShowNativeNotification()
: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(¬ification); NotificationManagerCompat::destroy(¬ification_manager); }
Wenn Ihre Logik definiert ist, lösen Sie eine Benachrichtigung aus, indem Sie folgenden Befehl aufrufen:
ShowNativeNotification()
an einem geeigneten Speicherort in Ihrem Projekt.
App ausführen
Kompilieren Sie den Code und führen Sie ihn aus, der ShowNativeNotification()
aufruft. Eine einfache
sollte oben auf dem Bildschirm des Testgeräts eine entsprechende Benachrichtigung angezeigt werden.
Wrapper aus JARs generieren
Im vorherigen Beispiel haben Sie manuell Java-Klassen und Methoden, die nativen Code in einer Wrapper-Konfigurationsdatei erfordern. Für Szenarien, in denen auf große Abschnitte einer API zugreifen müssen, ist es effizienter, weitere Bibliotheks-JARs zum Wrapper-Tool hinzu. Der Wrapper generiert dann Wrapper für alle öffentlichen Symbole, die sie in der JAR-Datei finden.
Im folgenden Beispiel wird die gesamte Notifications API zusammengefasst, indem eine Bibliothek bereitgestellt wird. JAR-Datei.
Erforderliche JARs abrufen
Die Notification API ist Teil des androidx.core
-Pakets, das über
Das Google Maven-Repository. Laden Sie die aar-Datei der Bibliothek herunter und entpacken Sie sie in
ein Verzeichnis Ihrer Wahl. Suchen Sie die Datei classes.jar
.
Die Datei classes.jar
enthält neben den erforderlichen Benachrichtigungen noch viele weitere Klassen.
Bibliothek. Wenn Sie den Bibliotheks-Wrapper nur mit classes.jar
bereitstellen, wird das Tool
generiert nativen Code für jede Klasse in der JAR-Datei, was ineffizient ist und
für unser Projekt unnötig sind. Um dieses Problem zu lösen, stellen Sie dem
Wrapper-Konfiguration zur Beschränkung der Codegenerierung auf die JAR-Benachrichtigung
Klassen.
Zulassungsfilter definieren
Filterdateien sind Nur-Text-Dateien, die Sie im Bibliotheks-Wrapper bereitstellen. Konfiguration. Sie ermöglichen es, zu definieren, welche Klassen ein- oder ausgeschlossen werden sollen. aus JAR-Dateien, die an den Bibliotheks-Wrapper bereitgestellt werden.
Erstellen Sie in Ihrem Projekt eine Datei mit dem Namen allowed-symbols.txt
und fügen Sie den
folgende Zeile:
androidx.core.app.NotificationCompat*
Bei Verwendung als Zulassungsfilter gibt der vorherige Code an, dass nur Symbole
deren Namen mit androidx.core.app.NotificationCompat
beginnen, sind umschlossen.
Bibliotheks-Wrapper ausführen
Öffnen Sie ein Terminal für das JAR-Verzeichnis und führen Sie den folgenden Befehl aus:
java -jar lw.jar \
-i classes.jar \
-o "./generated-jar" \
-c "./config.json" \
-fa allowed-symbols.txt \
--skip_deprecated_symbols
Mit dem vorherigen Beispielbefehl wird Wrapper-Code für Ihre gefilterten Klassen generiert
in das Verzeichnis generated-jar/
.
Support
Wenn Sie ein Problem mit dem Bibliotheks-Wrapper feststellen, teilen Sie uns dies bitte mit.
In Programmfehlern suchen | Fehler melden |
---|---|
Technik | bug_report |
Dokumentation | bug_report |