Essentials: Launcher API

Created on 12 May 2018  路  19Comments  路  Source: xamarin/Essentials

Description of the Feature

Provide the ability to detect and launch another application already installed on the device.

//Updated by JM

API Declaration

Integration Point: Launcher

API:

- Task<bool> CanOpenAsync(string uri);
- Task<bool> CanOpenAsync(Uri uri);
- Task OpenAsync(string uri);
- Task OpenAsync(Uri uri);

Implementations:

CanOpenAsync:

OpenAsync:

  • UWP: Launcher LaunchUriAsync
  • Android: Standard launcher stuff
  • iOS: UIApplication.SharedApplication.OpenURL

Documentation links for supported platforms

All 19 comments

I realize there is some overlap with the way the Browser API works due to it handling HTTP protocols so this proposal could morph into enhancing it to support launching other applications. iOS specifically appears to be using the same code that would open another application when using BrowserLaunchType.External.

Changing the Browser API to Launcher API seems like a more appropriate generic/high-level thing since launching the device browser is only one such app. What do you guys think?

I am pretty open to changing the name here to Launcher instead of Browser as this should work out of the box with our current implementation. New check I think is good for this instance as well. Will triage Monday.

The question to me will be is it alright to have our single API for opening uri.. or perhaps just a new API that is always extrenal. Leaning that way.

Yeah, we want the ability for the browser to be more specialized. It needs to support Chorme/Safari views.

I am not such a fan of merging the two concepts.

Agreed it should be in the "Launcher" name.

I will be updating the main comment now with discussion points.

On Android we should essentially use QueryIntentActivities to see if there are any activities available to match our intent (which likely is just created with ACTION_VIEW).

The only question i have is if we need the application id at all or just the uri is fine.

The only thing would be to launch a specific app if there are multiple that supports the scheme... not sure if that is supported on all platforms (assumption is no).

I think taking the app id into consideration makes things considerably more challenging or impossible on some platforms (eg: iOS).

In practice I think most apps declare their own unique uri scheme anyway.

yeah, i would leave it off for now in first iteration.

Since Android provides a non-URI option, it will not be possible to cover it since we are going for lowest common denominator of the API surface area but you can open an application using it's package name:

Intent launchIntent = getPackageManager().getLaunchIntentForPackage("com.example.abc");
startActivity( launchIntent );

If the proposed methods will only be used to open other apps, what do you think about some convenience methods to open a specific app store page? Identifier would be the package name on Android and the appId on iOS. Might be too much since you could already do it with the OpenAsync(...) methods that would be available.

Something like:

- Task OpenAppStoreListingAsync(string identifier);

Arguably, any API that invokes an external application could be a candidate for the Launcher API
(replacing Sms, PhoneDialer, Email APIs) since launcher is just a higher-level abstraction.

So the complete API could be like this:

- Task<bool> CanOpenAsync(string uri);
- Task<bool> CanOpenAsync(Uri uri);
- Task OpenAsync(string uri);
- Task OpenAsync(Uri uri);
- Task OpenAppStoreListingAsync(string identifier);
- bool OpenDialer(string phoneNumber); // true - dialer opened successfully
- Task ComposeEmailAsync(EmailMessage message);
- Task ComposeSmsAsync(SmsMessage message);

That might be going a little too crazy but fun to brainstorm 馃槂

We probably won't merge in the sms, email, dialer because we probably will extend the APIs. For example, the dialer my get an actual start call, or the sms a background send.

But, you are right when saying that email (as it is today) can just use the launcher API internally. We actually do use our own apis in other apis here.

Yeah, ideally that route. I think the API I outlined in the original post is the go to.

As far as I understood the contribution guide I may now implement this feature? I began working on it on https://github.com/Mrnikbobjeff/Essentials/tree/feature/issue-250. I implemented it for all Platforms, though I only ran unit tests on the Android implementation. If it were possible I'd like to be assigned this issue so that it could be marked as "In Progress".

Thanks @Mrnikbobjeff I've marked it as in progress :)

@Redth @jamesmontemagno I implemented the UWP and Android Launcher and tested them. I would like to have clarified what should happen if the user inputs a string which is not a valid System.Uri. On UWP this would throw a InvalidOperationException, on Android this would simply return false on CanOpenAsync. Should we enforce that all URI's are valid or are we to accept different behviour on different platforms?
Check Can_Not_Open_Uri_As_String_Throws_InvalidUriException for different behaviour on different platforms.

As I see it we have three options:
1.) Try/Catch and return false, thus hiding the invalid uri exception.
2.) Enforce Uri validity, thus throwing on every plaftorm.
3.) Different exception behaviour on different platforms.

I went with option 3 for the moment, UWP and iOS throw UriFormatExceptions, Android simply returns false. Any other input on this matter?

I personally like option 2.

We generally want to keep things consistent between platforms whenever possible, and this is a relatively easy way to do so.

Okay, I changed it to verify the parameter on every platform. Once I return to a pc running windows I will update the documentation and create a PR

Merged.

Was this page helpful?
0 / 5 - 0 ratings