[Web Install] duplicates BIP
Hi Diego,
just following up after meeting with @dmurph and we identified potential blocker for .install() API as currently proposed.
There are a number of issues:
-
A precondition of
.install()is that the manifest has loaded, which causes race condition with user/transient activation: transient activation might expire before the manifest has loaded. Also, if .install() must meet any conditions to be called, and it throws, then it's the user that is left frustrated because there's an install button there, but it fails when pressed. -
There is significant usage of BIP, which Chromium has changed to be deterministic.
The preconditions for installing are that there be a manifest, possibly that it has an ID, and maybe other browser specific things. Also, calling .install() should result in the install sheet/prompt being shown.
If BIP has a significant amount of usage, and it meets the requirements, and it’s causing site-compat issues with Safari, we should probably fix BIP and not introduce a new mechanism that does effectively the same thing.
Thoughts?
BIP would only solve the same-document install case, and the API is quite unusual (receiving the prompt from an event). As a web developer, it would be quite nice to just have navigator.install(). This matches the vendors' consensus that installations should always be possible, regardless of certain preconditions such as a manifest being present.
So, it should be fine to just call navigator.install() to bring up the install dialog. The install dialog could still fetch the manifest or apply the default manifest for the given site (I think this is what Safari does). However, this would also mean that no restrictions, like a manifest ID being present, can be imposed.
To prevent buttons that aren't actually able to install another manifest, and to check the presence of an ID, and maybe for future-proofing such as for cross-origin installs, we could also consider a navigator.canInstall() method, as suggested before.
Related: https://github.com/w3c/manifest/pull/1175
Answer to 1) is that the transient activation is consumed by the install API call, not by the manifest loading. In a way BIP makes transient activation harder here instead of easier.
The .install method could do a reasonable wait for the manifest link to be added or know that a manifest is being downloaded. In that case the promise would be pending. If the process throws for whatever reason and causes the promise to reject, the site can know and just update the UI accordingly and either offer to navigate or resolve it in a different way.
BIP depends on the UA, and there's no guarantee that the event will fire. Additionally, as Christian points out this only works for the current loaded document. Thinking about developer ergonomics, it seems better to have a way to do .install() in a way that proves effective and not by waiting and having to prevent/intercept an unreliable event.
I see the install method as the way forward to acquire apps on both mobile and desktop, with a simpler approach than that of BIP and easier to futureproof if we wanted to standardize installing content from another origin or web bundles or whatever comes our way.
@dmurph assured me that BIP is deterministic in Chromium. Can someone point to Chromium’s code? MDN is not an authoritative source.
@marcoscaceres are there any meeting notes from this meeting you had with @dmurph ? It is hard to followup on this conversation without context, special on a feature that my team is leading.
No, it was during the Web Manifest Editor's meeting with @dmurph and I... we started doing a deep dive into the API and installation and realized the things above. Let's set up a call if we need to, to discuss in detail.
The .install method could do a reasonable wait for the manifest link to be added or know that a manifest is being downloaded.
If and only if we are ok with progressively loading various parts of the manifest, it's very racy and if the manifest doesn't load, or the icons don't load, you and up with a bad user experience.
From memory:
- This API has some edge cases with things like manifest loading, which means it has to have error handling (which it does in the promise).
- Marcos's request for having the API be impossible to use if there could be inconsistent UX (AKA the dev didn't handle the error right) resembled today's implementation of BIP, as today BIP is deterministic (I believe on Chrome it needs a manifest with icons, but no interaction required anymore)
- We talked a lot about how having the 'id' field required helps encourage devs to not have the footgun of no id / start_url changing issues. Having the authority of the 'id' in multiple places leads to too much confusion on which one should be used, so the manifest's id as the only authority here makes the most sense.
My conclusions:
- In either scenario, the developer can 'get things wrong', but one way to get things wrong is slightly harder in the BIP side (but more complicated in general).
- For BIP - the dev has to have the button not exist? or always show an error to the user before BIP?
- For install API, the dev has to display an error to the user if the install API doesn't work.
- We have received a ton of feedback that the BIP model is not ergonomic and devs hate it, and they just want a simple imperative API with simple rules.
- Personally I think it's OK to have this no-arg version of the API, assuming we report errors back to the dev for things like manifest not linked on the page or manifest on the page not having an id. And I believe the current implementation / API proposes this. Especially given the feedback we've received from developers and partners. Having the API fail with defined & documented errors is a common pattern.
Thanks, appreciate the additional context. The promise indeed provides a way to do error handling for when the manifest doesn't load/isn't found/doesn't have an id, and with this 0 param version of .install() it's possible for a developer to cater UX if an error occurs.
We have heard as well from developers that BIP is not an ergonomic solution for installation of apps. I have also heard from developers that there is interest in having a unifying imperative solution for mobile/desktop to install content. I wasn't aware that BIP doesn't require transient activation anymore, but I still particularly think the install method provides a better solution than BIP.
Happy to set up a joint meeting with the dev team if there are concerns about the API.
For @christianliebel - some additional info about the id footgun is here (and later in that presentation). We've had multiple high profile partners end up in state now where they have multiple 'versions' of their apps in the wild, and can only support / update one of them. Unrecoverable. It's a very easy footgun to hit, and by forcing this to be set for the API to work, we are:
- Removing that error from occuring when using this API
- Educating developers about the existence of the computed id, which they NEED to know about.
- Increasing the # of manifests that specify an
id, making it more normal.
I wish we didn't have to do this, but unfortunately because id wasn't required when the manifests were first introduced, we were forced to make it default-populated by something else as we needed backwards compatibility.
Perhaps an analogy is best here.... This is a faulty analogy but hopefully illustrates the point:
- Pretend you have a nice new e-bike and you live riding it.
- Retroactively, the e-bike added biological pairing support, so it only will 'work' if the owner uses it. (assume this is a good & desired thing for this analogy)
- However, to keep the existing e-bike sales working, the default biological pairing was for the front tire. So all of the old e-bikes keep working, and the new ones also work, and if the user wants (and know about it), they can pair it to their... DNA I guess.
Very few people do this - it's not well documented, and most people jump on to ride it right away, and it has never caused them problems.
It's common for people to want to change their tires. Perhaps a nice new 28mm gravel tire!
However, when users do this, the bike suddenly stops working! Or - rides off into the sunset! What? Why? Well, sorry, the biological pairing failed. And - (for the purposes of the analogy) they can't just put on the old tire anymore to make it work. It's not completely out of their control. oops!
So.... by requiring an 'id' for this API, in the analogy we're saying "Hey, you have to biologically pair the bike to your DNA before you ride it. You'll fail to ride it until you do that". We're requiring something that should have been required from the beginning.
@dmurph Thanks for the insights and the fascinating analogy.
It seems challenging to make web install happen in an interoperable way. Here are some pros and cons for the different approaches:
beforeinstallprompt |
navigator.install() |
|
|---|---|---|
| + |
|
|
| - |
|
|
| ID requirement | |
|---|---|
| + |
|
| - |
|
I suggest discussing this at TPAC, ideally with all vendors on board. I've created an issue for this here: https://github.com/w3c/manifest/issues/1178
As a side note - I do think we should have a way for the developer to fetch the current calculated manifest - e.g. something like document.getManifest() that returns a promise. MAYBE we include metadata there, IDK. But I have heard multiple times from devs that they would like to see this for both production code & tests to make sure things are set up right.
I filed a bug here: https://github.com/w3c/manifest/issues/1179
If this is there, then this COULD be used to check for navigator.install working, either just knowing that the manifest is there, or adding metadata for if install can happen. I personally don't think it is requirements.
@christianliebel said:
Contradicts TPAC 2023 consensus that all websites should be installable (even without a manifest, thus without an ID)
I do think that installable now needs two definitions - installable by user and installable via navigator.install / by dev. I believe that conclusion is still true for installable by user. However, I think it's appropriate to have more stringent requirements for a installable by dev to make sure they are set up correctly for success.
The proposal has evolved with feedback from TAG and other browser vendors, including more recently, the debate over 'computed id'. Unlike oBIP install API needs transient activation. I think there is room for a canInstall or even more generic getManifest that would allow developers to check if the installation is possible, similar to how Web Share works.
About the definition of installable, I agree that there is a difference between a 'user' install (can install any website) and the install API (installs websites with manifests-- web apps*?). Intentionally discussions of what "installation" means have been out of scope of the API, as different platforms handle the concept differenttly. Having said that, any website CAN still be installed by the user through the UA prompt or a menu.
*Related to web applications... it's even tricky to find how are they defined. According to a working draft from W3C on HTML5, "If the page is not a Web application, the application-name metadata name must not be used.". So while there is space to define installation and web app as concepts, I don't this is blocking for an API that was a designed with a requirement for a website to have a manifest id to avoid the issues mentioned earlier with updates.