WICG / web-app-launch

Web App Launch Handler
Other
75 stars 28 forks source link

Enqueue launch events for every app launch #33

Closed alancutter closed 2 years ago

alancutter commented 3 years ago

In the same vein as https://github.com/w3c/web-share-target/issues/84#issuecomment-865646597:

We can just enqueue the launch event always without any manifest API changes.

I propose that we always enqueue the launch event for any app launch (link capturing, OS app launch, menu shortcuts, file handlers, share target...).

What does this mean for existing-client-navigate vs existing-client-event? It removes the "event" aspect and leaves behind "navigation". If we always enqueue launch events then the behavioural options for the developer become "which app window gets used" and "whether the browser automatically navigates the app window to the launch URL".

Possible restructuring of the API:

"launch_handler": {
  "route_to": "new-client" | "existing-client" | "service-worker",
  "navigate_client": true | false
},
"new_client_url": null | <in-scope url>

new_client_url defaults to start_url if unset/null.

This decomposes the "launching" of the app into two configurable pipeline steps:

alancutter commented 3 years ago

It would be reasonable for the service worker path to override the navigate_client behaviour when it selects a client.

mgiuca commented 3 years ago

I think this is a reasonable take.

I'm not sure what the point of new_client_url is. If I set it to something other than the default, then when would start_url ever be used? Isn't this just ... the same as start URL?

alancutter commented 3 years ago

start_url will be the launch URL for OS app list launches. new_client_url is for sites that want a routing page to process launch event URLs that's more lightweight than their start_url. It's not a necessary component of this proposal though.

mgiuca commented 3 years ago

I'm really liking this. It's good to periodically rethink a design that was rather hastily put together and hasn't really been questioned since I wrote it.

Things that I like about it:

Some other thoughts:

For completeness, pasting a private email from @alancutter here, which explains the mapping from the previous design to the above proposal:

alancutter commented 3 years ago

I assume the default value for launch_handler is the equivalent of no link capturing

In Chrome's implementation there is no such thing as no link capturing. It's a user choice that the site has no control over (similar to users forcing web apps to open in a window/browser tab). I would reserve this kind of link capturing site configuration to the capture_links manifest field. launch_handler doesn't know about link capturing, link capturing is an app launch callsite that invokes launch handling.

dmurph commented 3 years ago

I like this structure.

Questions:

alancutter commented 3 years ago

Do we imagine that developers want the same settings for all launch events (share, file handlers, etc)? If not, how would we want the API to look to accomplish this?

If we want to provide that granularity I envision just embedding this launch_handler structure in whatever launch surface API wants it to override the general launch_handler behaviour.

"capture_links": {
  "exclude_paths": ["/example"],
  "launch_handler: { "route_to": "existing-client" }
}

Can you put examples of things this API CAN specify that the old one can't?

The old one can't:

This change is less about adding more capabilities and more about decoupling orthogonal concepts from the original DLC concept.

alancutter commented 3 years ago

Great suggestion from glenrob: Remove "route_to": "service-worker" and just always fire the service worker event. The route_to value is what to do if the service worker noops (same for navigate_client).

This makes the service worker event a way of "explaining" the declarative behaviour as a more procedural browser pipeline primitive.

phoglenix commented 3 years ago

So IIUC there are now 4 possible behaviours (please correct me if I'm describing it wrong):

  1. route_to: new-client + navigate_client: true - default+existing behaviour: launches a new instance and navigates to URL
  2. route_to: existing-client + navigate_client: true - "simple single window" behaviour: navigates an existing client to URL
  3. route_to: new-client + navigate_client: false - opens new_client_url and fires an event at it
  4. route_to: existing-client + navigate_client: false - "real app-y" behaviour: fires an event at an existing client

It seems to me that 3 and 4 would be better handled by a service worker event - less overhead and no declaration needed assuming we always fire the SW event, and able to customise the behaviour based on what URL is coming in. What is the advantage of firing the event inside a client instead?

mgiuca commented 3 years ago

So there would still be capture_links? For path overrides, and potentially for putting link-capturing-specific launch_handler in there as well?

In Chrome's implementation there is no such thing as no link capturing. It's a user choice that the site has no control over (similar to users forcing web apps to open in a window/browser tab).

OK, so then what is the default value of launch_handler?

It seems that in Chrome's implementation, launch_handler: undefined or {} will have different behaviour to any explicit value in route_to, right? So maybe even though it's implementation-specific whether capturing happens or not, you are still providing a hint to the browser that you want capturing, by specifying route_to.

alancutter commented 3 years ago

It seems to me that 3 and 4 would be better handled by a service worker event

This would make "navigate_client": false behaviour only accessible from the service worker launch event handler. I think existing-client-event is a common enough desire to warrant a declarative way of getting it without needing SW code. It's important for apps that don't want to lose existing page state.

So there would still be capture_links? For path overrides, and potentially for putting link-capturing-specific launch_handler in there as well?

Yes, if we have any link capturing specific configurations we want to provide e.g. excluding sub paths and link-capture-specific launch_handler as you said.

OK, so then what is the default value of launch_handler?

It should probably be null (or whatever the manifest's equivalent of CSS auto is) so the user agent can have its own default appropriate for the platform its running on (e.g. Android would only support "existing-client").

mgiuca commented 3 years ago

I think existing-client-event is a common enough desire to warrant a declarative way of getting it without needing SW code. It's important for apps that don't want to lose existing page state.

Yes. This was essentially the whole insight behind DLC in the first place, as an evolution on the older sw-launch plans (see the Overview section of the DLC explainer):

sw-launch has been proposed for a number of years and has never made it past a proposal stage, largely due to the complexity involved in both spec and implementation (a complex effort spanning PWAs, service workers, and HTML navigation stack).

We found that almost all launch use cases could be covered by a handful of fixed rules (for example, "choose an existing window in the same app, focus it, and navigate it to the launched URL"). Thus, this proposal, "Declarative Link Capturing", allows sites to choose one of those fixed rules without having to implement custom launch event logic, which should satisfy most use cases, and simplify the implementation in the browser and in all the sites. We leave open the option of expanding into the full launch event later on.

It's not only what we think will be the overwhelmingly common case, but it also means we can ship it without having to do a major implementation project on the guts of the navigation flow (& that follows for all the browser engines).

phoglenix commented 3 years ago

alancutter@ and I chatted about this. I can see the value in the decomposition into 2x2 properties now. They make more sense than the old 3 names (new client navigate (default), existing client event, existing client navigate) in the context that we are always sending the event.

My only remaining note is that "3. route_to: new-client + navigate_client: false" is quite an odd option, and most likely to be handled better by a service worker eventually, so we should avoid adding new_client_url to support that case, just use start_url.

I think the service worker approach wouldn't be much more complex for sites to implement but I can see how it would be more complex for the browser if we have to drop in to SW code to check if the event is handled during the navigation. Possibly we'd want to make that part declarative somehow. This is just musing though. The proposal (except new_client_url) LGTM.

mgiuca commented 3 years ago

@phoglenix Re new_client_url: that was my line of thinking in this comment as well:

But again, "new-client" + false is a weird thing and I'm not sure we need a feature specifically designed around it. Maybe new_client_url doesn't need to be in the initial version.

But I thought Alan explained (must've been privately): new_client_url isn't just used for new_client. It's also used for existing_client when there's no existing client. So it makes sense to have "existing_client" + false (which we expect to be common: it's the new equivalent of existing_client_event), but still have the common case where no window is open, we would spawn a new window at new_client_url. I think most sites will just want this to open start_url, but there is a case for having a lightweight page at new_client_url that does routing to whichever page is being requested, which may be start_url or it could be a share target, shortcut URL, etc. So I definitely see the value of new_client_url.

Having said that, I'm fine if it doesn't appear in the MVP. It isn't crucial.

alancutter commented 3 years ago

I think start_url was intended for use by "app launched from OS app launch surface", I don't think it's very relevent for any of the other ~6 ways of launching a web app. IMO the start_url member is a conceptual sibiling to share_target, new_note_url, shortcuts etc in that it's just configuring its own particular app launch entrypoint.

mgiuca commented 3 years ago

Yes, I agree, in theory / conceptually @alancutter .

However, in practice, I think the start_url is going to be the "main page" of an app, which most apps will want to load before they show any specific content for subpages. I think for the first version, we can always load start_url, then we can always add new_client_url later, with a default value of start_url.

Edit: Which I see you have done in the explainer (NCU is listed as a future work).

phoglenix commented 3 years ago

I think if you want a lightweight page to fire an event at, you're better off with a service worker. new_client_url seems like an awkward midpoint: not necessary for the initial version and not desirable for the ideal version.

mgiuca commented 3 years ago

Well let's talk practical terms.

Say you've got a video chat client with two pages:

  1. The home page that lets users enter a meeting ID, and
  2. The page where meetings take place.

Let's assume both of these pages load non-trivial resources that are unique to that page and not the other. And you want the single-window mode option so if you start a new video call, you focus the existing window and show a dialog asking if the user wants to switch to the new call.

I think in this case the ideal architecture is:

In light of that ... maybe new_client_url is actually needed in the MVP? Or ......

Hurr.... okay so actually, I think this has introduced a bit of a design flaw, @alancutter , when compared to my DLC proposal. In the DLC proposal, existing_client_event would not have navigated to start_url if no window was open; it would just directly open the intended URL. Basically, if no window is open, it behaves as if "navigate-client": true, but if a window is open, it behaves as if "navigate-client": false. There's no way to get that in the new design. Which leads to the above architecture, which let's face it, is pretty complex to reason about and implement (you need to build another lightweight page, which as we've seen with install URLs, is pretty difficult for complex sites, even if it's basically just blank HTML).

So maybe what we need is for navigate-client to be three-valued:

(As a bonus, it removes the awkward "string or Boolean" type that you had with "auto", true and false.)

Now we can map the previous DLC proposal onto the new one:

Then maybe we don't need new_client_url. It would only be used for navigate_client: never, and TBH I'm not sure what you'd ever want that for, though for completeness I'd be OK with including it.

alancutter commented 3 years ago

In CSS spec land they don't let you use true/false, you have to use enum values like visibility: visible and for good reason; booleans are not extensible. I think switching to "always" etc. is a good move and I'm on board with capturing the more complex "navigate if client is new" behaviour.

alancutter commented 2 years ago

This was added to the explainer.