Add manifest scope improvements doc#137
Conversation
Describe problems app developers face with the current manifest scope model and propose a two-layer scope architecture to address them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| | # | Problem | Proposed Solution Area | | ||
| |---|---------|----------------------| | ||
| | 1 | Cannot exclude paths from scope | New manifest members for scope include/exclude lists | | ||
| | 2 | Navigation capture scope ≡ app scope | Separate "capture scope" concept (Layer 2) | |
There was a problem hiding this comment.
I wonder if 2,3,4 could be combined into one thing?
E.g.:
"launch_handlers": [
// Patterns are evaluated in order, until one applies to the url.
{ "url_pattern": <..pattern..>,
"client_mode": "focus-existing" },
{ "url_pattern": <...pattern..>,
"client_code": "never_capture" },
...
// the pattern could be for exteneded urls! so we could say that an
// extended scope, for example, never captures.
// to maintain backwards compatibility, if none apply, the "launch_handler" entry is used as the default
],IDK if this is better - to NOT capture something into the app, you have to specify a handler for it.
Questions here would be for backwards compatibility in general too - all solutions need to make sure that old versions or chrome don't break - e.g. the manifest parser doesn't 'throw away' the manifest if it fails to parse something here (I don't think that's the case for most of this)
There was a problem hiding this comment.
Interesting. I've not thought about specifying capturing scope from launch_handlers before. Will investigate.
There was a problem hiding this comment.
Do you think this current doc is solution-agnostic enough to be merged?
| | 1 | Cannot exclude paths from scope | New manifest members for scope include/exclude lists | | ||
| | 2 | Navigation capture scope ≡ app scope | Separate "capture scope" concept (Layer 2) | | ||
| | 3 | Single launch behavior for all URLs | URL-pattern-keyed launch handlers (Layer 2) | | ||
| | 4 | `scope_extensions` lacks feature annotations | Per-origin opt-in/out in association file | |
There was a problem hiding this comment.
Maybe another way to say what I said above is - maybe we can flatten the concept of the per-origin opt-in and opt-out into the same concept of specializing launch handling per url, by introducing a 'never-capture' value? But maybe there are reasons to not do that?
|
|
||
| ### Layer 2 — In-App Behavior (fine-grained) | ||
|
|
||
| This layer answers: *"Now that we know this URL is part of the app, how should the browser handle it?"* This is where richer pattern matching (potentially `URLPattern`) becomes appropriate, because evaluation happens inside the browser after the OS has already routed the URL to the app. |
There was a problem hiding this comment.
If I'm following correctly, we're also talking about this 'layer' being where we think about a clicked link within the app, which we don't know yet if "this URL is part of the app". Small wording tweak suggestion:
| This layer answers: *"Now that we know this URL is part of the app, how should the browser handle it?"* This is where richer pattern matching (potentially `URLPattern`) becomes appropriate, because evaluation happens inside the browser after the OS has already routed the URL to the app. | |
| This layer answers: *"Now that we are in the app, how should the browser handle this URL?"* This is where richer pattern matching (potentially `URLPattern`) becomes appropriate, because evaluation happens inside the browser after the OS has already routed the URL to the app. |
|
|
||
| **Why it matters.** Different areas of an app have different interaction models. Forcing a single launch behavior leads to UX compromises: either users lose context when an existing window is reused for unrelated content, or they accumulate unnecessary windows when every launch opens a new one. | ||
|
|
||
| **What developers need.** The ability to specify **multiple launch handlers**, each associated with a set of URL patterns, so launch behavior can be tailored to the content being opened. |
There was a problem hiding this comment.
Is URL scoping enough? I'm wondering if the app might want to factor in even more dynamic information, like "what URL is my current app page on"? (e.g. YouTube PWA wants to open a video link in the current window if nothing is playing, but if something is playing wants to pause it and open a new window).
If so, this might be more wholistically solved by giving the app more permissions within the context of its launch handler. Namely, letting it easily launch a new window of itself with params similar to the LaunchParams it received.
| This layer answers: *"Does this URL belong to the application?"* It determines install-time registration with the OS, deep-link routing, and display-mode application. Because it must map to OS-level URL filtering (Android intent filters, Windows protocol/URI handling, etc.), it should remain **simple** — path prefixes, origin lists, and at most basic include/exclude patterns. | ||
|
|
||
| Design constraints: | ||
| - Must be expressible using primitives that operating systems support for URL filtering. Prior work on the (now-obsolete) [`pwa-url-handler` explainer](https://github.com/WICG/pwa-url-handler/blob/main/explainer.md#os-specific-implementation-notes) documented these OS mechanisms: Android [intent filters](https://developers.google.com/web/fundamentals/integration/webapks?hl=ro#android_intent_filters) via WebAPK, Windows ["Apps for Websites"](https://docs.microsoft.com/en-us/windows/uwp/launch-resume/web-to-app-linking), and iOS/macOS [Universal Links](https://developer.apple.com/ios/universal-links/). All are origin- or prefix-based — none support regex or complex pattern matching — which bounds the expressiveness of this layer. |
There was a problem hiding this comment.
FWIW - A browser could choose to support a more complex syntax at this layer, and attempt to best-effort translate it to the OS it is on, erring on the side of a broader capture, with a fall-back of trying to have it handled in the browser. I wouldn't recommend it for a v1, but worth considering as a potential future while designing the API shape.
So for example, on Windows or iOS/macOS the browser might try to break it into include/exclude paths with basic wildcards, whereas on Android it wouldn't have an 'exclude' option. In any case the browser would always check the URL at launch time, and if it didn't match the more complex syntax provided by the PWA it would launch it in the browser mode instead. (Or if it wanted to be super fancy, it could attempt to look up the default browser and forward it along to that. Should be possible on at least Windows, though likely not on Android/iOS).
|
|
||
| **Why it matters.** Navigation capturing is an all-or-nothing proposition today: it applies to every URL inside scope. Developers cannot differentiate between "this URL is part of my app" and "this URL should pull the user into the app window when clicked externally." These are distinct intents, and conflating them forces developers into workarounds (e.g., moving content to a different origin). | ||
|
|
||
| **What developers need.** A mechanism to define a **capture scope** that is a subset of (or different from) the application scope — controlling which URLs trigger navigation capturing independently of which URLs render in the app window. |
There was a problem hiding this comment.
I would lean into the 'different' rather than 'subset' direction. Though a very contrived case, I could imagine wanting to capture a URL activation, but still show it as 'outside the scope of the app' in the UI. Possibly for something like an old URL location that now attempts to guide you to the new URL, but less aggressively than an automatic redirect.
| **What developers need.** A mechanism to define a **capture scope** that is a subset of (or different from) the application scope — controlling which URLs trigger navigation capturing independently of which URLs render in the app window. | |
| **What developers need.** A mechanism to define a **capture scope** that is different from the application scope — controlling which URLs trigger navigation capturing independently of which URLs render in the app window. |
|
Chat at blinkon:
proposal from me would likely put all controls in manifest and only delegate to the scope extension the 'scope filtering' part? eg.g the scope member field and any new fields we add to modify scope for exlucsion etc, but then the 'UX behavior' bits with capturing and launch customization etc be in the manifest, and just have it able to specify url patterns or whatever that include extendeds origin. BUT - alternative should be docujented to have this be in the scope extensions dict area. We then should consult with T&S about what they think. Is this blocking? or likely ok? adding fields to better specify scope in both manifest and scope extensions dict sounds appropriate. other origins can specify the scope more fine-grained. but the actuall UX controls over launch handlign and capturing IN that scope can not make any situation "worse" for that extended scope origin than today (from a t&s point of view) -it's just making the app more UX-robust. So it seems fine to have all of that in the manifest not need to ,say, put a 'launch_handler' member field in the scope_extensions dict. |
Describe problems app developers face with the current manifest scope model and propose a two-layer scope architecture to address them.