【问题标题】:Xamarin.Android Binding to 3rd party SDK with dependenciesXamarin.Android 绑定到具有依赖项的 3rd 方 SDK
【发布时间】:2017-04-06 19:34:52
【问题描述】:

我正在使用带有当前/最新 Xamarin 的 VS2015 Update3,并且正在尝试创建一个绑定库来包装用 Java 编写的第 3 方 SDK。我有 C#/.Net 背景,到目前为止几乎没有 Java 经验。此 SDK 依赖于其他 3 个项目,可作为 AAR 或通过 NuGet 获得。

我能够为父 AAR 创建一个绑定库,使用一些 MetaData.xml 调整来调整参数类型和返回类型并更正类访问器以满足其抽象基类,所有这些最初都阻止了生成的 C# .Net Android 绑定库来自构建。现在父绑定程序集已构建,但无法执行,因为它需要其他 3 个 AAR 依赖项。

需要依赖项(“#”是下面帖子中提到的每个依赖项的别名):

  • “2”-> com.android.support:support-v4:25.1.1
  • “3”-> com.google.android.gms:play-services-location:10.2.0
  • “4”-> com.google.android.gms:play-services-gcm:10.2.0

在这种情况下,如果我需要创建一个绑定 dll 来包装依赖于其他 3 个 AAR 的父 AAR:

我是否应该 (A) 创建 4 个绑定程序集 - 一个依赖于 Bind_AAR_2.dll、Bind_AAR_3.dll 和 Bind_AAR_4.dll 的父绑定程序集 Bind_AAR_1.dll?

或者,我是否应该 (B) 深入研究 2、3 和 4 个 AAR 文件并从每个文件中获取 JAR 文件,然后使用“EmbeddedJar”(或其他属性/设置)?

或者,看到 2、3 和 4 实际上可以通过 NuGet 获得,我是否应该 (C) 使用 NuGet 将它们引用到 Bind_AAR_1 项目中?如果我使用 NuGet 引用/包含它们,AAR 1 中的 Javacode 是否能够看到 AAR 2、3 和 4 中的代码?

我尝试了每种方法 (A)、(B) 和 (C) 的变体,但没有运气,或者结果工作导致更多工作,这让我想知道什么是最好/正确的方法这样做。

在相关主题上,使用 Metadata.xml 文件从生成的包装 API 中显式删除您不打算在 Xamarin 项目中直接使用的所有内容(类等)是否是最佳做法?似乎限制接口可能会很好,也可能会减少绑定 dll 的构建大小(可能还有构建时间)。

任何帮助将不胜感激!

柯蒂斯

================================================ =========================

2017 年 4 月 11 日 - 更新

很高兴收到@_JonDouglas 之类的意见!但是...仍然无法让这个 SDK 工作。

我已经尝试了这些方法 A、B 和 C 中的每一个,并且能够构建我的绑定项目(通过转换/MetaData.xml 完成操作)。第 3 方 SDK 被设计/记录为 Java 解决方案中的一部分/组件。根据供应商的说明文档,此解决方案会将 3 个依赖项添加到其 .gradle 文件中,从而在整个 Java 解决方案中提供对这些项目的引用。我没有 Java 历史记录,所以在这里讨论一下。

事实上,当我使用 Visual Studio 将 SDK(单独或使用这 3 种方法中的任何一种的依赖项)包装到 Xamarin Android 绑定程序集中时,SDK 在运行时会遇到 ClassNotFound 异常(由“Google Play not found. “在日志中)。从所需的 Java 依赖项中使用的类是使用类名的名称字符串以后期绑定方式创建的,如下所示: try { Class.forName("com.google.android.gms.common.GooglePlayServicesUtil");
//more code here } catch (ClassNotFoundException e) { Log.e("3rd Party SDK", "Google Play not found."); }
我如何使用上述 3 种方法中的任何一种在 Visual Studio 中构建绑定程序集以包含依赖项(1 AAR + 3 Nuget OR 1 AAR + 3 Jars in 1 binding OR 4 AARs in 4 binding using项目参考)。在运行时,SDK 似乎看不到它们。也许这是有道理的,它不会 - 在 SDK 本身中没有指向它们的 .gradle(如 csproj 文件)?

我在想我需要做的是(更接近供应商的说明)创建一个包含 .gradle 文件的 Java 解决方案,其中包括 SDK 以及 Java 项目中的 3 个依赖项,构建以创建 AAR 文件.然后,我相信我可以为生成的包含 AAR 创建一个 Xamarin 绑定程序集。然后,我会在我的解决方案中将对此绑定程序集的引用添加到我的 .Andriod 程序集并继续。

理论(尚待证明):[失败。请参阅下面的 4/12 更新。] 将 Java SDK + 其编码依赖项(在 .gradle 中显式)包装在模块/库中,然后将其包装在 Xamarin Android 绑定库中。然后我需要做的就是从这个包装模块/库中找出我需要使用(并因此公开)哪些公共方法,添加这些公共方法并将调用转发到 SDK。

大图:我正在尝试将其设计和编码为跨平台 Xamarin 解决方案,但我正在使用特定于 Android 和特定于 IOS 的 SDK,它们似乎都旨在成为应用程序/UI 体验的一部分(旨在做的不仅仅是处理与第 3 方的通信)。这个 UI 方面还没有发挥出来,因为我还没有看到任何 SDK 功能。

================================================ =========================

2017 年 4 月 12 日 - 更新

理论(失败):将 Java SDK + 其编码依赖项(在 .gradle 中显式)包装在模块/库中,然后将其包装在 Xamarin Android 绑定库中。我们对此进行了编码、构建、部署和测试。我现在看到应用程序在运行时进入了第一层 Java 代码,但找不到任何低于该层的引用代码(也称为依赖项)。包装器的代码运行良好,但包装器在运行时找不到 SDK 的类,甚至找不到我们试图通过包装器使用的简单 Java 测试组件。这相当于我们最初使用 SDK 时遇到的问题,当时我们只是为它单独创建了一个绑定文件,然后通过 JAR 或通过 NuGet 将其余部分引用到绑定程序集中。下层代码还是没有找到,只执行了第一层java。仍在尝试提出解决方案。

================================================ =========================

2017 年 4 月 13 日 - 更新

我已经取得了一些进展。正如他们所说,向前一步,也许后退两步。

我现在意识到第 3 方 SDK 需要更多的 Google Play 服务,而不仅仅是两个依赖项。我对明确提到的两个项目进行了反编译,命名类不在其中。我开始查看本地 Android SDK 位置(在 Visual Studio 中配置)并找到“play-services-6.5.87.AAR”。将它作为 EmbeddedResourceJar 包含在我的绑定程序集中最终得到了 SDK 代码,以找到上面代码中列出的特定类。

使用 NuGet

我质疑上述 Java 包装器的价值,因为依赖项所需的一切现在都包含在 EmbeddedReferenceJar 中。似乎我应该直接绑定 SDK AAR(不添加 Java 包装层)。我正在重新考虑这一点,并尝试在 JARS 文件夹中创建指向 SDK AAR 的绑定程序集,然后使用 NuGet 包含 Google Play 服务。

继续,(使用 NuGet 引用 Google Play 服务)我现在收到此错误: No resource found that matches the given name (at 'value' with value '@integer/google_play_services_version'). {project name} {project path}\AndroidManifest.xml 我已经尝试了很多不同的方法来试图摆脱这个构建时错误,但没有任何运气。

不使用 NuGet

如果我坚持使用 Google 的“play-services-6.5.87.AAR”中的 JAR 文件作为 EmbeddedResourceJar,我不会收到构建错误,但会收到 SDK 无法解决的运行时错误找到所需的 Android 清单设置。如果您有这样安排的项目,我对使用哪个 Android Manifest 是否正确? XXX PCL Project --> XXX.Android project <-- My guess is that this is where the AndroidManifest.XML file is located that will be used....? ----> XXX.Android.AARBinding project
------> JARS folder --> 3pVendorSDK.AAR

还在挖....

【问题讨论】:

    标签: c# .net xamarin xamarin.android aar


    【解决方案1】:

    我最终如何让我的第 3 方 Java SDK 与 Xamarin 一起工作:

    由于我的解决方案是跨平台,我有:

    • 程序集:MyApplication(PCL 便携式)
    • 程序集:MyApplication.Android
    • 程序集:MyApplication.Android.Binding

      (包装第 3 方 SDK,作为 AAR 文件提供)

    相应的 .IOS 项目/程序集将遵循这种命名模式,当我们开始这样做时。

    Android 绑定程序集

    • 罐子文件夹
      • 包含 My3rdParty.AAR 文件
        使用构建操作设置:“LibraryProjectZip”
    • 转换文件夹
      • Metadata.XML - 我必须调整 Visual Studio 生成绑定代码的方式,以确保类型对齐等。
      • 我有一些方法返回的类型不能很好地映射到 .Net,所以我使用 attr 元素来调整它们的 'managedType' 和 'managedReturn' 类型值。
        注意:您可以使用多个一种方法上的一个 attr 元素,可以根据需要对其进行调整。
      • 我必须删除一个声明为虚拟的方法(通过使用 remove-node 元素),并在自定义代码中重新添加它作为覆盖以满足其基类的抽象类定义。
    • 根文件夹
      • CustomCode.cs - 重新添加需要从私有更改为公共的一种方法(已通过 MetaData.xml 删除)。 (请注意,生成的方法将不起作用,因为它只是一个满足抽象类继承的空存根)

    Android 程序集

    • 清单

      • 缺乏准确/完整的 SDK 清单文档。
        SDK 清单信息更改是在 Android 程序集中进行的。
    • 参考文献

      • 添加对 Android 绑定程序集的引用。
    • 组件(NuGet)

      • 由于我的第 3 方的 SDK 记录了对 Google Play 服务的依赖关系,并且我使用 JD-GUI 反编译了他们的代码以验证它尝试使用的类/等,因此我将 Xamarin.GooglePlayServices.Gcm 添加到此项目,而不是 Binding Assembly 项目。

        注意:在任何文档中,我都不清楚我会阅读什么级别来引入 AAR 的依赖项。在我的众多尝试之一中,我已经将它们作为 JAR 直接添加(从 AAR 中提取)到具有 EmbeddedResourceJar 的 BuildAction 的 Binding Assembly 的 JARS 文件夹中。当找到所需的项目时,这提供了稍微更好的运行时结果,但感觉……恶心……似乎是维护问题的秘诀。必须有更好的方法。输入 NuGet!

        注意:添加此项目会带来以下所有项目:
      • Xamarin.GooglePlayServices.Base
      • Xamarin.GooglePlayServices.Basement
      • Xamarin.GooglePlayServices.Gcm(通过 VS Manage NuGet 添加的那个)
      • Xamarin.GooglePlayServices.Iid
      • Xamarin.GooglePlayServices.Tasks
    • 资产

      • 我的第 3 方的 SDK 使用了一个 config.JSON 文件,需要将它放在这里以便在运行时它可以读取它。
        使用构建操作设置:“AndroidAsset”
    • 构建时间需要额外的工作:

      • 绑定程序集中的其他 MetaData.XML 更改。
        - 当 Android 程序集引用已编译的绑定程序集并尝试构建时,一些生成的代码在此时发生了构建错误。

    程序集绑定转换

    如上所述,当我构建 MyApplication.Android.Binding 时,它自己构建得很好。但是,当我在 MyApplication.Android 中引用它时,它生成了一个新的 Java 代码翻译构建错误,该错误表明特定类的范围不符合预期/要求。为了解决这个问题,我返回到 Binding 程序集的 MetaData.xml 文件并选择从生成的 Java 代码接口中删除问题类,因为我没有调用或使用的计划。

    提示:在 Visual Studio 中执行此操作(我发现)的最简单方法是在 BindingAssembly 项目中启用 Show All Files 功能,然后在 obj\Debug\generated\src\ 文件夹中查找问题类。找到它后,单击它,生成的 Java 接口代码将 XPath 语句生成为 cmets。这些是您使用 MetaData.XML 文件更改或删除问题类或方法所需要的。

    总结

    现在我需要做的就是在上面编写我的跨平台代码(使用 Dependency Inversion + Xamarin Forms 内置的 DependencyService 在运行时访问每个 SDK),我的应用程序应该可以运行了!

    希望这些发现对需要处理类似绑定场景的其他人有所帮助。

    如果您确实在此处看到任何不正确的内容,或者您​​有任何想要添加的内容,请发表评论!

    【讨论】:

      【解决方案2】:

      您应该能够执行 #3,您只需引用这些现有 GPS/支持库绑定的预构建 NuGet 包。

      请确保您使用绑定库所期望的确切版本,因为 google 一直在移动类。

      我个人的建议是按难易程度(易->难):

      1. NuGet 包
      2. .jarclasses.jar 中的 EmbeddedReferenceJar / ReferenceJar(如果有资源,请使用 LibraryProjectZip
      3. 为每个依赖项绑定项目

      作为最佳实践,是的,您应该在不会使用的项目上使用&lt;remove-node&gt;。但是,这主要用于当您一开始不会使用的代码生成错误时。除非有相当多的方法你永远不会接触,否则我只会把这些物品放在身边,这样你就可以注意你的 dexcount。

      如需进一步帮助,您可以查看我的绑定指南:https://gist.github.com/JonDouglas/dda6d8ace7d071b0e8cb

      【讨论】:

      • 添加了 4/12 更新。将 SDK + 依赖项包装在 Java 组件中的想法行不通。仍在尝试找出解决方案。
      • 有没有人有绑定到依赖外部项目(如 Google Play 服务)的示例?
      • 对不起 - 我应该澄清一下。我的意思是通过绑定组件(例如包装 AAR)使用组件,其中包装的组件使用 Google Play 服务。我最初的问题已于 4 月 13 日更新,并提供了更多信息。
      • 自从将 Google Play 服务添加到我的绑定项目(通过 NuGet 或通过 EmbeddedReferenceJar)后,当我尝试构建将使用绑定程序集的项目时出现此错误:No resource found that matches the given name (at 'value' with value '@integer/google_play_services_version'). 我尝试从 Google Play Services AAR 中提取 version.xml 文件并将其定位在我的项目中的 Resources\Values\version.xml 等位置,但在运行时看不到它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-15
      • 1970-01-01
      • 2015-06-02
      • 2020-04-29
      • 2019-12-16
      • 1970-01-01
      相关资源
      最近更新 更多