Skip to content

fix(ios): open custom schemes instead of always reporting failure - #2

Open
CodyPChristian wants to merge 1 commit into
NativePHP:mainfrom
CodyPChristian:fix/open-custom-scheme-without-canopenurl
Open

fix(ios): open custom schemes instead of always reporting failure#2
CodyPChristian wants to merge 1 commit into
NativePHP:mainfrom
CodyPChristian:fix/open-custom-scheme-without-canopenurl

Conversation

@CodyPChristian

Copy link
Copy Markdown

The problem

Browser.Open gates UIApplication.open behind canOpenURL:

if UIApplication.shared.canOpenURL(url) {
    UIApplication.shared.open(url, options: [:]) { opened in ... }
} else {
    semaphore.signal()   // success stays false
}

For a custom scheme, iOS answers canOpenURL false unless that scheme is listed in the calling app's LSApplicationQueriesSchemes — regardless of whether anything on the device handles it.

So Browser::open('myapp://') returns false on a phone that has myapp installed, and there's no way to tell that apart from a real failure.

That's awkward for any app that declares its target schemes up front, and impossible for one that can't. In our case a host app opens a per-tenant companion app whose scheme is issued long after the host's Info.plist is written — so the guard reports "nothing can open this" for every custom scheme, permanently.

The change

Drop the guard and let open's completion handler report the result.

It already answers the same question, without the declaration requirement, and answers it from what actually happened rather than from a pre-flight guess. That makes success mean what the docblock says it means: "True if successfully opened."

Why this shouldn't regress anything

  • http/https is unaffected. canOpenURL is unconditionally true for those — no declaration needed — so the guard never rejected one. That's every example in the README.
  • No new failure mode. UIApplication.open with a scheme nothing handles doesn't throw; the completion handler receives false, which is exactly what the else branch was producing.
  • The only behavior that changes is for custom schemes, which currently always fail.

The 2s semaphore timeout is untouched; the failure path now costs one async round-trip instead of returning immediately, which isn't observable.

Testing

vendor/bin/pest — 58 passed, 129 assertions, unchanged.

The Swift isn't covered by that suite. Verified by building a real app against the branch: it compiles, launches, and the custom-scheme path now reaches open instead of short-circuiting.

Also added a short note to the README's open() section, since custom schemes weren't mentioned and the success return is how you detect the target app isn't installed.

`Browser.Open` gated `UIApplication.open` behind `canOpenURL`. For a custom
scheme, iOS answers `canOpenURL` false unless that scheme is listed in the
CALLING app's `LSApplicationQueriesSchemes` — whether or not anything on the
device actually handles it.

So `Browser::open('myapp://')` returns false on a phone with `myapp` installed,
and there is no way to tell that apart from a genuine failure. An app whose
target schemes are not known when its own Info.plist is written can never
satisfy the declaration requirement, so for those the guard reports "nothing can
open this" for every custom scheme, permanently.

`open`'s completion handler already answers the same question, without the
declaration requirement, and from what actually happened rather than a
pre-flight guess. Dropping the guard makes `success` mean what the docblock
already claims it means.

http/https is unaffected: `canOpenURL` is unconditionally true for those, which
is every example in the README.

@simonhamp simonhamp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants