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

Launch Xamarin Android App Via a Browser Using Custom URL Scheme

程序

我有一个需要 URL 方案的跨平台 Xamarin 项目。为了在 Xamarin Android 上启用此功能,我在 AndroidManifest.xml 文件中添加了以下代码,参考 launch custom android application post.

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

在 Android 中直接在浏览器中输入 urlschemetest://testurl 会转到 Google 搜索而不是启动应用程序。因此,我有一个简单的 html 页面,其中包含一个用于打开应用程序的超链接,

<a href="urlschemetest://testurl">open app</a>

问题

点击上面的超链接,应用程序没有启动。 Visual Studio 在输出

中显示 Unhandled Exception 错误

Java.Lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.companyname.UrlSchemeTest/com.companyname.UrlSchemeTest.MainActivity}: java.lang.ClassNotFoundException: Didn't find class "com.companyname.UrlSchemeTest.MainActivity" on path: DexPathList[[zip file "/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中的attributes,可能是因为package属性与[=不匹配51=]namespace 在 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">

MainActivity.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
    }
}

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

<activity android:name="UrlSchemeTest.Droid.MainActivity">

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

注意: 这个问题是关于如何让它在 Android 平台上运行的,尽管我已经在 Android 上创建了这个 Xamarin simple demo 并且 iOS.

说明

最初,我认为activity 名称是名称空间(或包名称)和class 名称的组合。本机 Android 和 Xamarin Android 5.1 之前的版本都是如此。 Xamarin Android 5.1 及更高版本并非如此,如 docs

中所述

Beginning with Xamarin.Android 5.1, the type name of an activity is based on the MD5SUM of the assembly-qualified name of the type being exported.

使用我的 Xamarin simple demo 应用程序,如果您构建它并打开 UrlSchemeTest.Android/obj/Debug/android 文件夹中的 AndroidManifest.xml 文件,您会看到如下内容

<activity 
    android:configChanges="orientation|screenSize" 
    android:icon="@mipmap/icon" android:label="UrlSchemeTest" 
    android:theme="@style/MainTheme" 
    android:name="md56cd34387ec86a2e1e9ba0754e1c30e2c.MainActivity">

如您所见,activity名称是md5和class名称的组合。

因此,当我在 AndroidManifest.xml

中创建 activity 时,我在构建时遇到了冲突

解决方案

首先,我需要删除AndroidManifest.xml中的activity。 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>

然后,MainActivity.cs

中添加一个IntentFilter属性
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
    }
}

Url 方案现在应该可以工作了。

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

Xamarin.Android helps to minimize this difficulty by allowing you to add custom attributes to your classes, which will then be used to automatically generate the manifest for you. Our goal is that 99% of our users should never need to manually modify AndroidManifest.xml.