Inter-App Communications in Xamarin.iOS and Why OpenUrl Freezes for 10+ sec

March 09, 2016

Tags: iOS  scheme uri  xamarin 

Inter-App Communications

Mobile apps are meant to communicate using multiple channels, but the most popular, recommended, and widely used is using Scheme Uri. If you have not used Scheme URI then you should consider adding them to your app, it takes less than a minute to add support to your app, and it provides you a great way to get users to your app.

Setting the Stage

One scenario that I had was App A was launching App B and querying data, App B was in turn looking up the request, and returning data to App A. This is a common practice and can be seen in the diagram below.

Scheme uri ios<figcaption class="wp-caption-text">Scheme uri ios</figcaption></figure>

The Investigation

The problem here was that App B was freezing for up to 10+ sec before returning the result to App A. At first, I thought that this might be because the app initialisation or the data lookup taking long time, so I added diagnostic trace statements like below to time the operation and see where the time is spent.

public class AppDelegate
{
	...
	
	public override bool FinishedLaunching(UIApplication app, NSDictionary options)
	{
		Console.WriteLine("FinishedLaunching started: " + DateTime.Now.ToString("F"));

		...
		
		Console.WriteLine("FinishedLaunching complete: " + DateTime.Now.ToString("F"));
	}

	public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
	{
		Console.WriteLine("OpenUrl started: " + DateTime.Now.ToString("F"));

		...
		

		Console.WriteLine("OpenUrl complete: " + DateTime.Now.ToString("F"));
	}
}

I found that my app was starting in less than 1 Sec, which is quite impressive, and I am very happy about 🙂 but the problem was in returning the data to the launching app (App A). The traces were like these:

Launch Services application launch failed - timeout waiting - Trace logs<figcaption class="wp-caption-text">Launch Services application launch failed – timeout waiting – Trace logs</figcaption></figure>

This is telling me that App B was not able to launch App A to return back the data, which was quite surprising. I found that if you move that code to your pages/viewControllers things work fine. I thought that this was a bizarre situation, then I found this StackOverflow post, which explained the problem.

The Solution

Apparently, the iOS was having a race-condition like in trying to launch an app while the app itself was not fully launched. So the suggested solution was to add some delay or run it on another thread. Running the launch of App A on another thread would not work as it needs to be on the mainUiThread, so here is the solution I came up with:

public class AppDelegate
{
	...
	
	public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
	{
		// handle opening url and look up data

		...

		Task.Delay(500).ContinueWith(_ => 
				{									
					this.InvokeOnMainThread( () => 
					{			
						var uri = NSUrl.FromString(callbackUri);
						UIApplication.SharedApplication.OpenUrl(uri);
									
					});

				});

		return true;
		
	}
}

**_: LaunchServices: application launch failed – timeout waiting for launch._**

This works like a charm :). First, we got rid off the launch service error (see below). Second, App B is now returning the results to App A in less than 3 sec. If App B is in the background then it would return the data in less than 1 sec. Otherwise, it would take up to 3 sec to return the data. yayyy 🙂

If you have a comment, feedback or a question, I would love to hear from you