Skip to content

Ignore file URLs in DeepLinkRouter#106

Draft
wojt-janowski wants to merge 1 commit intoNativePHP:mainfrom
wojt-janowski:fix/deeplink-router-ignore-file-urls
Draft

Ignore file URLs in DeepLinkRouter#106
wojt-janowski wants to merge 1 commit intoNativePHP:mainfrom
wojt-janowski:fix/deeplink-router-ignore-file-urls

Conversation

@wojt-janowski
Copy link
Copy Markdown

Summary

  • Guard DeepLinkRouter.handle(url:) against file:// URLs so plugins that declare document types don't have to runtime-patch AppDelegate.swift / NativePHPApp.swift to keep their inbound files away from the deep-link router.
  • File URLs that slip through today are stripped of their scheme and dispatched as Laravel routes, producing user-visible errors like The route /private/var/mobile/Containers/.../Inbox/scan.pdf could not be found.

Why

Apps that register CFBundleDocumentTypes (and LSSupportsOpeningDocumentsInPlace) — for example, a PDF viewer, an image importer, or a share-target receiver — receive file:// URLs from iOS through the same code paths as deep links:

  1. Cold start: AppDelegate.application(_:didFinishLaunchingWithOptions:) reads the URL from launchOptions and forwards it to DeepLinkRouter.shared.handle(url:).
  2. Warm start (UIKit): AppDelegate.application(_:open:options:) forwards to DeepLinkRouter.shared.handle(url:).
  3. Warm start (SwiftUI lifecycle, iOS 14+): WindowGroup's .onOpenURL in NativePHPApp.swift forwards to DeepLinkRouter.shared.handle(url:).

DeepLinkRouter.handle(url:) then enters the custom-scheme branch (since url.scheme == "file" is neither http nor https), normalises the file path into php://127.0.0.1/private/var/mobile/.../filename.pdf, and asks Inertia to navigate there. The WebView 404s.

The router is conceptually only for deep links — custom URL schemes registered via CFBundleURLTypes and universal links via Associated Domains. File URLs are a different OS-level concept and belong to whichever plugin/listener declared the document type.

Repro

  1. Add a CFBundleDocumentTypes entry to your NativePHP iOS app for com.adobe.pdf, set LSSupportsOpeningDocumentsInPlace=true.
  2. Build & run on a real device.
  3. From Files.app or Safari, share/open a PDF → "Copy to ".
  4. Observe: WebView attempts to navigate to /private/var/mobile/.../filename.pdf and shows a Laravel 404.

Fix

Add a guard !url.isFileURL else { return } at the top of DeepLinkRouter.handle(url:). The router logs and returns; downstream plugin handlers (e.g. those wired via AppDelegate's open-URL methods or SwiftUI's .onOpenURL) are now free to handle the file URL.

Alternatives considered

  • Allowlist of schemes (http, https, configured NATIVEPHP_DEEPLINK_SCHEME) — more defensive but enumerates state already implicit in CFBundleURLTypes and would need plumbing to read the configured scheme into Swift. Felt like premature scope.
  • A pluggable URL-interceptor delegate on DeepLinkRouter — adds new public API surface for a single-line bug fix.
  • A separate OpenFileRouter — same objection as above.

The guard is the smallest change consistent with the file's existing shape (input normalization at the top of handle, debug-logged early returns).

Test plan

  • Share a PDF from Files.app to a NativePHP iOS app with CFBundleDocumentTypes registered → no more 404, plugin's file handler runs as expected.
  • Cold-start the app via a myapp://something deep link → routes correctly (existing behaviour unchanged).
  • Warm-start the app via a myapp://something deep link → routes correctly (existing behaviour unchanged).
  • Universal link (https://app.example.com/path) handled correctly (existing behaviour unchanged).

Notes

Filing as draft for visibility / discussion. Happy to switch to the allowlist approach if maintainers prefer that over the targeted file-URL guard.

When an iOS app declares CFBundleDocumentTypes (or
LSSupportsOpeningDocumentsInPlace) so it can receive shared files from
other apps' share sheets / "Open In…", iOS delivers a `file://` URL
through the standard URL handlers (AppDelegate.application(_:open:options:)
and SwiftUI's WindowGroup .onOpenURL).

Both call sites currently forward unconditionally to
DeepLinkRouter.shared.handle(url:), which strips the scheme and treats
the absolute file path as a Laravel route. The user sees:

  The route /private/var/mobile/Containers/.../Inbox/scan.pdf
  could not be found.

DeepLinkRouter has no business handling file URLs — it only knows about
custom URL schemes and universal links. Plugins that declare document
types are responsible for handling inbound file URLs before they reach
the router. Add a guard so file URLs are ignored (with a debug log)
instead of mangled into bad routes.

This eliminates the need for plugins like share-target receivers to
runtime-patch AppDelegate.swift and NativePHPApp.swift just to short-
circuit file URLs around DeepLinkRouter.
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.

1 participant