Kitaplık sarmalayıcı kılavuzu

Bu kılavuzda, Android API kitaplığı sarmalayıcının nasıl kullanılacağı açıklanmaktadır. Kitaplık sarmalayıcı komut satırı aracı, Java Android API'leri için C dili sarmalayıcı kodu oluşturarak Java kitaplıklarını yerel C/C++ Android uygulamalarına entegre etmenizi sağlar. Kitaplık sarmalayıcı hakkında daha fazla bilgi için Android API'leri için kitaplık sarmalayıcı bölümüne bakın.

Bu adım adım açıklamalı kılavuzda, Java kitaplığını yerel bir Android uygulamasına entegre etmek için sarmalayıcı aracının nasıl kullanılacağı gösterilmektedir. Örneğin, bu kılavuzda androidx.core.app paketinin bildirim kitaplığının entegre edilmesi ele alınmaktadır. Bu kitaplık hakkında daha fazla bilgi edinmek için Bildirim Oluşturma başlıklı makaleye bakın.

Ön koşullar

Bu kılavuzda, mevcut bir yerel Android projenizin olduğu varsayılmaktadır. Ayrıca Gradle derleme sistemini de kullanır. Mevcut bir projeniz yoksa Yerel C++ şablonunu kullanarak Android Studio'da yeni bir proje oluşturun.

Bu kılavuzdaki örnek kod my_project/ dizin kökünü kullanır. Yerel kod, Android Studio projeleri için varsayılan dizin olan my_project/app/src/main/cpp/ konumunda bulunur.

Kitaplık sarmalayıcı aracına sahip değilseniz paketi indirin ve istediğiniz dizine giden sıkıştırmasını açın. Bu CLI aracı için Java Runtime Ortamı (JRE) gerekir.

Yerel kod oluşturun

Java kitaplığı entegre ederken yerel kod sarmalayıcı oluşturmak için sarmalayıcı aracını kullanın. İlk adım, sarmalayıcıyı yapılandırmaktır.

Sarmalayıcı yapılandırmasını oluşturma

Yerel kod oluşturma aracının çıkışını kontrol etmek için kitaplık sarmalayıcı yapılandırma dosyaları oluşturursunuz. Bu dosyanın bir özelliği, sarmalayıcı kodu oluşturmak için sınıfları ve yöntemleri belirtmenize olanak tanır.

Bildirim kitaplığı için sarmalama yapılacak çok fazla yöntem olmadığından, bunları doğrudan custom_classes bölümünde tanımlayabilirsiniz. Yöntemleri tanımlamak için projenizin herhangi bir yerinde yeni bir config.json kaynağı oluşturun. Örneğin, my_project/library_wrapper/config.json oluşturup aşağıdaki örnek yapılandırmayı yapıştırabilirsiniz:

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

Önceki örnekte, yerel sarmalayıcı kodu gerektiren Java sınıflarını ve yöntemlerini doğrudan bildiriyorsunuz.

Kitaplık sarmalayıcıyı çalıştırma

Sarmalayıcı yapılandırma dosyanız tanımlanmışsa, yerel sarmalayıcı kodu oluşturmak için aracı kullanmaya hazırsınız demektir. Kitaplık sarmalayıcıyı çıkardığınız bir terminal penceresi açın ve aşağıdaki komutu çalıştırın:

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

Önceki örnekte, sarmalayıcı yapılandırma konumunuzu belirtmek için -c parametresini ve oluşturulan kod dizinini tanımlamak için -o parametresini kullanırsınız. Aracı çalıştırdıktan sonra, yerel uygulamanızdan Java tabanlı Notifications API'yi çağırmak için gereken kodu elde etmiş olmanız gerekir.

Yerel bildirimleri uygulayın

Bu bölümde, oluşturulan sarmalayıcı kodunuzu kullanarak Android bildirim kitaplığını yerel uygulamanıza entegre edeceksiniz. İlk adım, projenizin uygulama düzeyindeki gradle.build kaynağını (my_project/app/gradle.build) güncellemektir.

gradle.build uygulamasını güncelle

  1. GNI, oluşturulan sarmalayıcı kodunun gerektirdiği bir destek kitaplığıdır. Oluşturulan kod kullanan tüm projeler bu kitaplığa başvurmalıdır. Bu kitaplığa referans vermek için aşağıdaki satırı build.gradle öğesinin dependencies bölümüne ekleyin:

    implementation 'com.google.android.gms:play-services-gni-native-c:1.0.0-beta2'
    
  2. Prefab desteğini etkinleştirmek için aşağıdaki kodu android bölümüne ekleyin:

    buildFeatures {
      prefab true
    }
    
  3. cmake hizmetini yapılandırmak için android/defaultConfig bölümünde aşağıdaki cmake yapılandırmasını kullanın:

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

Tamamlanmış build.gradle yapılandırmanız aşağıdakine benzer şekilde görünmelidir:

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 öğesini değiştir

  1. Dosyanın en üst seviyesine aşağıdaki satırı ekleyerek GNI kitaplığını projenizin CMakeLists.txt (my_project/app/src/main/cpp/CMakeLists.txt) bölümüne ekleyin:

    find_package(com.google.android.gms.gni.c REQUIRED CONFIG)
    
  2. Aşağıdaki satırı target_link_libraries bölümüne ekleyin:

    PUBLIC com.google.android.gms.gni.c::gni_shared
    
  3. Aşağıdaki satırı dosyanın üst düzeyine ekleyerek oluşturulan koda bir referans ekleyin:

    file(GLOB_RECURSE native_wrappers CONFIGURE_DEPENDS "native_wrappers/*.cpp" "native_wrappers/*.cc")
    
  4. Dosyanın sonuna şu satırları ekleyin:

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

Güncellenen CMakeLists.txt kaynağınız şu örneğe benzeyecektir:

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)

Bildirim mantığını uygulayın

  1. Bildirim özelliklerini uygulamak istediğiniz kaynak dosyayı açın veya oluşturun. Bu dosyaya gni.h başlık dosyasını ekleyin ve yeni bir ShowNativeNotification() işlevi tanımlayın:

    #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. Bildirime özgü sabit değerleri ve bildirim işleyici işlevleri olan CharSequenceFromCString() ve CreateNotification() tanımlayın:

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

    Bildirim kitaplığının bazı işlevleri, String yerine CharSequence öğesini kullanır. CharSequenceFromCString() işlevi, bu nesneler arasında dönüştürme işlemi sağlar. CreateNotification() işlevi, bildirim oluşturmak için Java'nın NotificationCompat.Builder sarmalanmış sürümünü kullanır.

  3. Aşağıdaki işleve (CreateNotificationChannel()) yapıştırarak bildirim kanalı oluşturma mantığını ekleyin:

    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. Daha önce oluşturduğunuz ShowNativeNotification() işlevini CreateNotificationChannel() çağırmak için güncelleyin. ShowNativeNotification() öğesinin sonuna aşağıdaki kodu ekleyin:

    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. Mantığınız tanımlandıktan sonra, projenizde uygun bir konuma ShowNativeNotification() çağrısı yaparak bir bildirimi tetikleyin.

Uygulamayı çalıştırma

ShowNativeNotification() kodunu çağıran kodu derleyip çalıştırın. Test cihazınızın ekranının üst kısmında basit bir bildirim görünür.

JAR'lerden sarmalayıcı oluşturma

Önceki örnekte, sarmalayıcı yapılandırma dosyasında yerel kod gerektiren Java sınıflarını ve yöntemlerini manuel olarak tanımlamıştınız. Bir API'nin büyük bölümlerine erişiminizin gerektiği senaryolarda sarmalayıcı aracına bir veya daha fazla kitaplık JAR'si sağlamak daha etkilidir. Sarmalayıcı daha sonra JAR'de bulduğu tüm genel semboller için sarmalayıcılar oluşturur.

Aşağıdaki örnekte, bir kitaplık JAR sağlayarak Notifications API'nin tamamı sarmalanmıştır.

Gerekli JAR'leri alın

Notification API, Google Maven deposunda bulunan androidx.core paketinin bir parçasıdır. Kitaplık aar dosyasını indirin ve paketinden istediğiniz bir dizine açın. classes.jar dosyasını bulun.

classes.jar dosyası, gerekli bildirim kitaplığımızın dışında birçok sınıf içerir. Kitaplık sarmalayıcıya yalnızca classes.jar sağlarsanız araç, JAR'deki her sınıf için yerel kod oluşturur. Bu, projemiz için verimsiz ve gereksizdir. Bu sorunu çözmek için, kod oluşturmayı JAR'ın bildirim sınıflarıyla kısıtlamak üzere sarmalayıcı yapılandırmasına bir filtre dosyası sağlayın.

İzin verme filtresi tanımlama

Filtre dosyaları, kitaplık sarmalayıcı yapılandırmanıza sağladığınız düz metin dosyalarıdır. Bunlar, kitaplık sarmalayıcıya sağlanan JAR dosyalarına dahil edilecek (veya hariç tutulacak) sınıfları tanımlamanıza olanak tanır.

Projenizde allowed-symbols.txt adlı bir dosya oluşturun ve aşağıdaki satıra yapıştırın:

androidx.core.app.NotificationCompat*

İzin verme filtresi olarak kullanıldığında, önceki kod yalnızca adı androidx.core.app.NotificationCompat ile başlayan simgelerin sarmalandığını belirtir.

Kitaplık sarmalayıcıyı çalıştırma

JAR dizinine giden bir terminal penceresi açın ve aşağıdaki komutu çalıştırın:

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

Yukarıdaki örnek komut, filtrelenen sınıflarınız için generated-jar/ dizininde sarmalayıcı kodu oluşturur.

Destek

Kitaplık sarmalayıcıyla ilgili bir sorun tespit ederseniz lütfen bize bildirin.

Hatalara göz at Hata bildir
Mühendislik
Dokümanlar