Reputation: 320
I have a cross-platform Xamarin project that needs a URL scheme. To enable this feature on Xamarin Android, I add following code in AndroidManifest.xml
file, referenced to 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>
Typing urlschemetest://testurl
directly to a browser in an Android would go to Google search instead of launching the app. So, I have a simple html
page that has a hyperlink to open the app, test url scheme.
<a href="urlschemetest://testurl">open app</a>
By clicking on the hyperlink above, the app isn't launched. Visual Studio shows a Unhandled Exception
error in the Output
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) I looked at attributes in AndroidManifest.xml
, and maybe it's because package attribute did not match with namespace used in MainActivity.cs
. So I changed it.
<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) Using absolute classname in <activity>
tag
<activity android:name="UrlSchemeTest.Droid.MainActivity">
3) To see if this was a emulator bug, I've tested the app on both Android emulator and real Android device.
Note: This question is about making it work on Android platform although I've created this Xamarin simple demo on Android and iOS.
Upvotes: 4
Views: 7846
Reputation: 320
Initially, I thought that the activity name is a combination of the namespace (or package name) and the class name. It's true with native Android and prior to Xamarin Android 5.1. It's not true with Xamarin Android 5.1 and later, as stated in 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.
With my Xamarin simple demo app, if you build it and open AndroidManifest.xml
file in UrlSchemeTest.Android/obj/Debug/android folder, you would see something as below
<activity
android:configChanges="orientation|screenSize"
android:icon="@mipmap/icon" android:label="UrlSchemeTest"
android:theme="@style/MainTheme"
android:name="md56cd34387ec86a2e1e9ba0754e1c30e2c.MainActivity">
As you can see, the activity name is a combination of md5 sum and class name.
For this reason, there my had a conflict at build time when I created an activity in AndroidManifest.xml
First, I need to remove the activity in AndroidManifest.xml
. In the demo, following code needs to be deleted
<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>
Then, add a IntentFilter
property in 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
}
}
Url Scheme should work now.
As an advice, I think we should try not to modify AndroidManifest.xml
if we can.
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.
Upvotes: 10