绑定疑难解答Troubleshooting Bindings

本文汇总了生成绑定,以及可能的原因和解决这些问题的建议的方法时可能发生的多种常见错误。This article summarizes serveral common errors that may occur when generating bindings, along with possible causes and suggested ways to resolve them.

概述Overview

绑定 Android 库 ( .aar.jar) 文件很少是简单的会议时间; 它通常需要进行其他工作来缓解问题而导致的 Java 和.NET 之间的差异。Binding an Android library (an .aar or a .jar) file is seldom a straightforward affair; it usually requires additional effort to mitigate issues that result from the differences between Java and .NET. 这些问题将阻止 Xamarin.Android 绑定 Android 库和它们自身显示为生成日志中的错误消息。These issues will prevent Xamarin.Android from binding the Android library and present themselves as error messages in the build log. 本指南将提供一些提示,用于解决问题,列出了一些较为常见的问题/情景,并提供可能的解决方案成功绑定到 Android 库。This guide will provide some tips for troubleshooting the issues, list some of the more common problems/scenarios, and provide possible solutions to successfully binding the Android library.

绑定现有 Android 库时,必须要时刻牢记以下几点:When binding an existing Android library, it is necessary to keep in mind the following points:

  • 库的外部依赖关系–必须为 Xamarin.Android 项目中包含所需的 Android 库的任何 Java 依赖项ReferenceJar或是EmbeddedReferenceJarThe external dependencies for the library – Any Java dependencies required by the Android library must be included in the Xamarin.Android project as a ReferenceJar or as an EmbeddedReferenceJar.

  • Android 库所面向的 Android API 级别–它无法"降级"的 Android API 级别; 确保,Xamarin.Android 绑定项目面向的相同的 API 级别 (或更高) 为 Android 库。The Android API level that the Android library is targetting – It is not possible to "downgrade" the Android API level; ensure that the Xamarin.Android binding project is targeting the same API level (or higher) as the Android library.

  • 用于打包 Android 库的 Android jdk 版本–绑定错误可能会发生,如果使用不同版本的 JDK 比使用 xamarin.android 生成 Android 库。The version of the Android JDK that was used to package the Android library – Binding errors may occur if the Android library was built with a different version of JDK than the one in use by Xamarin.Android. 如果可能,请重新编译使用相同的 Xamarin.Android 安装使用的 jdk 版本的 Android 库。If possible, recompile the Android library using the same version of the JDK that is used by your installation of Xamarin.Android.

解决问题的绑定 Xamarin.Android 库的第一步是能够诊断 MSBuild 输出The first step to troubleshooting issues with binding a Xamarin.Android library is to enable diagnostic MSBuild output. 启用诊断输出后, 重新生成 Xamarin.Android 绑定项目并检查生成日志,以找到有关问题的原因的线索。After enabling the diagnostic output, rebuild the Xamarin.Android binding project and examine the build log to locate clues about what the cause of problem is.

它可以证明反编译 Android 库并检查的类型和 Xamarin.Android 尝试绑定的方法很有帮助。It can also prove helpful to decompile the Android library and examine the types and methods that Xamarin.Android is trying to bind. 这一点在稍后在本指南中的更多详细信息。This is covered in more detail later on in this guide.

反编译的 Android 库Decompiling an Android Library

检查的类和方法的 Java 类可以提供有价值的信息会帮助你绑定库。Inspecting the classes and methods of the Java classes can provide valuable information that will assist in binding a library. JD GUI是一个图形实用工具,可以显示从 Java 源代码JAR 中包含的文件。JD-GUI is a graphical utility that can display Java source code from the CLASS files contained in a JAR. 它可以作为独立应用程序或插件为 IntelliJ 或运行 Eclipse。It can be run as a stand alone application or as a plug-in for IntelliJ or Eclipse.

反编译一个 Android 库打开 。JAR Java 反编译器使用的文件。To decompile an Android library open the .JAR file with the Java decompiler. 如果库 。AAR文件,但有必要从中提取文件classes.jar从存档文件。If the library is an .AAR file, it is necessary to extract the file classes.jar from the archive file. 以下是使用 JD GUI 来分析的示例屏幕截图看毕加索会如何JAR:The following is a sample screenshot of using JD-GUI to analyze the Picasso JAR:

使用 Java 反编译器分析看毕加索会如何 2.5.2.jar

一旦具有反编译程序 Android 库,检查源代码。Once you have decompiled the Android library, examine the source code. 通常情况下,查找:Generally speaking, look for :

  • 具有模糊处理的特征的类–经过模糊处理类的特征包括:Classes that have characteristics of obfuscation – Characteristics of obfuscated classes include:

    • Class 名称中包含 $ ,即 $.class The class name includes a $, i.e. a$.class
    • 类名完全破坏的小写字符,即a.classThe class name is entirely compromised of lower case characters, i.e. a.class
  • import 语句未引用的库–标识未引用的库并将这些依赖项添加到 Xamarin.Android 绑定项目与生成操作ReferenceJarEmbedddedReferenceJarimport statements for unreferenced libraries – Identify the unreferenced library and add those dependencies to the Xamarin.Android binding project with a Build Action of ReferenceJar or EmbedddedReferenceJar.

备注

反编译 Java 库可能会禁止或受到法律限制的约束根据当地的法律或在其下发布 Java 库的许可证。Decompiling a Java library may be prohibited or subject to legal restrictions based on local laws or the license under which the Java library was published. 如有必要,然后再尝试反编译 Java 库和检查的源代码登记法律专业人员的服务。If necessary, enlist the services of a legal professional before attempting to decompile a Java library and inspect the source code.

检查 API。XMLInspect API.XML

生成一个绑定项目的一部分,Xamarin.Android 将生成 XML 文件名obj/Debug/api.xml:As a part of building a binding project, Xamarin.Android will generate an XML file name obj/Debug/api.xml:

在 obj / 调试下生成的 api.xml

此文件提供了 Xamarin.Android 正尝试绑定的所有 Java Api 的列表。This file provides a list of all the Java APIs that Xamarin.Android is trying bind. 此文件的内容可以帮助确定任何缺少的类型或方法,重复的绑定。The contents of this file can help identify any missing types or methods, duplicate binding. 尽管此文件进行检查是单调乏味并且耗时,但可提供用于在什么可能会导致任何绑定问题的线索。Although inspection of this file is tedious and time consuming, it can provide for clues on what might be causing any binding problems. 例如, api.xml属性返回一个不适当的类型,或有两个类型为该共享相同的托管名称可能会显示。For example, api.xml might reveal that a property is returning an inappropriate type, or that there are two types that share the same managed name.

已知问题Known Issues

本部分将列出的一些常见的错误消息或症状,我尝试绑定一个 Android 库时发生。This section will list some of the common error messages or symptoms that my occur when trying to bind an Android library.

问题:Java 版本不匹配Problem: Java Version Mismatch

有时不会生成类型或意外的故障可能是由于使用的 Java 库已与编译相比更高版本或较旧版本。Sometimes types will not be generated or unexpected crashes may occur because you are using either a newer or older version of Java compared to what the library was compiled with. 重新编译使用相同版本的 Xamarin.Android 项目使用的 JDK 的 Android 库。Recompile the Android library with the same version of the JDK that your Xamarin.Android project is using.

问题:至少一个 Java 库是必需的Problem: At least one Java library is required

您会收到错误"至少一个 Java 库是必需的"即使。已添加 JAR。You receive the error "at least one Java library is required," even though a .JAR has been added.

可能的原因:Possible Causes:

请确保生成操作设置为EmbeddedJarMake sure the build action is set to EmbeddedJar. 由于没有对应的多个生成操作。JAR 文件 (如InputJarEmbeddedJarReferenceJarEmbeddedReferenceJar),不能自动在默认情况下使用哪一个猜出绑定生成器。Since there are multiple build actions for .JAR files (such as InputJar, EmbeddedJar, ReferenceJar and EmbeddedReferenceJar), the binding generator cannot automatically guess which one to use by default. 有关生成操作的详细信息,请参阅生成操作For more information about build actions, see Build Actions.

问题:绑定工具无法加载。JAR 库Problem: Binding tools cannot load the .JAR library

绑定库生成器无法加载。JAR 库。The binding library generator fails to load the .JAR library.

可能的原因Possible Causes

一些。Java 工具不能加载使用 (通过 Proguard 等工具) 的代码混淆的 JAR 库。Some .JAR libraries that use code obfuscation (via tools such as Proguard) cannot be loaded by the Java tools. 由于我们的工具可以利用 Java 反射和工程库的 ASM 字节代码,这些从属工具可能会拒绝的经过模糊处理的库,虽然 Android 运行时工具可能会将传递。Since our tool makes use of Java reflection and the ASM byte code engineering library, those dependent tools may reject the obfuscated libraries while Android runtime tools may pass. 对此解决方法是手动绑定而不是使用绑定生成器这些库。The workaround for this is to hand-bind these libraries instead of using the binding generator.

问题:缺少C#中生成的输出类型。Problem: Missing C# types in generated output.

绑定 .dll生成,但未命中某些 Java 数据类型,或生成C#源未生成由于一个错误,指出缺少的类型。The binding .dll builds but misses some Java types, or the generated C# source does not build due to an error stating there are missing types.

可能的原因:Possible Causes:

此错误可能有多种原因,如下所示:This error may occur due to several reasons as listed below:

  • 要绑定的库可能引用第二个 Java 库。The library being bound may reference a second Java library. 如果绑定库的公共 API 使用从第二个库类型,则必须引用第二个库的托管的绑定。If the public API for the bound library uses types from the second library, you must reference a managed binding for the second library as well.

  • 有可能库被注入由于 Java 反射,类似于上面,从而导致意外的元数据加载库加载错误的原因。It is possible that a library was injected due to Java reflection, similar to the reason for the library load error above, causing the unexpected loading of metadata. Xamarin.Android 的工具当前不能解决此问题。Xamarin.Android's tooling cannot currently resolve this situation. 在这种情况下,必须手动绑定库。In such a case, the library must be manually bound.

  • 未能加载程序集时应具有的.NET 4.0 运行时中出现 bug。There was a bug in .NET 4.0 runtime that failed to load assemblies when it should have. 在.NET 4.5 运行时中已修复此问题。This issue has been fixed in the .NET 4.5 runtime.

  • Java 允许从非公共类,派生的公共类,但这在.NET 中不支持。Java allows deriving a public class from non-public class, but this is unsupported in .NET. 因为绑定生成器不生成绑定的非公共类,派生类,如这些无法正确生成。Since the binding generator does not generate bindings for non-public classes, derived classes such as these cannot be generated correctly. 若要解决此问题,请删除这些派生类使用中的删除节点的元数据条目Metadata.xml,或修复公开非公共类的元数据。To fix this, either remove the metadata entry for those derived classes using the remove-node in Metadata.xml, or fix the metadata that is making the non-public class public. 尽管后一种解决方案将创建绑定,以便C#将生成源,不应使用非公共类。Although the latter solution will create the binding so that the C# source will build, the non-public class should not be used.

    例如:For example:

    <attr path="/api/package[@name='com.some.package']/class[@name='SomeClass']"
        name="visibility">public</attr>
    
  • 模糊处理 Java 库的工具可能会影响 Xamarin.Android 绑定生成器,并生成其功能与C#包装器类。Tools that obfuscate Java libraries may interfere with the Xamarin.Android Binding Generator and its ability to generate C# wrapper classes. 以下代码片段演示如何更新Metadata.xml以 unobfuscate 类名:The following snippet shows how to update Metadata.xml to unobfuscate a class name:

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

问题:生成C#源未生成由于参数类型不匹配Problem: Generated C# source does not build due to parameter type mismatch

生成C#不生成源。The generated C# source does not build. 重写方法的参数类型不匹配。Overridden method's parameter types do not match.

可能的原因:Possible Causes:

Xamarin.Android 包含了多种映射到枚举中的 Java 字段的C#绑定。Xamarin.Android includes a variety of Java fields that are mapped to enums in the C# bindings. 这些会导致生成的绑定中的类型不兼容问题。These can cause type incompatibilities in the generated bindings. 若要解决此问题,从绑定生成器创建的方法签名需要进行修改以使用枚举。To resolve this, the method signatures created from the binding generator need to be modified to use the enums. 有关详细信息,请参阅更正枚举For more imformation, please see Correcting Enums.

问题:在包装 NoClassDefFoundErrorProblem: NoClassDefFoundError in packaging

java.lang.NoClassDefFoundError 在打包步骤中,将引发。java.lang.NoClassDefFoundError is thrown in the packaging step.

可能的原因:Possible Causes:

此错误最可能的原因是必需的 Java 库需要添加到应用程序项目 (.csproj)。The most likely reason for this error is that a mandatory Java library needs to be added to the application project (.csproj). .JAR 文件不自动解决。.JAR files are not automatically resolved. 针对目标设备或仿真程序中不存在的用户程序集始终不生成 Java 库绑定 (如 Google Maps maps.jar)。A Java library binding is not always generated against a user assembly that does not exist in the target device or emulator (such as Google Maps maps.jar). 这是与库的不用于 Android 库项目支持这种情况。在类库 dll 中嵌入 JAR。This is not the case for Android Library project support, as the library .JAR is embedded in the library dll. 例如:Bug 4288For example: Bug 4288

问题:重复的自定义 EventArgs 类型Problem: Duplicate custom EventArgs types

由于重复的自定义 EventArgs 类型,生成失败。Build fails due to duplicate custom EventArgs types. 发生如下错误:An error like this occurs:

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

可能的原因:Possible Causes:

这是因为来自多个共享具有相同名称的方法的接口"侦听器"类型的事件类型之间的某些冲突。This is because there is some conflict between event types that come from more than one interface "listener" type that shares methods having identical names. 例如,如果在下面的示例所示,有两个 Java 接口,生成器将创建DismissScreenEventArgs同时MediationBannerListenerMediationInterstitialListener,从而导致错误。For example, if there are two Java interfaces as seen in the example below, the generator creates DismissScreenEventArgs for both MediationBannerListener and MediationInterstitialListener, resulting in the error.

// Java:
public interface MediationBannerListener {
    void onDismissScreen(MediationBannerAdapter p0);
}
public interface MediationInterstitialListener {
    void onDismissScreen(MediationInterstitialAdapter p0);
}

这是特意设计,以便避免了事件自变量类型上的耗时较长名称。This is by design so that lengthy names on event argument types are avoided. 若要避免这些冲突,某些元数据转换是必需的。To avoid these conflicts, some metadata transformation is required. 编辑 Transforms\Metadata.xml ,并添加argsType接口中的任何一个 (或在接口方法) 的属性:Edit Transforms\Metadata.xml and add an argsType attribute on either of the interfaces (or on the interface 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>

问题:类未实现接口方法Problem: Class does not implement interface method

指示生成的类不实现所需的生成的类实现的接口的方法来生成一条错误消息。An error message is produced indicating that a generated class does not implement a method that is required for an interface which the generated class implements. 但是,看一下生成的代码,您可以看到此方法实现。However, looking at the generated code, you can see that the method is implemented.

下面是错误的示例:Here is an example of the error:

obj\Debug\generated\src\Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.cs(8,23):
error CS0738: 'Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter' does not
implement interface member 'Oauth.Signpost.Http.IHttpRequest.Unwrap()'.
'Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.Unwrap()' cannot implement
'Oauth.Signpost.Http.IHttpRequest.Unwrap()' because it does not have the matching
return type of 'Java.Lang.Object'

可能的原因:Possible Causes:

这是协变返回类型与绑定 Java 方法会出现一个问题。This is a problem that occurs with binding Java methods with covariant return types. 在此示例中,该方法Oauth.Signpost.Http.IHttpRequest.UnWrap()需要返回Java.Lang.ObjectIn this example, the method Oauth.Signpost.Http.IHttpRequest.UnWrap() needs to return Java.Lang.Object. 但是,该方法Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap()的返回类型为HttpURLConnectionHowever, the method Oauth.Signpost.Basic.HttpURLConnectionRequestAdapter.UnWrap() has a return type of HttpURLConnection. 有两种方法来解决此问题:There are two ways to fix this issue:

  • 添加的分部类声明HttpURLConnectionRequestAdapter和显式实现IHttpRequest.Unwrap():Add a partial class declaration for HttpURLConnectionRequestAdapter and explicitly implement IHttpRequest.Unwrap():

    namespace Oauth.Signpost.Basic {
        partial class HttpURLConnectionRequestAdapter {
            Java.Lang.Object OauthSignpost.Http.IHttpRequest.Unwrap() {
                return Unwrap();
            }
        }
    }
    
  • 从生成中删除协方差C#代码。Remove the covariance from the generated C# code. 这涉及到添加到以下转换Transforms\Metadata.xml这将导致生成C#代码的返回类型Java.Lang.Object:This involves adding the following transform to Transforms\Metadata.xml which will cause the generated C# code to have a return type of Java.Lang.Object:

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

问题:名称冲突上的内部类 / 属性Problem: Name Collisions on Inner Classes / Properties

继承的对象的冲突可见性。Conflicting visibility on inherited objects.

在 Java 中,这不被必需的派生的类具有相同的可见性作为其父级。In Java, it's not required that a derived class have the same visibility as its parent. Java 只需修复,为您。Java will just fix that for you. 在C#,具有可以明确,因此您需要确保层次结构中的所有类都有相应的可见性。In C#, that has to be explicit, so you need to make sure all classes in the hierarchy have the appropriate visibility. 下面的示例演示如何从 Java 包名称更改com.evernote.android.jobEvernote.AndroidJob:The following example shows how to change a Java package name from com.evernote.android.job to Evernote.AndroidJob:

<!-- 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>

问题:一个 .so由绑定所需的库是未加载Problem: A .so Library Required by the Binding is Not Loading

某些绑定项目还取决于中的功能 .so库。Some binding projects may also depend on functionality in a .so library. 很可能不会自动加载 Xamarin.Android .so库。It is possible that Xamarin.Android will not automatically load the .so library. Xamarin.Android 已包装的 Java 代码执行时,将无法进行 JNI 调用和错误消息_java.lang.UnsatisfiedLinkError:找不到的本机方法:_ 会在 logcat 出应用程序中显示。When the wrapped Java code executes, Xamarin.Android will fail to make the JNI call and the error message java.lang.UnsatisfiedLinkError: Native method not found: will appear in the logcat out for the application.

此解决方法是手动加载 .so库通过调用Java.Lang.JavaSystem.LoadLibraryThe fix for this is to manually load the .so library with a call to Java.Lang.JavaSystem.LoadLibrary. 例如假设 Xamarin.Android 项目已共享库libpocketsphinx_jni.so绑定项目的生成操作中包含EmbeddedNativeLibrary,以下代码片段(使用共享的库之前执行) 将加载 .so库:For example assuming that a Xamarin.Android project has shared library libpocketsphinx_jni.so included in the binding project with a build action of EmbeddedNativeLibrary, the following snippet (executed before using the shared library) will load the .so library:

Java.Lang.JavaSystem.LoadLibrary("pocketsphinx_jni");

总结Summary

在本文中,我们将列出与 Java 绑定相关联的常见故障排除问题并说明了如何解决这些问题。In this article, we listed common troubleshooting issues associated with Java Bindings and explained how to resolve them.