Aracılığıyla paylaş


Java Bağlamaları Meta Verileri

Önemli

Şu anda Xamarin platformunda özel bağlama kullanımını araştırıyoruz. Gelecekteki geliştirme çalışmalarını bilgilendirmek için lütfen bu ankete katılın.

Xamarin.Android'deki C# kodu, Java Yerel Arabirimi'nde (JNI) belirtilen alt düzey ayrıntıları soyutlayan bir mekanizma olan bağlamalar aracılığıyla Java kitaplıklarını çağırır. Xamarin.Android, bu bağlamaları oluşturan bir araç sağlar. Bu araç, geliştiricinin meta verileri kullanarak bağlamanın nasıl oluşturulduğunu denetlemesine olanak tanır ve bu da ad alanlarını değiştirme ve üyeleri yeniden adlandırma gibi yordamlara olanak tanır. Bu belgede meta verilerin nasıl çalıştığı açıklanır, meta verilerin desteklediği öznitelikler özetlenir ve bu meta verileri değiştirerek bağlama sorunlarının nasıl çözüleceğini açıklar.

Genel bakış

Xamarin.Android Java Bağlama Kitaplığı, bazen Bağlama Oluşturucu olarak da bilinen bir aracın yardımıyla mevcut bir Android kitaplığını bağlamak için gereken işlerin çoğunu otomatikleştirmeye çalışır. Bir Java kitaplığını bağlarken, Xamarin.Android Java sınıflarını inceler ve bağlanacak tüm paketlerin, türlerin ve üyelerin listesini oluşturur. Bu API listesi, BIR RELEASE derlemesi için {project directory}\obj\Release\api.xml konumunda ve DEBUG derlemesi için {project directory}\obj\Debug\api.xml konumunda bulunan bir XML dosyasında depolanır.

obj/Debug klasöründeki api.xml dosyasının konumu

Bağlama Oluşturucu gerekli C# sarmalayıcı sınıflarını oluşturmak için bir kılavuz olarak api.xml dosyasını kullanır. Bu XML dosyasının içeriği, Google'ın Android Açık Kaynak Proje biçiminin bir çeşitlemesidir. Aşağıdaki kod parçacığı, api.xml içeriğinin bir örneğidir:

<api>
    <package name="android">
        <class abstract="false" deprecated="not deprecated" extends="java.lang.Object"
            extends-generic-aware="java.lang.Object" 
            final="true" 
            name="Manifest" 
            static="false" 
            visibility="public">
            <constructor deprecated="not deprecated" final="false"
                name="Manifest" static="false" type="android.Manifest"
                visibility="public">
            </constructor>
        </class>
...
</api>

Bu örnekte, api.xml adlı Manifest pakette android öğesini genişleten java.lang.Objectbir sınıf bildirir.

Çoğu durumda Java API'sinin daha ".NET gibi" hissetmesini sağlamak veya bağlama derlemesinin derlenmesini engelleyen sorunları düzeltmek için insan yardımı gerekir. Örneğin, Java paket adlarını .NET ad alanları olarak değiştirmek, sınıfı yeniden adlandırmak veya bir yöntemin dönüş türünü değiştirmek gerekebilir.

Bu değişiklikler, api.xml doğrudan değiştirilerek elde edilmiyor. Bunun yerine, değişiklikler Java Bağlama Kitaplığı şablonu tarafından sağlanan özel XML dosyalarına kaydedilir. Xamarin.Android bağlama derlemesi derlenirken bağlama derlemesi oluşturulurken Bağlama Oluşturucu bu eşleme dosyalarından etkilenir

Bu XML eşleme dosyaları projenin Dönüşümler klasöründe bulunabilir:

  • MetaData.xml : Oluşturulan bağlamanın ad alanını değiştirme gibi son API'de değişiklik yapılmasına izin verir.

  • EnumFields.xml – Java int sabitleri ile C# enums arasındaki eşlemeyi içerir.

  • EnumMethods.xml – Yöntem parametrelerinin değiştirilmesine ve Java int sabitlerinden dönüş türlerinin C# enums olarak değiştirilmesine izin verir.

MetaData.xml dosyası, bağlamada genel amaçlı değişikliklere izin verdiğinden bu dosyaların en çok içeri aktarılmasını sağlar:

  • Ad alanlarını, sınıfları, yöntemleri veya alanları yeniden adlandırarak .NET kurallarını izlemelerini sağlar.

  • Gerekli olmayan ad alanlarını, sınıfları, yöntemleri veya alanları kaldırma.

  • Sınıfları farklı ad alanlarına taşıma.

  • Bağlamanın tasarımını yapmak için ek destek sınıfları eklemek .NET framework desenlerini izler.

Metadata.xml daha ayrıntılı olarak tartışmak için ilerleyin.

Dönüştürme Dosyasını Metadata.xml

Daha önce öğrendiğimiz gibi dosya Metadata.xml bağlama derlemesinin oluşturulmasını etkilemek için Bağlama Oluşturucu tarafından kullanılır. Meta veri biçimi XPath söz dizimini kullanır ve GAPI Meta Verileri kılavuzunda açıklanan GAPI Meta Verileri ile neredeyse aynıdır. Bu uygulama, XPath 1.0'ın neredeyse eksiksiz bir uygulamasıdır ve bu nedenle 1.0 standardında öğeleri destekler. Bu dosya, API dosyasındaki herhangi bir öğeyi veya özniteliği değiştirmek, eklemek, gizlemek veya taşımak için güçlü bir XPath tabanlı mekanizmadır. Meta veri belirtimindeki tüm kural öğeleri, kuralın uygulanacağı düğümü tanımlamak için bir yol özniteliği içerir. Kurallar aşağıdaki sırayla uygulanır:

  • add-node : Path özniteliği tarafından belirtilen düğüme bir alt düğüm ekler.
  • attr : path özniteliği tarafından belirtilen öğenin özniteliğinin değerini ayarlar.
  • remove-node – Belirtilen XPath ile eşleşen düğümleri kaldırır.

Aşağıda bir Metadata.xml dosyası örneği verilmiştir:

<metadata>
    <!-- Normalize the namespace for .NET -->
    <attr path="/api/package[@name='com.evernote.android.job']" 
        name="managedName">Evernote.AndroidJob</attr>

    <!-- Don't  need these packages for the Xamarin binding/public API --> 
    <remove-node path="/api/package[@name='com.evernote.android.job.v14']" />
    <remove-node path="/api/package[@name='com.evernote.android.job.v21']" />

    <!-- Change a parameter name from the generic p0 to a more meaningful one. -->
    <attr path="/api/package[@name='com.evernote.android.job']/class[@name='JobManager']/method[@name='forceApi']/parameter[@name='p0']" 
        name="name">api</attr>
</metadata>

Aşağıda Java API'leri için daha yaygın olarak kullanılan XPath öğelerinden bazıları listelenmiştir:

  • interface – Java arabirimini bulmak için kullanılır. Örneğin: /interface[@name='AuthListener'].

  • class – Sınıfını bulmak için kullanılır. Örneğin: /class[@name='MapView'].

  • method – Java sınıfı veya arabiriminde bir yöntemi bulmak için kullanılır. Örneğin: /class[@name='MapView']/method[@name='setTitleSource'].

  • parameter – Bir yöntemin parametresini tanımlayın. ör. /parameter[@name='p0']

Tür Ekleme

öğesi, add-node Xamarin.Android bağlama projesine api.xml yeni bir sarmalayıcı sınıfı eklemesini söyler. Örneğin, aşağıdaki kod parçacığı Bağlama Oluşturucu'ya oluşturucu ve tek bir alan içeren bir sınıf oluşturmaya yönlendirir:

<add-node path="/api/package[@name='org.alljoyn.bus']">
    <class abstract="false" deprecated="not deprecated" final="false" name="AuthListener.AuthRequest" static="true" visibility="public" extends="java.lang.Object">
        <constructor deprecated="not deprecated" final="false" name="AuthListener.AuthRequest" static="false" type="org.alljoyn.bus.AuthListener.AuthRequest" visibility="public" />
        <field name="p0" type="org.alljoyn.bus.AuthListener.Credentials" />
    </class>
</add-node>

Türler Kaldırılıyor

Xamarin.Android Bağlama oluşturucusunun java türünü yoksaymasını ve bağlamamasını bildirmek mümkündür. Bu, metadata.xml dosyasına bir remove-node XML öğesi eklenerek yapılır:

<remove-node path="/api/package[@name='{package_name}']/class[@name='{name}']" />

Üyeleri Yeniden Adlandırma

Xamarin.Android için özgün Java Yerel Arabirimi (JNI) adları gerektiğinden üyeleri yeniden adlandırma işlemi doğrudan api.xml dosyası düzenlenerek yapılamaz. Bu nedenle, //class/@name özniteliği değiştirilemez; değiştiriliyorsa bağlama çalışmaz.

türünü android.Manifestyeniden adlandırmak istediğimiz durumu düşünün. Bunu başarmak için api.xml doğrudan düzenlemeyi ve sınıfı şu şekilde yeniden adlandırmayı deneyebiliriz:

<attr path="/api/package[@name='android']/class[@name='Manifest']" 
    name="name">NewName</attr>

Bu, Bağlama Oluşturucusunun sarmalayıcı sınıfı için aşağıdaki C# kodunu oluşturmasını sağlar:

[Register ("android/NewName")]
public class NewName : Java.Lang.Object { ... }

Sarmalayıcı sınıfının olarak yeniden adlandırıldığını NewName, özgün Java türünün ise hala Manifestolduğuna dikkat edin. Xamarin.Android bağlama sınıfının üzerindeki android.Manifestherhangi bir yönteme erişmesi artık mümkün değildir; sarmalayıcı sınıfı mevcut olmayan bir Java türüne bağlıdır.

Sarmalanan bir türün (veya yöntemin) yönetilen adını düzgün bir şekilde değiştirmek için, özniteliğinin managedName bu örnekte gösterildiği gibi ayarlanması gerekir:

<attr path="/api/package[@name='android']/class[@name='Manifest']" 
    name="managedName">NewName</attr>

Sarmalayıcı Sınıflarını EventArg Yeniden Adlandırma

Xamarin.Android bağlama oluşturucu bir dinleyici türü için bir onXXX ayarlayıcı yöntemi tanımladığında, Java tabanlı dinleyici deseni için .NET aromalı API'sini desteklemek üzere bir C# olayı ve EventArgs alt sınıfı oluşturulur. Örneğin, aşağıdaki Java sınıfını ve yöntemini göz önünde bulundurun:

com.someapp.android.mpa.guidance.NavigationManager.on2DSignNextManuever(NextManueverListener listener);

Xamarin.Android, setter yönteminden ön eki on bırakır ve bunun yerine alt sınıfın EventArgs adı için temel olarak kullanır2DSignNextManuever. Alt sınıf şuna benzer bir adla adlandırılır:

NavigationManager.2DSignNextManueverEventArgs

Bu yasal bir C# sınıf adı değildir. Bu sorunu düzeltmek için bağlama yazarının özniteliğini argsType kullanması ve alt sınıf için EventArgs geçerli bir C# adı sağlaması gerekir:

<attr path="/api/package[@name='com.someapp.android.mpa.guidance']/
    interface[@name='NavigationManager.Listener']/
    method[@name='on2DSignNextManeuver']" 
    name="argsType">NavigationManager.TwoDSignNextManueverEventArgs</attr>

Desteklenen Öznitelikler

Aşağıdaki bölümlerde Java API'lerini dönüştürmeye yönelik bazı öznitelikler açıklanmaktadır.

argsType

Bu öznitelik, Java dinleyicilerini desteklemek için oluşturulacak alt sınıfı adlandırmak EventArg için ayarlayıcı yöntemlerine yerleştirilir. Bu, bu kılavuzun devamında yer alan EventArg Sarmalayıcı Sınıflarını Yeniden Adlandırma bölümünde aşağıda daha ayrıntılı olarak açıklanmıştır.

eventName

Bir olay için bir ad belirtir. Boşsa, olay oluşturmayı engeller. Bu, EventArg Sarmalayıcı Sınıflarını Yeniden Adlandırma başlıklı bölümde daha ayrıntılı olarak açıklanmıştır.

managedName

Bu, bir paketin, sınıfın, yöntemin veya parametrenin adını değiştirmek için kullanılır. Örneğin, Java sınıfının MyClass adını olarak değiştirmek için NewClassName:

<attr path="/api/package[@name='com.my.application']/class[@name='MyClass']" 
    name="managedName">NewClassName</attr>

Sonraki örnekte yönteminin java.lang.object.toString Java.Lang.Object.NewManagedNameolarak yeniden adlandırılması için bir XPath ifadesi gösterilmektedir:

<attr path="/api/package[@name='java.lang']/class[@name='Object']/method[@name='toString']" 
    name="managedName">NewMethodName</attr>

managedType

managedType bir yöntemin dönüş türünü değiştirmek için kullanılır. Bazı durumlarda Bağlama Oluşturucu bir Java yönteminin dönüş türünü yanlış çıkarsar ve bu da derleme zamanı hatasına neden olur. Bu durumda olası çözümlerden biri yöntemin dönüş türünü değiştirmektir.

Örneğin Bağlama Oluşturucu, Java yönteminin de.neom.neoreadersdk.resolution.compareTo() bir int döndürüp parametre olarak alması Object gerektiğine inanıyor ve bu da Hata CS0535: 'DE hata iletisiyle sonuçlanır. Neom.Neoreadersdk.Resolution', 'Java.Lang.IComparable.CompareTo(Java.Lang.Object)' arabirim üyesini uygulamaz. Aşağıdaki kod parçacığı, oluşturulan C# yönteminin ilk parametresinin türünü bir DE.Neom.Neoreadersdk.Resolution Java.Lang.Objectolarak değiştirme işlemini gösterir:

<attr path="/api/package[@name='de.neom.neoreadersdk']/
    class[@name='Resolution']/
    method[@name='compareTo' and count(parameter)=1 and
    parameter[1][@type='de.neom.neoreadersdk.Resolution']]/
    parameter[1]" name="managedType">Java.Lang.Object</attr> 

managedReturn

Bir yöntemin dönüş türünü değiştirir. Bu, dönüş özniteliğini değiştirmez (dönüş özniteliklerindeki değişiklikler JNI imzasında uyumsuz değişikliklere neden olabileceğinden). Aşağıdaki örnekte yöntemin append dönüş türü olarak değiştirilmiştir SpannableStringBuilder IAppendable (C# öğesinin kovarant dönüş türlerini desteklemediğini hatırlayın):

<attr path="/api/package[@name='android.text']/
    class[@name='SpannableStringBuilder']/
    method[@name='append']" 
    name="managedReturn">Java.Lang.IAppendable</attr>

Karartılmış

Java kitaplıklarını gizleyen araçlar, Xamarin.Android Bağlama Oluşturucu'ya ve C# sarmalayıcı sınıfları oluşturma yeteneğine engel olabilir. Karartılmış sınıfların özellikleri şunlardır:

  • Sınıf adı bir $içerir; örneğin , a$.class
  • Sınıf adı, küçük harf karakterlerinden (örneğin, a.class) tamamen tehlikeye girer

Bu kod parçacığı, "belirsiz" bir C# türü oluşturmaya yönelik bir örnektir:

<attr path="/api/package[@name='{package_name}']/class[@name='{name}']" 
    name="obfuscated">false</attr>

propertyName

Bu öznitelik, yönetilen özelliğin adını değiştirmek için kullanılabilir.

Özel bir kullanım propertyName örneği, Java sınıfının bir alan için yalnızca bir getter yöntemine sahip olduğu durumu içerir. Bu durumda Bağlama Oluşturucu, .NET'te önerilmez olan bir salt yazma özelliği oluşturmak isteyebilir. Aşağıdaki kod parçacığı, öğesini boş bir dizeye ayarlayarak propertyName .NET özelliklerinin nasıl "kaldırılacağını" gösterir:

<attr path="/api/package[@name='org.java_websocket.handshake']/class[@name='HandshakeImpl1Client']/method[@name='setResourceDescriptor' 
    and count(parameter)=1 
    and parameter[1][@type='java.lang.String']]" 
    name="propertyName"></attr>
<attr path="/api/package[@name='org.java_websocket.handshake']/class[@name='HandshakeImpl1Client']/method[@name='getResourceDescriptor' 
    and count(parameter)=0]" 
    name="propertyName"></attr>

Ayarlayıcı ve getter yöntemlerinin Bağlama Oluşturucu tarafından oluşturulmaya devam edeceğine dikkat edin.

gönderen

Yöntem bir olaya eşlendiğinde bir yöntemin hangi parametresinin parametre olması sender gerektiğini belirtir. Değer veya falseolabilirtrue. Örneğin:

<attr path="/api/package[@name='android.app']/
    interface[@name='TimePickerDialog.OnTimeSetListener']/
    method[@name='onTimeSet']/
    parameter[@name='view']" 
    name="sender">true</ attr>

görünürlük

Bu öznitelik bir sınıfın, yöntemin veya özelliğin görünürlüğünü değiştirmek için kullanılır. Örneğin, karşılık gelen C# sarmalayıcısının publicolması için bir protected Java yöntemini yükseltmek gerekebilir:

<!-- Change the visibility of a class -->
<attr path="/api/package[@name='namespace']/class[@name='ClassName']" name="visibility">public</attr>

<!-- Change the visibility of a method --> 
<attr path="/api/package[@name='namespace']/class[@name='ClassName']/method[@name='MethodName']" name="visibility">public</attr>

EnumFields.xml ve EnumMethods.xml

Android kitaplıklarının, kitaplıkların özelliklerine veya yöntemlerine geçirilen durumları temsil etmek için tamsayı sabitleri kullandığı durumlar vardır. Çoğu durumda, bu tamsayı sabitlerini C# içindeki sabitlere bağlamak yararlıdır. Bu eşlemeyi kolaylaştırmak için bağlama projenizdeki EnumFields.xml ve EnumMethods.xml dosyalarını kullanın.

EnumFields.xml kullanarak Sabit Listesi tanımlama

EnumFields.xml dosyası Java int sabitleri ile C# enumsarasındaki eşlemeyi içerir. Bir dizi sabit için oluşturulan C# sabit listesi örneğini int alalım:

<mapping jni-class="com/skobbler/ngx/map/realreach/SKRealReachSettings" clr-enum-type="Skobbler.Ngx.Map.RealReach.SKMeasurementUnit">
    <field jni-name="UNIT_SECOND" clr-name="Second" value="0" />
    <field jni-name="UNIT_METER" clr-name="Meter" value="1" />
    <field jni-name="UNIT_MILIWATT_HOURS" clr-name="MilliwattHour" value="2" />
</mapping>

Burada Java sınıfını SKRealReachSettings aldık ve ad alanında Skobbler.Ngx.Map.RealReachadlı SKMeasurementUnit bir C# sabit listesi tanımladık. Girdiler field , Java sabitinin adını (örnek UNIT_SECOND), numaralandırma girdisinin adını (örnek Second) ve her iki varlık tarafından temsil edilen tamsayı değerini (örnek 0) tanımlar.

EnumMethods.xml kullanarak Getter/Setter Yöntemlerini Tanımlama

EnumMethods.xml dosyası, yöntem parametrelerinin değiştirilmesine ve Java int sabitlerinden dönüş türlerinin C# enumsolarak değiştirilmesine olanak tanır. Başka bir deyişle, C# sabit listelerinin (EnumFields.xml dosyasında tanımlanan) okunmasını ve yazmasını Java int sabiti get ve set yöntemleriyle eşler.

SKRealReachSettings Yukarıda tanımlanan sabit listesi göz önüne alındığında, aşağıdaki EnumMethods.xml dosyası bu sabit listesi için getter/setter öğesini tanımlar:

<mapping jni-class="com/skobbler/ngx/map/realreach/SKRealReachSettings">
    <method jni-name="getMeasurementUnit" parameter="return" clr-enum-type="Skobbler.Ngx.Map.RealReach.SKMeasurementUnit" />
    <method jni-name="setMeasurementUnit" parameter="measurementUnit" clr-enum-type="Skobbler.Ngx.Map.RealReach.SKMeasurementUnit" />
</mapping>

İlk method satır, Java getMeasurementUnit yönteminin dönüş değerini sabit listesiyle SKMeasurementUnit eşler. İkinci method satır, öğesinin ilk parametresini setMeasurementUnit aynı sabit listesiyle eşler.

Tüm bu değişiklikler gerçekleştiğinde, Xamarin.Android'de aşağıdaki kodu kullanarak öğesini ayarlayabilirsiniz MeasurementUnit:

realReachSettings.MeasurementUnit = SKMeasurementUnit.Second;

Özet

Bu makalede, Xamarin.Android'in Api tanımını Google AOSP biçiminden dönüştürmek için meta verileri nasıl kullandığı açıklandı. Metadata.xml kullanarak mümkün olan değişiklikleri ele aldıktan sonra, üyeleri yeniden adlandırırken karşılaşılan sınırlamaları inceledi ve desteklenen XML özniteliklerinin listesini sundu ve her özniteliğin ne zaman kullanılması gerektiğini anlattı.