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

Scheme uri ios

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.

[code lang=”csharp”]
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"));
}
}

[/code]

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

Launch Services application launch failed – timeout waiting – Trace logs

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:

[code lang=”csharp”]

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;

}
}

[/code]

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

This works like a charm :). First, we got rid off the launch service error (shown above). 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 ๐Ÿ™‚

Category:
Application Development and Integration, Mobile, User Experience
Tags:
, , ,