The trouble opening app rating interface

As many other apps, SlideFour allow the user to open Google Play to rate the game.

The classic example of code you can find online contains the following steps:

  1. get the app Activity
  2. get the PackageManager of the activity
  3. create a Intent describing the action
  4. start the intent activity
public virtual void RateApp()
{
	Context activity = Android.App.Application.Context;
	string package_name = activity.PackageName;
	string url = "market://details?id=" + package_name;

	PackageManager package_manager = activity.PackageManager;

	try
	{
		// check if Google Play is installed:
		package_manager.GetPackageInfo("com.android.vending", PackageInfoFlags.Activities);

		Intent intent = new Intent(Intent.ActionView, Android.Net.Uri.Parse(url));
		activity.StartActivity(intent);
	}
	catch (NameNotFoundException ex)
	{
		Console.WriteLine(ex.Message);
	}

}//RateApp

Unfortunately, the real world is much more complex: on some devices, regardless the android version in it, the property activity.PackageManager returns NULL !

The official docs state (note the bold phrase) "Caution: If there are no apps on the device that can receive the implicit intent, your app will crash when it calls startActivity(). To first verify that an app exists to receive the intent, call resolveActivity() on your Intent object. If the result is non-null, there is at least one app that can handle the intent and it's safe to call startActivity(). If the result is null, you should not use the intent and, if possible, you should disable the feature that invokes the intent."

The strange thing is that we ask to open Google Play and we got NULL in some devices that have Google Play installed!
This was the reason that in SlideFour v1.0 we got a lot of application crashes (the v1.0.2 fixed this issue).

So we need to write a workaround:

  1. get the app Activity
  2. get the PackageManager of the activity
  3. if the package manager is not NULL then
  4. create a Intent describing the action and start the intent activity
  5. else (if the package manager is NULL)
  6. provide a fallback using internet browser

Finally, is suggest to wrap any of external calls into a try-catch section. 

// returns TRUE if successfully start app rating interface
public virtual bool RateApp()
{
	bool result = true;

	try
	{
		Context activity = Android.App.Application.Context;
		string package_name = activity.PackageName;
		string url = "market://details?id=" + package_name;

		// check if Google Play is installed:
		try
		{
			PackageManager package_manager = activity.PackageManager;
			package_manager.GetPackageInfo("com.android.vending", PackageInfoFlags.Activities);

			Intent intent = new Intent(Intent.ActionView, Android.Net.Uri.Parse(url));
			activity.StartActivity(intent);
		}
		catch (Exception play_ex)
		{
			result = false;
			Console.WriteLine(play_ex.Message);
		}

		if (!result)
		{
			// fallback using the internet browser:
			string google_play_url = "https://play.google.com/store/apps/details?id=" + package_name;

			var browser_intent = new Intent(Intent.ActionView, Android.Net.Uri.Parse(google_play_url));
			browser_intent.AddFlags(ActivityFlags.NewTask | ActivityFlags.ResetTaskIfNeeded);

			activity.StartActivity(browser_intent);

			result = true;
		}
	}
	catch (Exception ex)
	{
		Console.WriteLine(ex.Message);
		result = false;
	}

	return result;

}//RateApp