Xamarin.Android之绑定库教程

下面是我收集的常用的错误代码,绑定的时候,不只是错误需要处理,警告也是尽可能处理,不然会出现很多类丢失的情况

必备工具:

1.JD-GUI 能直接查看jar包里面的类结构

  很多情况下,需要知道一个文件到底是类还是接口,才能写Metadata.xml文件

 

 

1.Class is not abstract and does not override abstract method

接口中存在泛型T,generator会将T自动转换成Java.Lang.Object类型,而子类实现的,并不是该类型,必须将子类的类型转换成Java.Lang.Object

 

<attr path="/api/package[@name='org.vudroid.core.events']/class[@name='BringUpZoomControlsEvent']/method[@name='dispatchSafely' and count(parameter)=1 and parameter[1][@type='org.vudroid.core.events.BringUpZoomControlsListener']]/parameter[1]" name="managedType">
    Java.Lang.Object
</attr>

在Thread中说后面还要移除上面的节点(参数类型还是之前的),好像是generator并未移除之前的方法,但在实际操作过程中报错

 

目前还是不行,后面会报错,无法将Listener转化为java.lang.Object

 

最新方法:

     将接口中的抽象方法移除

 

 

2.missing class error was raised while reflecting setBehindCanvasTransformer [public void com.slidingmenu.lib.SlidingMenu.setBehindCanvasTransformer(com.slidingmenu.lib.SlidingMenu$CanvasTransformer)]

查看实际的代码,发现是将接口写在类中,

而官方文档

classes and interfaces whose name only consists of lower case letters, numbers, or the $ as obfuscated

Generator会将这些类剔除掉

解释说,绑定生成器对那些名称只包含小写字母,数字或者$的类或者接口剔除掉

 

解决办法:

 1.如果有源码,将接口单独写在一个文件中,并将引用的地方修改

 2.如果没有源码,将类中的接口移除,添加一个新的接口<add-node>,并将相应引用的地方的类型变为新的接口的类型

 3.(未确定)name="obfuscated">false</attr>

 

 

3.errorCS0102:

 The type `Com.Google.Ads.Mediation.DismissScreenEventArgs' already contains a definition for `p0'

原因一:

类同时继承两个具有相同抽象方法的接口

// Java:

public interface MediationBannerListener {

    void onDismissScreen(MediationBannerAdapter p0);

}

public interface MediationInterstitialListener {

    void onDismissScreen(MediationInterstitialAdapter p0);

}

 

解决办法:一般情况下是继承了系统的接口,但是有自动生成了与接口具有相同名称的属性,导致冲突,这种情况下直接修改系统接口的属性名称可以起到一劳永逸的作用

在接口或者接口方法上添加argcType属性

add a argsTypeattribute on either of the interfaces or the interface's method

<attr path="/api/package[@name='com.google.ads.mediation']

        interface[@name='MediationBannerListener']/method[@name='onDismissScreen']"

        name="argsType">BannerDismissScreenEventArgs</attr>

 <attr path="/api/package[@name='com.google.ads.mediation']

        interface[@name='MediationInterstitialListener']/method[@name='onDismissScreen']"

        name="argsType">IntersitionalDismissScreenEventArgs</attr>

 <attr path="/api/package[@name='android.content']

        interface[@name='DialogInterface.OnClickListener']"

        name="argsType">DialogClickEventArgs</attr>

 

 

 

原因二:在Listener中,有同名的两个方法,但实际生成的EventArgs是一个,导致EventArgs的属性添加了两次,生成的Event也是两个完全一样的

解决办法就是将Listener的其中一个方法,使用argsType将该方法单独生成一个不同名的EventArgs(解决第一个错误)

Listener的其中一个方法,使用managedName的名称改变(解决后一个错误)

 

4.Class does not implement interface method

This is a problem that occurs with binding Java methods with covariant return types. In this example, the method Oauth.Signpost.Http.IHttpRequest.UnWrap() needs to returnJava.Lang.Object. However, the methodOauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap() has a return type ofHttpURLConnection.

就是接口方法返回的是java.lang.object,但是子类实现时返回的是更具体的类型

 

解决办法(两种):

1).Add a partial class declaration for HttpURLConnectionRequestAdapter and explicitly implement IHttpRequest.Unwrap():

在 Additions文件夹里面添加partial类,添加一个符合的方法

namespace Oauth.Signpost.Basic {

    partial class HttpURLConnectionRequestAdapter {

        Java.Lang.Object OauthSignpost.Http.IHttpRequest.Unwrap() {

            return Unwrap();

        }

    }

}

 

2).Remove the covariance from the generated C# code. This involves adding the following transform toTransforms\Metadata.xml which will cause the generated C# code to have a return type of Java.Lang.Object:

使用Metadata.xml将子类的返回值改为Java.Lang.Object

<attr    path="/api/package[@name='oauth.signpost.basic']/class[@name='HttpURLConnectionRequestAdapter']/method[@name='unwrap']" name="managedReturn">Java.Lang.Object</attr>

 

 

5.Warning J2XA001: missing class error was raised while reflecting de.neom.neoreadersdk.Viewfinder14View$AdView [public de.neom.neoreadersdk.Viewfinder14View$AdView(de.neom.neoreadersdk.Viewfinder14View,android.content.Context)] : de/neom/neoreadersdk/R

This problem is caused by a limitation in the bindings generator.

See also: https://bugzilla.xamarin.com/show_bug.cgi?id=18154#c7

The workaround is to add the skipped XML nodes by hand. Note that

this workaround does _not_ stop the warnings from appearing in

the build output, but it _does_ make the methods available in the

final C# binding. -->

内部类,实际的情况是依旧会生成该类(还是为内部类),但是只有一个构造函数

protected Check (IntPtr javaReference, JniHandleOwnership transfer);

也就是说无法使用该类

<add-node path="/api/package[@name='com.gc.materialdesign.views']/class[@name='CheckBox.Check']">
    <constructor deprecated="not deprecated" final="false" name="CheckBox.Check" static="false" type="com.gc.materialdesign.views.CheckBox.Check" visibility="public">
<!--        <parameter name="checkBox" type="com.gc.materialdesign.views.CheckBox" />-->
        <parameter name="context" type="android.content.Context" />
    </constructor>
</add-node>

添加上面的node,Check类会出现一个新的构造函数

Java:

public Check(Context context) {....}\

C#:

   [Register (".ctor", "(Lcom/gc/materialdesign/views/CheckBox;Landroid/content/Context;)V", "")]
            public Check (CheckBox __self, Context context);

 

但在实际大的处理中,发现Generator会自动添加一个参数(Check类所在的类),也就是第一个参数无需添加(报错显示的是两个参数).

 

 

6.Warning J2XA005: missing class error was raised while reflecting setOnhideListener[public void com.gc.materialdesign.widgets.SnackBar.setOnhideListener(com.gc.materialdesign.widgets.SnackBar$OnHideListener)] : com/gc/materialdesign/R (J2XA005)

 

> 1>JARTOXML : warning J2XA005: missing class error was raised while reflecting setOnRefreshListener [public void com.costum.android.widget.PullToRefreshListView.setOnRefreshListener(com.costum.android.widget.PullToRefreshListView$OnRefreshListener)] : com/android/widget/R

Rephrased, our "jar2xml" program (what generates api.xml) wanted the com.android.widget.R type while processing the setOnRefreshListener() method, and the com.android.widget.R type doesn't exist (it's generated later).

I think this is a variation on: https://bugzilla.xamarin.com/show_bug.cgi?id=15885

Which isn't entirely gratifying...

You should be able to workaround this by editing Transforms\Metadata.xml, and adding the following (ugly) XML fragment:

        <add-node path="/api/package[@name='com.costum.android.widget']/class[@name='PullToRefreshListView']">
                <method name="setOnRefreshListener" return="void" abstract="false" native="false" synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" >
                        <parameter name="listener" type="com.costum.android.widget.PullToRefreshListView.OnRefreshListener"/>
                </method>
        </add-node>

The above "manually" declares the setOnRefreshListener() method on the PullToRefreshListView type, and should allow the generator to bind the setOnRefreshListener() method.

 

dll中的表现:

丢失setOnRefreshListener(IOnRefreshListener listener)方法

注意:修改成功后警告依旧不变,但类中已经添加了该方法

 

//最终报错

no non-static method "Lcom/gc/materialdesign/views/CheckBox;.setOnCheckListener(Lcom/gc/materialdesign/views/CheckBox$OnCheckListener;)V"

 

 

 

7.Error CS0066:

    `IO.Vov.Vitamio.MediaPlayer.HWRenderFailed': event must be of a delegate type (CS0066) (Vitamio)

<attr path="/api/package[@name='io.vov.vitamio']/class[@name='MediaPlayer.EventHandler']" name="managedName">MediaPlayerEventHandler</attr>

 

 

 

8.Error CS0111: A member `SomeMethodName' is already defined. Rename this member or use different parameter types (CS0111)

Due to limited Java generics support (http://docs.xamarin.com/guides/android/advanced_topics/limitations/#Partial_Java_Generics_Support)

 

 

9.CS1721  cannot have multiple base classes

BaseColumns is an unusual interface because all it does is define 2 string constants. It includes no methods (http://developer.android.com/reference/android/provider/BaseColumns.html). Since C# interfaces cannot contain fields, BaseColumns is instead bound as an abstract class. As it turns out, the Clover SDK never uses BaseColumns as a method argument type or return type, so you can just remove BaseColumns from the list of implemented interfaces:

<remove-node path="/api/package[@name='com.clover.sdk.v1.printer']/class[@name='ReceiptRegistrationContract.Registration']/implements[@name='android.provider.BaseColumns']" />

In fact, since the library contain other classes with this same problem, you can instead remove this node for all of the classes that include it:

<remove-node path="/api/package/class/implements[@name='android.provider.BaseColumns']" />

See also:

[1] http://mono-for-android.1047100.n5.nabble.com/Trouble-with-Android-Provider-BaseColumns-tp5712046p5712052.html

[2] http://docs.xamarin.com/guides/android/advanced_topics/api_design/#Interfaces

 

 

 

10.Error CS0234: The type or namespace name INativePlayerNotificationCallback' does not exist in the namespaceCom.Spotify.Sdk.Android.Player'. Are you missing an assembly reference?

 

通过观察可以发现,该类的修饰符为默认(也就是前面没有public),只需要修改visibility即可

<attr path="/api/package[@name='com.spotify.sdk.android.player']/interface[@name='NativePlayerNotificationCallback']" name="visibility">public</attr>

 

11.Error 1 'Com.Devsmart.Android.UI.HorizontalListView' does not implement inherited abstract member 'Android.Widget.AdapterView.RawAdapter.set'

This has been filed as bug 11279. The workaround is to add a file to your binding project with the following contents:

using Android.Runtime;namespace Com.Devsmart.Android.UI {   partial class HorizontalListView {    protected override Java.Lang.Object RawAdapter {      get {return Adapter.JavaCast<Java.Lang.Object>();}      set {Adapter = value.JavaCast<global::Android.Widget.IListAdapter>();}    }  }}

Change the namespace and type name as appropriate to fix other binding projects.

 

http://forums.xamarin.com/discussion/2443/getting-error-with-java-binding-project

 

 

12.Error CS0535: “Com.Baidu.Nplatform.Comapi.Map.ItemizedOverlay”不实现接口成员“Java.Util.IComparator.Compare(Java.Lang.Object, Java.Lang.Object)” (CS0535) (BaiduMapBinding)

不必修改原来的Compare,直接添加一个参数类型为Java..Lang.object的即可(添加类或者使用add-node)

  <add-nodepath="/api/package/class[implements[@name='java.lang.Comparable']]">    <method name="compareTo" return="int" abstract="false" native="false"synchronized="false" static="false" final="false" deprecated="not deprecated"visibility="public">      <parameter name="o" type="java.lang.Object" />    </method>  </add-node>  <add-nodepath="/api/package/class[implements[@name='java.util.Comparator']]">    <method name="compare" return="int" abstract="false" native="false"synchronized="false" static="false" final="false" deprecated="not deprecated"visibility="public">      <parameter name="o1" type="java.lang.Object" />      <parameter name="o2" type="java.lang.Object" />    </method>  </add-node>

这样会将所有实现该接口的类或接口都改变,很可能会报错

 

13.Error CS0507: 'MySample.Start()': cannot change access modifiers when overriding 'protected' inherited member 'Urho.Application.Start()' (CS0507) (Test1)

将方法的public改为protected

 

14.Error CS0534: `Com.APNS.ServiceStringRequest' does not implement inherited abstract member `Android.OS.AsyncTask.DoInBackground(params Java.Lang.Object[])' (CS0534) (ApnsLib

The quick way to fix that is to just provide it in a custom partial class definition:

 

namespace Com.APNS {

    partial class ServiceStringRequest {

        protected override Java.Lang.Object DoInBackground (params Java.Lang.Object[] @params)

        {

            // Do something...

        }

    }}

 

 

The "better" answer is a question: if the com.APNS.ServiceStringRequest type provides the doInBackground()method, what is the API XML description for the doInBackground method? Perhaps it has the "wrong" visibility to be considered as an override? See e.g. obj\Debug\api.xml.

 

<method abstract="false" deprecated="not deprecated" final="false" name="doInBackground" native="false" return="java.lang.String" static="false" synchronized="false" visibility="protected"><parameter name="p0" type="org.apache.http.message.BasicNameValuePair..."></parameter></method>

 

15.Warning BG8102: Class Com.Umeng.Message.Local.UmengLocalNotificationService has unknown base type android.app.IntentService. (BG8102) (UmengMessage_v2.7)

 

<attr path="/api/package[@name='com.radiusnetworks.ibeacon']/class[@name='IBeaconIntentProcessor' and @extends='android.app.IntentService']" name="extends">mono.android.app.IntentService</attr>

 

posted @ 2016-08-28 11:36  做一个清醒者  阅读(1654)  评论(0编辑  收藏  举报