使用自定义 URL 方案通过浏览器启动 Xamarin Android 应用程序

Fuo*_*ong 2 url-scheme deep-linking intentfilter xamarin.android applinks

程序

我有一个需要 URL 方案的跨平台 Xamarin 项目。要在 Xamarin Android 上启用此功能,我在AndroidManifest.xml文件中添加了以下代码,引用以启动自定义 android 应用程序帖子。

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="urlschemetest" android:host="testurl" />
    </intent-filter>
</activity>
Run Code Online (Sandbox Code Playgroud)

urlschemetest://testurl直接在 Android 中的浏览器中键入将转到 Google 搜索,而不是启动应用程序。所以,我有一个简单的html页面,它有一个打开应用程序的超链接,test url scheme

<a href="urlschemetest://testurl">open app</a>
Run Code Online (Sandbox Code Playgroud)

问题

通过单击上面的超链接,该应用程序不会启动。Visual StudioUnhandled Exception在输出中显示错误

Java.Lang.RuntimeException:无法实例化活动 ComponentInfo{com.companyname.UrlSchemeTest/com.companyname.UrlSchemeTest.MainActivity}:java.lang.ClassNotFoundException:在路径上找不到类“com.companyname.UrlSchemeTest.MainActivity”: DexPathList[[zip 文件 "/data/app/com.companyname.UrlSchemeTest-1/base.apk"],nativeLibraryDirectories=[/data/app/com.companyname.UrlSchemeTest-1/lib/arm, /data/app/ com.companyname.UrlSchemeTest-1/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]

尝试的解决方案

1)我看了看属性AndroidManifest.xml,也许这是因为的属性不相匹配的命名空间中使用MainActivity.cs。所以我改变了它。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   android:versionCode="1" 
   android:versionName="1.0" 
   package="UrlSchemeTest.Droid" 
   android:installLocation="auto">
Run Code Online (Sandbox Code Playgroud)

主Activity.cs

namespace UrlSchemeTest.Droid
{
    [Activity(Label = "UrlSchemeTest", Icon = "@mipmap/icon", 
        Theme = "@style/MainTheme", MainLauncher = true, 
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity :global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
         //body here
    }
}
Run Code Online (Sandbox Code Playgroud)

2) 在<activity>标签中使用绝对类名

<activity android:name="UrlSchemeTest.Droid.MainActivity">
Run Code Online (Sandbox Code Playgroud)

3) 要查看这是否是模拟器错误,我已经在 Android 模拟器和真正的 Android 设备上测试了该应用程序。

注意:虽然我已经在 Android 和 iOS 上创建了这个Xamarin 简单演示,但这个问题是关于让它在 Android 平台上工作。

Fuo*_*ong 7

解释

最初,我认为活动名称是命名空间(或包名称)和类名称的组合。对于本机 Android 和 Xamarin Android 5.1 之前的版本来说确实如此。如文档中所述,Xamarin Android 5.1 及更高版本并非如此

从 Xamarin.Android 5.1 开始,活动的类型名称基于要导出的类型的程序集限定名称的 MD5SUM。

使用我的Xamarin 简单演示应用程序,如果您构建它并AndroidManifest.xmlUrlSchemeTest.Android/obj/Debug/android文件夹中打开文件,您将看到如下内容

<activity 
    android:configChanges="orientation|screenSize" 
    android:icon="@mipmap/icon" android:label="UrlSchemeTest" 
    android:theme="@style/MainTheme" 
    android:name="md56cd34387ec86a2e1e9ba0754e1c30e2c.MainActivity">
Run Code Online (Sandbox Code Playgroud)

如您所见,活动名称是 md5 sum 和类名称的组合。

出于这个原因,当我在 AndroidManifest.xml

解决方案

首先,我需要移除该活动AndroidManifest.xml。在demo中,需要删除以下代码

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="urlschemetest" android:host="testurl" />
    </intent-filter>
</activity>
Run Code Online (Sandbox Code Playgroud)

然后,添加一个IntentFilter属性MainActivity.cs

using Android.App;
using Android.Content;

[IntentFilter(new[] { Intent.ActionView },
    Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
    DataScheme = "urlschemetest",
    DataHost = "testurl")]
public class MainActivity :global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        //code here
    }
}
Run Code Online (Sandbox Code Playgroud)

Url Scheme 现在应该可以工作了。

作为一个建议,我认为我们应该尽量不要修改AndroidManifest.xml

Xamarin.Android 允许你将自定义属性添加到你的类,然后将用于自动为你生成清单,从而帮助最大程度地减少此困难。我们的目标是让 99% 的用户永远不需要手动修改 AndroidManifest.xml。