Closed Bug 851693 Opened 7 years ago Closed 5 years ago

Allow loading URI Intents

Categories

(Firefox for Android :: General, defect)

x86
Linux
defect
Not set

Tracking

()

RESOLVED FIXED
Firefox 41
Tracking Status
p11 + ---
firefox41 --- fixed
relnote-firefox --- 41+

People

(Reporter: wesj, Assigned: mcomella)

References

(Blocks 2 open bugs)

Details

(Keywords: dev-doc-complete)

Attachments

(2 files, 2 obsolete files)

We should support these. Patch coming
Attached patch Patch v1 (obsolete) — Splinter Review
Just creating a uri from this string the normal way does not work correctly for these intents. Its a little scary how much power this exposes to pages though (they can, for instance, open the awesomescreen)....
Attachment #725639 - Flags: review?(mark.finkle)
Grr. qcrecord seems to have let some Logging slip through. Apologies.
Duplicate of this bug: 851512
Attachment #725639 - Flags: review?(mark.finkle) → review+
Let's loop security in as well. We should take a look at what, if any, limits should be in place.
Yeah, I should note, we do show a prompt before opening them. Right now its very uninformative about what's happening, but we can fix that (bug 851581).
Flags: sec-review?
Flags: sec-review? → sec-review?(mgoodwin)
Whiteboard: [in-progress secreview][start 2013-04-11][target 2013-04-18]
Mark, how did the sec review go?
Flags: needinfo?(mgoodwin)
Mark told me that having a prompt in place made him feel better about this. Unfortunately, I think we've removed these prompts. I think we're going to need to rework nsIContentDispatchChooser to show something for these...
I experience a problem with Firefox which I think is related to this bug.

The desired behavior is that when a link is clicked either the app opens if it's installed, or Google Play opens, if it's not installed. (or alternatively a website loads if the app is not installed).

I have tested a few methods for starting an intent from a link in Firefox Android.

The three methods are:
1. Regular HTTPS link (https://myapp.com)
2. Custom scheme (myAppScheme://myapp.com)
3. Intent method (intent://myapp/#Intent;scheme=myAppScheme;package=com.myapp;end)

The results from my tests show the following:
1. Regular link - Just opens the website
2. Custom scheme - yes-no dialog, then launches my app (if the app is installed) OR yes-no dialog, then no reaction if the app is not installed.
3. Intent method - shows yes-no dialog, which does not do anything (whether or not the app is installed).

In the end none of the possible methods works with Firefox. 

The only partially working method is with a custom scheme, which launches the app successfully. The problem is that this is a not recommended method. Furthermore, it shows an error if the app is not installed (instead of opening it in the Google Play).

-> The recommended method for android is the third one (with an "intent:// link"). However, it does not seem to work with Firefox at all. In my opinion, Firefox should focus on supporting this method, as it is most logical, useful and also standard for Android.

Do you know what the recommendation for Firefox is?
Yeah, I agree. I think we need some sort of prompt when we're going to load a uri in an app IF there's only one app around that can handle the uri. i.e. If I tap a link to:

myAppScheme://myapp.com

we should show a little prompt before launching. My feeling would be to show something like a context menu:

Open with       |
----------------|
My App          |


but we could alternatively do a normal alert type dialog (maybe a remember-me checkbox?):

Open link                                 |
------------------------------------------|
Open with My App?                         |
[] Don't ask again for myAppScheme links  |
------------------------------------------|
        Open         |      Cancel        |


If there are multiple apps, you should just get an Android chooser.
Mark Goodwin said he was fine with this if we had a prompt of some sort. Ian, what do you think?
Flags: needinfo?(mgoodwin) → needinfo?(ibarlow)
Makes sense to me. I would only suggest we use more Android-like language for the yes/no buttons:


   +------------------------------------------------+
   |  Open with                                     |
   |------------------------------------------------|
   |                                                |
   |  +-----+         +-----+          +------+     |
   |  |     |         |     |          |      |     |
   |  |     |         |     |          |      |     |
   |  +-----+         +-----+          +------+     |
   |   App             App               App        |
   |                                                |
   |                                                |
   |                                                |
   |  +-----+                                       |
   |  |     |                                       |
   |  |     |                                       |
   |  +-----+                                       |
   |   App                                          |
   |                                                |
   +------------------------+----------------------->
   |                        |                       |
   |      Always            |       Just once       |
   |                        |                       |
   +------------------------v-----------------------+
Flags: needinfo?(ibarlow)
I like Ian's suggestion, for what it's worth. Do we plan on doing more work with this?
Flags: needinfo?(wjohnston)
Yes. We can show these types of dialogs now. Just need to implement it!
Flags: needinfo?(wjohnston)
Duplicate of this bug: 963099
The dialog should be optional depending on the package param in intent://

See: https://developer.chrome.com/multidevice/android/intents

Now, the way this works on AOSP-based browsers as well as Chrome, is that if the package: param is set, it will check to see if the app is installed, and if not, it will take you to the Play Store with this link: https://play.google.com/store/apps/details?id=PACKAGE_NAME

If the app is installed, then there's no need for a dialog, the app will handle the intent, and if multiple apps are supported, then Android will show up the dialog, this is how it works on Chrome for Android.

If you'd like to try this scenario, use this link to test it on Chrome for Android and see how it works: http://easyshiftapp.com/redeem/?email=test&code=testCode

Direct Intent URL (will show as a link when opening that site above on Android):
intent://redeem/?email=testEmail&code=testCode#Intent;scheme=easyshift;package=com.quri.easyshift;launchFlags=268435456;end

Thanks.
Oh, forgot to mention, the Play Store app handles https://play.google.com/store links on it's own, so if the app needs to be installed, it will open in the Play Store, ready to install, without a dialog.
I have a user asking about the support of this in version 30, is this still being worked on? [https://support.mozilla.org/en-US/questions/1005893]
Adding information. This creates Web Compatibility issues for some companies, which want to propose the users to start a webapp with a button for a specific domain.

Here is an example of code used on a Web site. (There is a ill user-agent detection). 

function launchApp() {
    var ua = window.navigator.userAgent.toLowerCase();
    if (ua.search(/iphone/) != -1 || ua.search(/ipad/) != -1 || ua.search(/ipod/) != -1) {
        var appUrl='com-company-appName://';
        var storeUrl='https://itunes.apple.com/jp/app/id1234567890?mt=8';
        document.location = storeUrl;
    } else if (ua.search(/android/) != -1) {
        var appUrl = 'intent://#Intent;scheme=com-company-appName;package=com.company.appName;end';
        location.href = appUrl;
    } else {
        document.location = 'https://www.example.com';
    }
    return;
}


It might be good to do telemetry on how often intent:// url is used. And at least have a message saying the scheme is not supported.
Duplicate of this bug: 817532
(In reply to Karl Dubost :karlcow from comment #18)
> Adding information. This creates Web Compatibility issues for some
> companies, which want to propose the users to start a webapp with a button
> for a specific domain.

Karl, what do you mean by the above comment? Do you mean not having this implemented is a web compat issue or that the implemented version of this causes compatibility issues?

Provided there are no web compat issues, my v1 for this bug would entail following the suggestion in comment 15. To make this initial implementation as small as possible, I will focus on only opening URLs with a specific package listed. This could avoid the need to show a custom dialog before opening an intent URI link, as we either open the app or the play store. We can show a "Not supported" toast for intent URIs without a specific package for now (comment 18).
Assignee: nobody → michael.l.comella
Flags: needinfo?(kdubost)
Clearing secreview flags because I'll be posting a new patch (though it'll probably be fairly similar to the previous one).
Flags: sec-review?(mgoodwin)
Whiteboard: [in-progress secreview][start 2013-04-11][target 2013-04-18]
Michael,
I meant this: "Do you mean not having this implemented is a web compat issue"
Flags: needinfo?(kdubost)
/r/8391 - Bug 851693 - Open Activity via Intent URI if it is installed. r=margaret
/r/8393 - WIP

Pull down these commits:

hg pull -r dcf06283755077926c0fe850492f36c4366cec42 https://reviewboard-hg.mozilla.org/gecko/
I made a test page: https://people.mozilla.org/~mcomella/test/intent_uri.html

When this bug is completed, if you click the link you should be brought to either the zxing QRCode reader or to the Play Store to install it.
I believe the Java components of the second changeset in comment 23 are correct, however, the JNI code [1] we fall back on seems to be dropping the ball on my Play Store Intent (even though it correctly opens the qr code reader when it is installed using my test case from comment 24). Specifically, when I'm constructing a Play Store Intent,  the correct handler output is received:

05-07 17:51:44.751 D/lol     (13752): handlers:
05-07 17:51:44.751 D/lol     (13752):   Google Play Store
05-07 17:51:44.751 D/lol     (13752):
05-07 17:51:44.751 D/lol     (13752):   com.android.vending
05-07 17:51:44.751 D/lol     (13752):   com.google.android.finsky.activities.LaunchUrlHandlerActivity

However, the store never opens. The "could not find an app to open" toast never appears so something is running successfully somewhere. I was able to use similar code to open the store in a standalone app via `startActivity(appStoreIntent);`.

I'm having difficulty making sense of the JNI code because getHandlersForURL doesn't seem to be called from anywhere that actually uses the returned handler data - Jim, do you have any idea what's going on here?

[1]: https://mxr.mozilla.org/mozilla-central/source/widget/android/AndroidBridge.cpp?rev=a2619dca0a16#482
Flags: needinfo?(nchen)
A little team debugging with liuche showed that getOpenURIIntent is called from other places from which the output may actually be used. More digging ahead...
Flags: needinfo?(nchen)
tracking-p11: --- → +
I realized I'm starting to scope creep here - I don't need to open the Play Store if the intent fails to find an installed applications for the purposes of this bug (I will file a followup).

Notably, we have the Play Store search functionality, just as part of the "Couldn't find an app to open this link" toast - there's a "Search" button. However, it seems broken on my test page: bug 1164112.
Comment on attachment 8603098 [details]
MozReview Request: bz://851693/mcomella

/r/8391 - Bug 851693 - Open Activity via Intent URI if it is installed. r=margaret
/r/8393 - REMOVE: Dummy commit to push to reviewboard

Pull down these commits:

hg pull -r f2f7cbe7eae2e298986b656c8b27541ba7eeabd9 https://reviewboard-hg.mozilla.org/gecko/
Attachment #8603098 - Flags: review?(margaret.leibovic)
Attachment #725639 - Attachment is obsolete: true
I'm not sure this deserves its own bug yet but Jim responded to me on IRC (re comment 25) I just wanted to put this here so I don't lose it:

<jchen> mcomella: so i looked into that bug. the reason it's not launching market is because the market handler is not marked as default. without a default handler, we resort to the android app chooser, but we give the app chooser the original uri, which is the intent:// uri, which the app chooser doesn't understand. so nothing happens in the end
<mcomella> jchen: Thanks. Where do we give it the original url?
<jchen> mcomella: here afaiu http://mxr.mozilla.org/mozilla-central/source/mobile/android/components/ContentDispatchChooser.js#50

And later:

<mcomella> jchen: re your research on https://bugzilla.mozilla.org/show_bug.cgi?id=851693#c25 , why is the intent handling done in native code anyway?
<jchen> mcomella: i think to play nice with gecko's protocol handling system. we have a js protocol handler, and to launch an intent from it, we need to go js > native > java
https://reviewboard.mozilla.org/r/8391/#review7271

::: mobile/android/base/GeckoAppShell.java:1206
(Diff revision 2)
> +            if (intent.getPackage() == null) {

In this case should we instead be falling through to handle the URI as we would in the default case? Same question applies up above with the URISyntaxException, although that seems like it would happen less frequently.
https://reviewboard.mozilla.org/r/8391/#review7299

> In this case should we instead be falling through to handle the URI as we would in the default case? Same question applies up above with the URISyntaxException, although that seems like it would happen less frequently.

The intent:// URIs have only one way they're expected to be parsed so falling back to default handling could produce unexpected results (and is thus undesirable).
Comment on attachment 8603098 [details]
MozReview Request: bz://851693/mcomella

https://reviewboard.mozilla.org/r/8389/#review7333

Ship It!
Attachment #8603098 - Flags: review?(margaret.leibovic) → review+
Because I can't login to reviewboard, I commented in another bug, but IMO these functions should probably not be showing toasts anyway. They're utility functions to do work and not really UI ones. They may (and apparently do) call through here multiple times to try and open things different ways.

I'd love to rename, cleanup, and move them to IntentUtils.java some day (and clean up GeckoAppShell along the way). They'd need some great unit tests first probably. Let me file those two bugs.
(In reply to Wesley Johnston (:wesj) from comment #33)
> Because I can't login to reviewboard, I commented in another bug, but IMO
> these functions should probably not be showing toasts anyway. They're
> utility functions to do work and not really UI ones. They may (and
> apparently do) call through here multiple times to try and open things
> different ways.

Makes sense to me, especially given the get* name on the function - I've removed the "we need a toast!" comments.
https://hg.mozilla.org/mozilla-central/rev/22652196dd36
Status: NEW → RESOLVED
Closed: 5 years ago
Resolution: --- → FIXED
Target Milestone: --- → Firefox 41
Comment on attachment 8603098 [details]
MozReview Request: bz://851693/mcomella

Approval Request Comment
[Feature/regressing bug #]: N/A
[User impact if declined]:
  Users will be unable to open Android apps via web links. Also related to the work in bug 1156869 & bug 1168662.
 
[Describe test coverage new/current, TreeHerder]: Tested locally, on Nightly for a while.

[Risks and why]: 
  Low - we only add code to handle links that start with "intent" so we'll only break "intent..." links, which don't do anything as is. Then we call out to an Android framework function to create the Intent and return that only if there is an explicit package set.

[String/UUID change made/needed]: None.
Attachment #8603098 - Flags: approval-mozilla-aurora?
Attachment #8603098 - Flags: approval-mozilla-aurora?
From some testing from a partner - please consider the following:
"We can confirm to launching application using "intent://" URIs. But, Unexpected behavior is remained in the case that a receiver application does not exist.
In Chrome : App page is shown in Google Play App.
In Firefox : Error toast is shown and search from toast is also unexpected behavior. (searching "intent" in Google Play App.) "
(In reply to Karen Rudnitski [:kar] from comment #38)
> From some testing from a partner - please consider the following:
> "We can confirm to launching application using "intent://" URIs. But,
> Unexpected behavior is remained in the case that a receiver application does
> not exist.
> In Firefox : Error toast is shown and search from toast is also unexpected
> behavior. (searching "intent" in Google Play App.) "

I will dig into bug 1168980 then.
Attachment #8603098 - Attachment is obsolete: true
Attachment #8618006 - Flags: review+
Attachment #8618007 - Flags: review+
I wasn't really sure where best to document this, so for now I've added a note to the bottom of this section:

https://developer.mozilla.org/en-US/docs/Web/API/Web_Activities#Firefox_for_Android_activities
Keywords: relnote
Margaret, we stopped using the relnote keyword a while ago (I found this bug when I requested the removal of this keyword).

We are using the tracking flags now.

Could you fill this template for this change? thanks
Release Note Request (optional, but appreciated)
[Why is this notable]:
[Suggested wording]:
[Links (documentation, blog post, etc)]:
relnote-firefox: --- → ?
Flags: needinfo?(margaret.leibovic)
Keywords: relnote
(Leave NI for Margaret to verify)

Release Note Request (optional, but appreciated)
[Why is this notable]:
  Intent URIs allow web developers to open Android apps via links in the web browser, unifying Android applications and the web. They are a common web browser feature that was originally implemented in Chrome (or maybe the stock browser) and has been adopted by pretty much every other mobile browser.

[Suggested wording]:
  Open Android applications from a web page via [Intent URIs](https://developer.chrome.com/multidevice/android/intents)

[Links (documentation, blog post, etc)]:
  General intent URI info: https://developer.chrome.com/multidevice/android/intents
(In reply to Sylvestre Ledru [:sylvestre] from comment #44)
> Margaret, we stopped using the relnote keyword a while ago (I found this bug
> when I requested the removal of this keyword).

Thanks for catching that, and sorry I was behind the times :)


(In reply to Michael Comella (:mcomella) from comment #45)
> (Leave NI for Margaret to verify)
> 
> Release Note Request (optional, but appreciated)
> [Why is this notable]:
>   Intent URIs allow web developers to open Android apps via links in the web
> browser, unifying Android applications and the web. They are a common web
> browser feature that was originally implemented in Chrome (or maybe the
> stock browser) and has been adopted by pretty much every other mobile
> browser.
> 
> [Suggested wording]:
>   Open Android applications from a web page via [Intent
> URIs](https://developer.chrome.com/multidevice/android/intents)
> 
> [Links (documentation, blog post, etc)]:
>   General intent URI info:
> https://developer.chrome.com/multidevice/android/intents

Looks great, thanks!
Flags: needinfo?(margaret.leibovic)
Added to the release notes with Michael's wording. Thanks!

I added it in the "New" category as it is a user facing change.
However, for this item "Open links from Android applications in the same tab via EXTRA_APPLICATION_ID" (bug 840574), I selected the category "Developer" as it is seem a more appropriate.
Thanks for all the awesome work! One problem I have now is that I can't fallback to my website if the app is not installed. This is possible on Chrome with `S.browser_fallback_url`. 

I use Chrome intents in the following way: intent://open?foo=bar#Intent;scheme=myapp;package=com.example.myapp;S.browser_fallback_url=http%3A%2F%2Fexample.com;end

Are there any plans to add this in the near future? Or are my options now limited to opening the Play Store if my app is not installed? 

Thank you!
(In reply to statenderrick from comment #48)
> Thanks for all the awesome work! One problem I have now is that I can't
> fallback to my website if the app is not installed. This is possible on
> Chrome with `S.browser_fallback_url`. 

This is implemented already [1], I'm surprised it doesn't work! Are you running Firefox Beta (or later versions)? If so, do you have a more concrete test case?

[1]: https://mxr.mozilla.org/mozilla-central/source/mobile/android/base/IntentHelper.java?rev=a5d7ee79a10c#204
Flags: needinfo?(statenderrick)
(In reply to Michael Comella (:mcomella) from comment #49)

Thank you for being so responsive! Here's a concrete example.

intent://listen/live_radio/1281?played_from=46&link_click_id=106782750287072124#Intent;scheme=ihr;package=com.clearchannel.iheartradio.controller;S.browser_fallback_url=https%3A%2F%2Fbnc.lt%2Fd%2FFZ2njK7R2l%2Fchrome_deepview;end

On Firefox beta, this always opens the Play Store rather than falling back to bnc.lt. This definitely works in Chrome as I just tested it. Is there something that I'm doing incorrectly?

For your convenience: https://dl.dropboxusercontent.com/u/13158636/site/firefox41/intenttest.html
Flags: needinfo?(statenderrick)
Flags: needinfo?(michael.l.comella)
Michael, let me know if we can provide any more information. I'm at Branch Metrics and we have an open-source solution for linking and deeplinking on mobile. Our partners who don't want to redirect to the Play Store (for whatever reason) make heavy use of S.browser_fallback_url.

Really sorry to bother you, I'm sure you all are super busy. Again, we're excited that Firefox is using Chrome Intents. Thanks for all your hard work here.
I see what's going on here – we search the play store if the app package is specified and then try to use the fallback url, which is unlike Chrome's behavior (which does the opposite) – I filed bug 1198369.

Thanks for letting us know! :)
Flags: needinfo?(michael.l.comella)
Ah, that makes sense. I'll follow that thread for updates. Thanks!
intent: links like described above seem to work fine on Android Firefox 59 as long as there is no package parameter is included; but if it is, Google Play is opened, even if the package exists on the device. Is this a regression?
(In reply to Glenn Linderman from comment #55)
> intent: links like described above seem to work fine on Android Firefox 59
> as long as there is no package parameter is included; but if it is, Google
> Play is opened, even if the package exists on the device. Is this a
> regression?

Glenn, could you file a new ticket to track this discussion?  Thanks!
Flags: needinfo?(v+mozbug)
You need to log in before you can comment on or make changes to this bug.