Android API'leri için kitaplık sarmalayıcı Android Game Development Kit'in bir parçasıdır.

Kitaplık sarmalayıcı, Java'da yazılan Android API'leri için C dili sarmalayıcısı kodu oluşturan bir komut satırı aracıdır (KSA). Yerel Android uygulamalarında bu kodu kullanarak, manuel olarak Java Yerel Arayüzü veya JNI oluşturmaya gerek kalmadan Java API'lerini çağırabilirsiniz. Bu araç, öncelikli olarak C veya C++ dilinde yazılmış Android uygulamalarının geliştirme sürecini basitleştirebilir.

Araç, sağladığınız Java Arşivi (JAR) dosyalarındaki genel simgeler veya aracın yapılandırma dosyasında tanımlanan sınıflar ya da her ikisi için C kodu oluşturarak çalışır. Araç tarafından oluşturulan kod, Java API'lerinin yerini almaz. Bunun yerine C kodunuz ile Java arasında bir köprü görevi görür. Uygulamanız için yine de sarmaladığınız Java kitaplıklarının projenize dahil edilmesi gerekir.

İndir

Kitaplık sarmalayıcı arşivini indirin ve içeriğini istediğiniz dizinde paketinden çıkarın.

Sözdizimi

Kitaplık sarmalayıcı aracında aşağıdaki komut satırı söz dizimi vardır:

java -jar lw.jar \
  [-i jar-file-to-be-wrapped] \
  [-o output-path] \
  [-c config-file] \
  [-fa allow-list-file] \
  [-fb block-list-file] \
  [--skip_deprecated_symbols]
Parametre Description
-i jar-file-to-be-wrapped JAR dosyası kullanarak C sarmalayıcı kodu oluşturabilirsiniz. Birden fazla JAR belirtilebilir. Örneğin:
-i first_library.jar -i second_library.jar...
-o output-path Oluşturulan kodun dosya sistemi konumu.
-c config-file Kitaplık sarmalayıcı yapılandırma dosyasının dosya sistemi yolu. Ayrıntılar için Yapılandırma bölümünü inceleyin.
-fa allow-list-file Aracın sarmalaması için semboller belirtebileceğiniz bir filtre dosyasının yolu. Ayrıntılar için Filtre bölümünü inceleyin.
-fb block-list-file Sarmalamadan hariç tutulan sembolleri içeren bir filtre dosyasının yolu. Ayrıntılar için Filtre bölümünü inceleyin.
--skip_deprecated_symbols Sarmalayıcı aracına @Kullanımdan kaldırıldı simgelerini atlamasını söyler.

Sarmalayıcı yapılandırma dosyası

Kitaplık sarmalayıcı yapılandırması, kod oluşturma işlemini kontrol etmenize olanak tanıyan bir JSON dosyasıdır. Dosya aşağıdaki yapıyı kullanır.

{
  // An array of type-specific configs. A type config is useful when a user wants to map
  // a Java type to a manually defined C type without generating the code. For example, when a developer
  // has their own implementation of the "java.lang.String" class, they can tell the generator to use it
  // instead of generating it.
  "type_configs": [
    {
      // [Required] Name of a fully qualified Java type.
      "java_type": "java.lang.String",
      // The C type that the java_type will be mapped to.
      "map_to": "MyOwnStringImplementation",
      // A header file that contains the declaration of the "map_to" type.
      "source_of_definition": "my_wrappers/my_own_string_implementation.h",
      // Controls if a value should be passed by pointer or value.
      "pass_by_value": false
    }
  ],
  // An array of package-specific configs.
  "package_configs": [
    {
      // [Required] A name of a Java package that this section regards. A wildchar * can be used at the
      // end of the package name to apply this config to all packages whose name starts with this value.
      "package_name": "androidx.core.app*",
      // A subdirectory relative to the root directory where the generated code will be located.
      "sub_directory": "androidx_generated/",
      // If true, the generated file structure reflects the package name. For example, files generated
      // for the package com.google.tools will be placed in the directory com/google/tools/.
      "file_location_by_package_name": true,
      // A prefix added to all class names from this package.
      "code_prefix": "Gen",
      // A prefix added to all generated file names from this package.
      "file_prefix": = "gen_"
    }
  ],
  // An array of manually defined classes for wrapping. Defining classes manually is useful when a
  // jar file with desired classes are not available or a user needs to wrap just a small part of an SDK.
  "custom_classes": [
    {
      // [Required] A fully-qualified Java class name. To define inner class, use symbol "$", for example
      // "class com.example.OuterClass$InnerClass".
      "class_name": "class java.util.ArrayList<T>",
      // List of methods.
      "methods": [
        "ArrayList()", // Example of a constructor.
        "boolean add(T e)", // Example of a method that takes a generic parameter.
        "T get(int index)", // Example of a method that returns a generic parameter.
        "int size()" // Example of parameterless method.
      ]
    },
  ]
}

Dosyaları filtrele

Sarmalamayı planladığınız JAR dosyalarından bazı simgeleri hariç tutmak faydalı olabilir. Simgeleri hariç tutmak için yapılandırmanızda bir filtre dosyası belirtebilirsiniz. Filtre dosyası, her satırın sarmalanacak bir simge tanımladığı basit bir metin dosyasıdır. Filtre dosyaları aşağıdaki söz dizimini kullanır:

java-symbol-name java-jni-type-signature

Aşağıda bir filtre dosyası örneği verilmiştir:

# Class filter
java.util.ArrayList Ljava.util.ArrayList;

# Method filter
java.util.ArrayList.lastIndexOf (Ljava.lang.Object;)I

# Field filter
android.view.KeyEvent.KEYCODE_ENTER I

-fa parametresi kullanılarak izin verilen sembolleri ve -fb parametresini kullanarak engellenen simgeleri belirten bir filtre dosyası yapılandırması sağlarsınız. Her iki parametre de aynı anda kullanılabilir. Her iki filtre de sağlanmışsa "izin ver" filtresi dosyasında tanımlanıp engelleme filtresi dosyasında yer almayan bir simge sarmalanır.

Örnek senaryo

Aşağıdaki sınıfı içeren ChatLibrary.jar JAR dosyasını sarmalamanız gerektiğini varsayalım:

public class ChatManager {
  public static void sendMessage(int userId, String message) {...}
}

C projeniz, bu JAR için yerel bir sarmalayıcı oluşturmanızı gerektirir. Böylece yerel Android uygulamanızın çalışma zamanında çağırabilmesi sağlanır. Kitaplık sarmalayıcıyı kullanıp aşağıdaki komutla bu kodu oluşturun:

java -jar lw.jar -i ChatLibrary.jar -o ./generated_code/

Yukarıdaki komut, ./generated_code dizini için C kaynak kodu oluşturur. Oluşturulan chat_manager.h dosyası aşağıdakine benzer bir kod içerir. Bu sayede projenizdeki kitaplığı çağırabilirsiniz:

#include "java/lang/string.h"

typedef struct ChatManager_ ChatManager;
void ChatManager_sendMessage(int32_t user_id, String* message);

Ayrıntılı bir örnek senaryo için Kitaplık sarmalayıcı kılavuzuna bakın.

Araç ayrıntıları

Aşağıdaki bölümlerde kitaplık sarmalayıcı işlevi hakkında ayrıntılı bilgi verilmektedir.

Çıkış dizini yapısı

Tüm C kaynak ve üst bilgi dosyaları, sarmalanmış Java sınıfının paket adını yansıtan alt dizinlerde bulunur. Örneğin, belirtilen JAR java.lang.Integer için sarmalayıcı kodu ./java/lang/integer.[h/cc] dizinine oluşturulur.

Aracın yapılandırma dosyasını kullanarak bu çıkış davranışını kontrol edebilirsiniz.

Nesne yaşam döngüsü

Java nesneleri C kodunda sarmalayıcılar adı verilen opak işaretçiler olarak gösterilir. Sarmalayıcı, karşılık gelen Java nesnesi için bir JNI referansını yönetir. Sarmalayıcı aşağıdaki senaryolarda oluşturulabilir:

  • MyClass_wrapJniReference(jobject jobj) işlevini çağırarak mevcut bir JNI referansını sarmalayarak. İşlev, sağlanan referansın sahipliğini almaz ancak kendi genel JNI referansını oluşturur.
  • Java'da kurucu çağırmaya eşdeğer yeni bir nesne oluşturarak: MyClass_construct()
  • Bir işlevden yeni bir sarmalayıcı döndürerek. Örneğin: Score* Leaderboard_getScore(Leaderboard* instance, String* leaderboard_name)

Artık kullanılmayan tüm sarmalayıcıları kaldırmanız gerekir. Bunu yapmak için özel destroy() işlevini MyClass_destroy(MyClass* instance) çağırın.

Sarmalayıcılar döndüren işlevler, sarmalayıcılar aynı Java örneğini temsil etse bile her çağrı için bunlar için yeni bir bellek ayırır.

Örneğin, Singleton.getInstance() Java yöntemi her zaman aynı örneği döndürdüğünde C tarafındaki eşdeğer işlev, aynı Java örneği için yeni bir sarmalayıcı örneği oluşturur:

Singleton* singleton_a = Singleton_getInsance();
Singleton* singleton_b = Singleton_getInsance();

// singleton_a and singleton_b are different pointers, even though they represent the same Java instance.

Başvurulmayan sınıfları işleme

Bir sınıf, sağlanan bir JAR'de bulunamadığında kitaplık içi sarmalayıcı, opak bir işaretçi ve aşağıdaki yöntemlerden oluşan temel bir uygulama oluşturur:

  • wrapJniReference()
  • getJniReference()
  • destroy()

Kod oluşturma ayrıntıları

Kitaplık sarmalayıcı, çalıştırıldığında aracı sağladığınız JAR dosyalarındaki genel sembollere göre C kodu oluşturur. Oluşturulan C kodu, sarmalanmış Java kodundan farklı olabilir. Örneğin C, OOP gibi özellikleri, genel türler, yöntemi aşırı yükleme veya diğer Java özelliklerini desteklemez.

Bu durumları yansıtan C kodu, C geliştiricilerinin beklediği kod türünden farklı olabilir. Aşağıdaki bölümlerde yer alan örnekler, aracın Java kodundan C'yi nasıl oluşturabileceğine dair bağlam sağlar. Not: Kod snippet'lerinde, aşağıdaki örnekler C/C++ ve Java kod snippet'lerini içerir. Bu snippet'lerin amacı sadece aracın her bir durum için nasıl kod oluşturduğunu göstermektir.

Sınıflar

Sınıflar, C'de opak işaretçiler olarak temsil edilir:

C/C++

typedef struct MyClass_ MyClass;

Java

public class MyClass { ... }

Opak işaretçi örneklerine sarmalayıcılar olarak başvurulur. Sarmalayıcı aracı, her sınıf için ek destek işlevleri oluşturur. Yukarıdaki örnek MyClass sınıfı için aşağıdaki işlevler oluşturulur:

// Wraps a JNI reference with MyClass. The 'jobj' must represent MyClass on the Java side.
MyClass* MyClass_wrapJniReference(jobject jobj);

// Return JNI reference associated with the 'MyClass' pointer.
jobject MyClass_getJniReference(const MyClass* object);

// Destroys the object and releases underlying JNI reference.
void MyClass_destroy(const MyClass* object);

Markalar

Genel veya varsayılan kuruculara sahip sınıflar, özel işlevler kullanılarak temsil edilir:

C/C++

MyClass* MyClass_construct(String* data);

Java

public class MyClass {
  public MyClass(String data) { ... }
}

Yöntemler

Yöntemler normal işlevler olarak temsil edilir. İşlevin adı, orijinal sınıf adını içerir. Statik olmayan örnek yöntemlerini temsil eden işlevler, ilk parametre olarak Java nesnesini temsil eden bir yapıya işaret edene sahiptir ve bunun adına işlevin çağrılır. Bu yaklaşım, this işaretçisine benzer.

C/C++

Result* MyClass_doAction(const MyClass* my_class_instance, int32_t action_id, String* data);
int32_t MyClass_doAction(int32_t a, int32_t b);

Java

public class MyClass {
  public Result doAction(int actionId, String data) { ... }
  public static int doCalculations(int a, int b) { ... }
}

Sınıf içi sınıflar

İç sınıflar normal sınıflara yakın şekilde temsil edilir ancak karşılık gelen C yapısının adı, dış sınıfların zincirleme adlarını içerir:

C/C++

typedef struct MyClass_InnerClass_ MyClass_InnerClass;

Java

public class MyClass {
  public class InnerClass {...}
}

İç sınıf yöntemleri

İç sınıf yöntemleri aşağıdaki gibi gösterilir:

C/C++

bool MyClass_InnerClass_setValue(MyClass_InnerClass* my_class_inner_class_instance, int32_t value);

Java

public class MyClass {
  public class InnerClass {
    public boolean setValue(int value) { ... }
  }
}

Genel türler

Kitaplık sarmalayıcı, genel türleri doğrudan sarmaz. Bunun yerine, araç yalnızca genel tür örnekler için sarmalayıcılar oluşturur.

Örneğin, bir API'de MyGeneric<T> sınıfı varsa ve bu sınıfın MyGeneric<Integer> ve MyGeneric<String> gibi iki örneği olduğunda bu iki örneklendirme için sarmalayıcılar oluşturulur. Diğer bir deyişle, farklı tür yapılandırmalar kullanarak MyGeneric<T> türünde yeni örnekler oluşturamazsınız. Aşağıdaki örneğe bakın:

C/C++

// result.h

typedef struct Result_Integer_ Result_Integer;
typedef struct Result_Float_ Result_Float;

Integer* Result_Integer_getResult(const Result_Integer* instance);
Float* Result_Float_getResult(const Result_Float* instance);

// data_processor.h

typedef struct DataProcessor_ DataProcessor;

Result_Integer* DataProcessor_processIntegerData(const DataProcessor* instance);
Result_Float* DataProcessor_processFloatData(constDataProcessor* instance);

Java

public class Result<T> {
  public T getResult();
}

public class DataProcessor {
  public Result<Integer> processIntegerData();
  public Result<Float> processFloatData();
}

Arayüzleri uygulama

implementInterface() yöntemini çağırarak ve her arayüz yöntemi için bir geri çağırma işlevi sağlayarak C arayüzü uygulayın. Yalnızca arayüzler bu şekilde uygulanabilir; sınıflar ve soyut sınıflar desteklenmez. Aşağıdaki örneğe bakın:

C/C++

// observer.h

typedef struct Observer_ Observer;
typedef void (*Observer_onAction1Callback)();
typedef void (*Observer_onAction2Callback)(int32_t data);

Observer* Observer_implementInterface(
Observer_onAction1Callback observer_on_action1_callback,
Observer_onAction2Callback observer_on_action2_callback);

Java

public interface Observer {
  void onAction1();
  void onAction2(int data);
}

public class Subject {
  public void registerObserver(Observer observer);
}

Kullanım örneği:

void onAction1() {
  // Handle action 1
}

void onAction2(int32_t data) {
  // Handle action 2
}

Observer* observer = Observer_implementInterface(onAction1, onAction2);
Subject_registerObserver(subject, observer);

Sınırlamalar

Kitaplık sarmalayıcı aracı beta sürümündedir. Aşağıdaki sınırlamalarla karşılaşabilirsiniz:

Desteklenmeyen Java yapıları

Kitaplık sarmalayıcı beta, aşağıdaki yapıları desteklemez:

  • Yöntem aşırı yükleme

    C dilinde, aynı ada sahip iki işlevin tanımlanmasına izin verilmez. Sınıfta yöntem aşırı yükleme kullanılıyorsa oluşturulan C kodu derlenmez. Geçici çözüm, yeterli sayıda parametreye sahip tek bir yöntem kullanmaktır. Geri kalan işlevler filtreler kullanılarak filtrelenebilir. Bu, kurucular için de geçerlidir.

  • Şablonlu yöntemler

  • static final int ve static final String dışındaki alanlar

  • Diziler

Olası ad çakışmaları

Java sınıflarının C kodunda temsil edilme şekli nedeniyle, çok nadir durumlarda ad çakışmaları olabilir. Örneğin, Foo sınıfı içindeki Foo<Bar> sınıfı ve Bar iç sınıfı, C'de aynı simgeyle temsil edilir: typedef struct Foo_Bar_ Foo_Bar;

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