Repository navigation
Open the app's own links in a browser on Android - #4
Merged
Merged
Conversation
Browser::open() fired a plain ACTION_VIEW intent. When the URL is one the app holds a verified App Link for, Android resolves that intent straight back to the app's own MainActivity, so the browser never opens and the link comes in as a deep link instead. On core 4.6 an unrouted deep link is handed to Browser::open() again, so the app loops. Custom Tabs (inApp, and the auth tab) go through the same resolution and have the same problem. Before launching, check whether the app itself is one of the activities that would handle the URL. Only then set a selector for the same request with a host-less URL, which only browsers can match, so the default browser gets the real URL. Every other URL is left alone, so links to YouTube or Maps still open in those apps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On Android,
Browser::open()fires a plainACTION_VIEWintent. If the URL is one the app holds a verified App Link for (a link on itsNATIVEPHP_DEEPLINK_HOST), Android resolves that intent straight back to the app's own MainActivity. The browser never opens and the link comes back in as a deep link. On core 4.6.0 an unrouted deep link is handed toBrowser::open()again, so the app loops. On an emulator that was about 1,500 round trips in 6 seconds, and Chrome never started.Browser::inApp()has the same problem, because a Custom Tabs intent with no package goes through the same resolution. So does the tabBrowser::auth()opens.The fix: before launching, ask the package manager which activities would handle the URL. If the app itself is one of them, set a selector for the same request with a host-less URL (
https://). Only browsers match a web URL with no host, so Android picks the default browser and still delivers the real URL. This is the same trick as NativePHP/mobile-air#558. Every other URL is left alone, so YouTube and Maps links still open in those apps. No<queries>entry is needed because an app can always see its own package.I used
queryIntentActivitiesrather thanresolveActivityso the check also covers the chooser. Before Android 12 an unverified link can show the app in the chooser next to the browsers, andresolveActivitywould only report the chooser. On Android 12 and later the query already leaves the app out when its link isn't approved, so nothing changes in that case.Testing
API 35 emulator with Chrome as the default browser and YouTube installed. Starter app on core 4.6.0 with
NATIVEPHP_DEEPLINK_HOST=example.com, approved withpm set-app-links-user-selection. Pluginmainfor "before", this branch for "after". The evidence is the ActivityTaskManager START lines in logcat.open()own linksel=https:///inApp()own linkauth()own linkopen()YouTube linkopen()github.comopen()own link, approval turned offChrome stopped at its first-run screen because I didn't accept its terms on the emulator, so I didn't see the page itself render.
Not tested: Android 11 and older (the chooser case), and two browsers with no default set.
Custom schemes are untouched. There's no browser to send them to, and
open('myapp://...')should keep reaching the app that registered the scheme.The new test in PluginTest checks the Kotlin source, like the existing AuthTab test. There are no Kotlin unit tests in this repo, which is why I tested on the emulator.
iOS doesn't need this. Opening an app's own universal link with
UIApplication.opengoes to Safari on the iOS 26.2 and 27.0 simulators (checked for mobile-air#558).🤖 Generated with Claude Code