Android API'leri için kitaplık sarmalayıcı Android Game Development Kit'in bir parçasıdır.
Kitaplık sarmalayıcısı, Java ile yazılmış Android API'leri için C dilinde sarmalayıcı kodu oluşturan bir komut satırı aracıdır (KSA). Bu kodu, Java Native Interface (JNI) oluşturmanıza gerek kalmadan Java API'lerini çağırmak için yerel Android uygulamalarında kullanabilirsiniz. Bu araç, öncelikle C veya C++ ile yazılmış Android uygulamalarının geliştirilmesini kolaylaştırabilir.
Araç, sağladığınız Java Arşivi (JAR) dosyalarında bulunan herkese açık semboller 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, sarmaladığınız Java kitaplıklarının projenize dahil edilmesini gerektirir.
İndir
Kitaplık sarmalayıcı arşivini indirin ve içeriğini istediğiniz dizine çıkarın.
Sözdizimi
Kitaplık sarmalayıcı aracının komut satırı söz dizimi şöyledir:
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 | Açıklama |
---|---|
-i jar-file-to-be-wrapped |
C sarmalayıcı kodu oluşturmak için kullanılan JAR dosyası. 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ılı bilgi için Yapılandırma bölümüne bakın. |
-fa allow-list-file |
Aracın sarmalayacağı sembolleri belirtebileceğiniz bir filtre dosyasının yolu. Ayrıntılar için Filtre bölümüne bakın. |
-fb block-list-file |
Sarmalamanın dışında tutulan sembolleri içeren bir filtre dosyasının yolu. Ayrıntılar için Filtrele bölümüne bakın. |
--skip_deprecated_symbols |
Sarmalayıcı araca, @Deprecated sembollerini atlaması talimatını verir. |
Sarmalayıcı yapılandırma dosyası
Kitaplık sarmalayıcı yapılandırması, kod oluşturma sürecini 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ı filtreleme
Sarmalamayı planladığınız JAR dosyalarından bazı sembolleri hariç tutmak faydalı olabilir. Sembolleri hariç tutmak için yapılandırmanızda bir filtre dosyası belirtebilirsiniz. Filtre dosyası, her satırın sarmalanacak bir sembolü tanımladığı basit bir metin dosyasıdır. Filtre dosyaları şu söz dizimini kullanır:
java-symbol-name java-jni-type-signature
Aşağıda bir örnek filtre dosyası 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
parametresi kullanılarak engellenen sembolleri belirten bir filtre dosyası yapılandırması sağlarsınız. Her iki parametre de aynı anda kullanılabilir. Her iki filtre de sağlanırsa izin verilen filtre dosyasında tanımlanan ve engellenen filtre dosyasında bulunmayan bir sembol 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 projenizde bu JAR için yerel bir sarmalayıcı oluşturmanız gerekir. Böylece yerel Android uygulamanız, çalışma zamanında bu JAR'ı çağırabilir. Aşağıdaki komutla kitaplık sarmalayıcısını kullanarak 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 dosya chat_manager.h
, aşağıdakine benzer bir kod içerir. Bu kod, projenizde kitaplığı çağırmanıza olanak tanır:
#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ısının işlevselliği hakkında ayrıntılı bilgi verilmektedir.
Çıkış dizini yapısı
Tüm C kaynak ve başlık 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]
dizininde oluşturulur.
Bu çıkış davranışını aracın yapılandırma dosyasını kullanarak kontrol edebilirsiniz.
Nesne yaşam döngüsü
Java nesneleri, C kodunda sarmalayıcı adı verilen opak işaretçiler olarak temsil edilir. Sarmalayıcı, ilgili Java nesnesi için bir JNI referansını yönetir. Sarmalayıcı aşağıdaki senaryolarda oluşturulabilir:
MyClass_wrapJniReference(jobject jobj)
işlevi çağrılarak mevcut bir JNI referansı sarmalanarak. Bu işlev, sağlanan referansın sahipliğini almaz ancak kendi genel JNI referansını oluşturur.- Java'da bir oluşturucuyu çağırmaya eşdeğer olan yeni bir nesne oluşturarak:
MyClass_construct()
- Örneğin, bir işlevden yeni bir sarmalayıcı döndürerek:
Score* Leaderboard_getScore(Leaderboard* instance, String* leaderboard_name)
Artık kullanılmayan tüm sarmalayıcıları imha etmeniz gerekir. Bunu yapmak için özel destroy()
işlevini MyClass_destroy(MyClass* instance)
çağırın.
Sarmalayıcı döndüren işlevler, sarmalayıcılar aynı Java örneğini temsil etse bile her çağrı için yeni bir bellek ayırır.
Örneğin, Java yöntemi Singleton.getInstance()
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ı yönetme
Sınıf, sağlanan JAR'da bulunamadığında kitaplık 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 araca sağladığınız JAR dosyalarındaki herkese açık sembollere dayalı C kodu oluşturur. Oluşturulan C kodu, sarmalanmış Java kodundan farklılıklar gösterebilir. Örneğin C, OOP, genel türler, yöntem aşırı yüklemesi veya diğer Java özellikleri gibi özellikleri desteklemez.
Bu durumları yansıtan oluşturulan C kodu, C geliştiricilerinin beklediği kod türünden farklı olabilir. Aşağıdaki bölümlerdeki örnekler, aracın Java kodundan nasıl C kodu oluşturabileceği hakkında bağlam bilgisi sağlar. Not: Kod snippet'lerinde, aşağıdaki örneklerde C/C++ ve Java kod snippet'leri yer almaktadır. Bu snippet'ler yalnızca aracın, her bir durumda nasıl kod oluşturduğunu göstermek amacıyla sağlanmıştır.
Sınıflar
Sınıflar, C'de opak işaretçiler olarak gösterilir:
C/C++
typedef struct MyClass_ MyClass;
Java
public class MyClass { ... }
Opak işaretçi örneklerine sarmalayıcılar olarak atıfta bulunulur. Sarmalayıcı aracı, her sınıf için ek destek işlevleri oluşturur. Yukarıdaki örnekte
class MyClass
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);
Üreticiler
Herkese açık veya varsayılan oluşturuculara 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 gösterilir. Bir işlevin adı, orijinal sınıf adını içerir. Statik olmayan örnek yöntemleri temsil eden işlevlerin ilk parametresi, işlevin çağrıldığı Java nesnesini temsil eden bir yapıya yönelik işaretçidir. 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ıflar
İç sınıflar, karşılık gelen C yapısının adı dış sınıfların zincirlenmiş adlarını içermesi dışında normal sınıflara benzer şekilde gösterilir:
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 şu şekilde 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ısı, genel türleri doğrudan sarmalamaz. Bunun yerine araç yalnızca genel tür örneklemeleri 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 varsa bu iki örnek için sarmalayıcılar oluşturulur. Bu, farklı tür yapılandırmaları kullanarak MyGeneric<T>
türünde yeni örnekler oluşturamayacağınız anlamına gelir. 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()
işlevini çağırarak ve her arayüz yöntemi için geri çağırma işlevi sağlayarak bir C arayüzü uygulayın. Bu şekilde yalnızca arayüzler 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 sürümü aşağıdaki yapıları desteklemez:
Yöntem aşırı yüklemesi
C dilinde aynı ada sahip iki işlevin bildirilmesine izin verilmez. Sınıf, yöntem aşırı yüklemesini kullanıyorsa oluşturulan C kodu derlenmez. Geçici çözüm olarak, yeterli sayıda parametre içeren tek bir yöntem kullanabilirsiniz. Kalan işlevler filtreler kullanılarak filtrelenebilir. Bu durum, oluşturucular için de geçerlidir.
Şablonlu yöntemler
static final int
vestatic final String
dışındaki alanlarDiziler
Olası ad çakışmaları
Java sınıfları C kodunda temsil edildiğinden, çok nadir durumlarda ad çakışmaları olabilir. Örneğin, bir Foo<Bar>
sınıfı ve bir Foo
sınıfının içindeki bir iç sınıf Bar
, C'de aynı sembolle gösterilir: typedef struct Foo_Bar_ Foo_Bar;
Destek
Kitaplık sarmalayıcısıyla ilgili bir sorun tespit ederseniz lütfen bize bildirin.
Hatalara göz atma | Hata bildir |
---|---|
Mühendislik | bug_report |
Belgeler | bug_report |