Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite installation process and install prompting logic #790

Merged
merged 14 commits into from
Sep 26, 2019
220 changes: 122 additions & 98 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,35 @@ <h2>
and again as an example, the user agent could <a>install</a> the web
application into a list of bookmarks within the user agent itself.
</p>
<p>
A {{Document}} may either be <dfn>installable</dfn> or not. The initial
state of a document is non-<a>installable</a>.
mgiuca marked this conversation as resolved.
Show resolved Hide resolved
</p>
<p>
At any time, the user agent MAY perform the <dfn>steps to determine
installability of the document</dfn>:
</p>
<ol>
<li>Let <var>manifest</var> and <var>manifest URL</var> be the result
of <a>obtaining the manifest</a>.
</li>
<li>If <a>obtaining the manifest</a> results in an error, the user
agent MAY either:
<ol>
<li>Fall back to using the <a>top-level browsing context</a>
{{Document}}'s metadata to to populate <var>manifest</var> in a
user-agent-specific way (e.g., setting
<var>manifest</var>.<a data-link-for="WebAppManifest">`name`</a> to
mgiuca marked this conversation as resolved.
Show resolved Hide resolved
the document <a data-cite="HTML#the-title-element">`title`</a>) and
considering the document <a>installable</a>, or
mgiuca marked this conversation as resolved.
Show resolved Hide resolved
</li>
<li>Consider the document non-<a>installable</a>.
mgiuca marked this conversation as resolved.
Show resolved Hide resolved
</li>
</ol>
</li>
<li>Otherwise, the {{Document}} is considered <a>installable</a>.
</li>
</ol>
<section>
<h3>
Authority of the manifest's metadata
Expand Down Expand Up @@ -334,77 +363,52 @@ <h3>
<h3>
Installation process
</h3>
<p>
An <dfn>installation process</dfn> is an attempt by the user agent to
<a>install</a> a web application. The details of such a process
(i.e., the display of an install <abbr>UI</abbr>, and any resulting
<abbr>IO</abbr> operations of the host <abbr>OS</abbr>) are left up
to implementers. Implementers need to be aware that there are
<a href="#installation-sec">privacy and security considerations</a>
that directly relate to the <a>installation process</a>.
</p>
<p>
For the purpose of this specification, the <dfn>installation
succeeded</dfn> once the <a>installation process</a> succeeds in
<a>installing</a> the web application (e.g., an icon was successfully
placed onto the device's homescreen). If the end-user cancels the
installation process (even if they <a>manually</a> triggered it, and
then changed their minds), then the <dfn>installation was
canceled</dfn>. Otherwise, the <dfn>installation failed</dfn>.
Reasons for installation failure can include, for example, the OS
denying permission to the user agent to add an icon to the homescreen
of the device and the end-user rejecting the installation.
</p>
<p>
The <dfn>steps to install the web application</dfn> are given by the
following algorithm:
</p>
<ol>
<li>Let <var>window</var> be the {{Window}} object of the
<a>top-level browsing context</a> for which the user agent will
attempt installation.
<li>Let <var>manifest</var> and <var>manifest URL</var> be the values
that were created during <a>steps to determine installability of the
document</a>.
Copy link
Collaborator

Choose a reason for hiding this comment

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

whether the document is installable ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think this phrasing is OK, given that we also define "installability signals" (keeping it this way implies that the two are connected, which they are).

</li>
<li>Then, <a>in parallel</a>:
<li>If <var>manifest URL</var> exists, and the result of running <a>
processing the `serviceworker` member</a> with <var>manifest</var>
returns a valid <var>registration</var>, the user agent MAY:
<ol>
<li>Instantiate an <a>installation process</a>.
</li>
<li>Let <a>manifest</a> and <a>manifest URL</a> be the result of
<a>obtaining the manifest</a>.
</li>
<li>If <a>obtaining the manifest</a> results in an error, a user
agent can, at this point, fall back to using the <a>top-level
browsing context</a> {{Document}}'s metadata to populate an
<a>installation process</a>'s UI.
</li>
<li>If <a>obtaining the manifest</a> succeeds, and the result of
running <a>processing the `serviceworker` member</a> with
<a>manifest</a> returns a valid <var>registration</var>, a user
agent can at this point:
<ol>
<li>Let <var>client</var> be the <a>top-level browsing
context</a> {{Document}}'s <a>relevant settings object</a>,
or <code>null</code> if unavailable.
</li>
<li>Invoke <a>Start Register</a> with <var>scope</var> and
<var>src</var> members of the <var>registration</var>, a new
<var>promise</var>, <var>client</var>, <a>manifest URL</a>,
plus the <var>type</var> and <var>update_via_cache</var>
members of the <var>registration</var>, in which case the
state of the settled <var>promise</var> determines whether
the <a>installation succeeded</a> or not.
</li>
</ol>
</li>
<li>If the <a>installation succeeded</a>, <a>queue a task</a> on
the <a>application life-cycle task source</a> to <a>fire an
event</a> named <code>appinstalled</code> at the
<var>window</var> object.
<li>Let <var>client</var> be the <a>top-level browsing
context</a> {{Document}}'s <a>relevant settings object</a>, or
<code>null</code> if unavailable.
</li><!-- Start Register no longer exists in the Service Worker
mgiuca marked this conversation as resolved.
Show resolved Hide resolved
spec. -->
<li>Invoke <a>Start Register</a> with <var>scope</var> and <var>
src</var> members of the <var>registration</var>, a new
<var>promise</var>, <var>client</var>, <var>manifest URL</var>,
plus the <var>type</var> and <var>update_via_cache</var>
members of the <var>registration</var>. If the settled
<var>promise</var> is rejected, abort these steps.
</li>
</ol>
</li>
<li>Perform an unspecified sequence of actions to attempt to register
the web application in the user's operating system (e.g., create
shortcuts that launch the web application, register the application
in the system uninstall menu, etc.). If the installation fails (which
can be for any reason, for example, the OS denying permission to the
user agent to add an icon to the home screen of the device), abort
these steps.
</li>
<li>
<a>Queue a task</a> on the <a>application life-cycle task
source</a> to <a>fire an event</a> named <code>appinstalled</code>
at the the {{Window}} object of the <a>top-level browsing
context</a> for which the installation took place.
</li>
</ol>
</section>
<section>
<!-- TODO(mgiuca): Move this section up above Installation process. (In
a separate PR; otherwise it would be too hard to review.) -->
<h2>
Install prompts
</h2>
Expand All @@ -414,41 +418,59 @@ <h2>
</p>
<ul>
<li>An end-user can <dfn data-lt="manual installation">manually</dfn>
trigger the <a>installation process</a> through the user agent's
<abbr>UI</abbr>.
</li>
<li>The <a>installation process</a> can occur through an
<dfn>automated install prompt</dfn>: that is, a <abbr>UI</abbr> that
the user agent presents to the user when, for instance, there are
sufficient <a>installability signals</a> to warrant
<a>installation</a> of the web application.
</li>
<li>The <a>installation process</a> can occur through a
<dfn>site-triggered install prompt</dfn>: the site can
programmatically request that the user agent present an install
prompt to the user. The user agent MAY restrict the availability of
this feature to cases where, for instance, there are sufficient
trigger the installation process through the user agent's
<abbr>UI</abbr>, directly invoking the steps to <a>present an install
mgiuca marked this conversation as resolved.
Show resolved Hide resolved
prompt</a>.
</li>
<li>The installation process can occur through an <dfn>automated
install prompt</dfn>: that is, a <abbr>UI</abbr> that the user agent
mgiuca marked this conversation as resolved.
Show resolved Hide resolved
presents to the user when, for instance, there are sufficient
<a>installability signals</a> to warrant <a>installation</a> of the
web application.
</li>
<li>The installation process can occur through a <dfn>site-triggered
install prompt</dfn>: the site can programmatically request that the
user agent present an install prompt to the user. The user agent MAY
restrict the availability of this feature to cases where, for
instance, there are sufficient <a>installability signals</a> to
warrant <a>installation</a> of the web application.
</li>
</ul>
<p>
In any case, the user agent MUST NOT <a>present an install prompt</a>
if the document is not <a>installable</a>.
</p>
<p>
Prior to presenting an <a>automated install prompt</a>, a user agent
MUST run the <a>steps to notify that an install prompt is
available</a>, to give the site the opportunity to prevent the
default action (which is to install the application). Alternatively,
the user agent MAY run the <a>steps to notify that an install prompt
is available</a> at any time, giving the site the opportunity to show
a <a>site-triggered install prompt</a> without automatically showing
the prompt.
the user agent MAY, at any time (only if the document is
<a>installable</a>), run the <a>steps to notify that an install
prompt is available</a> at any time, giving the site the opportunity
to show a <a>site-triggered install prompt</a> without automatically
showing the prompt.
</p>
<p>
In either case, when a user agent <dfn data-lt=
"present an install prompt|presenting an install prompt">presents an
install prompt</dfn>, the end-user's choice is represented either
"accepted" or "dismissed". These values are represented in the API of
this specification via the <a>AppBannerPromptOutcome</a> enum.
To <dfn data-lt="presenting an install prompt">present an install
prompt</dfn>:
</p>
<ol>
<li>Show some user-agent-specific UI, asking the user whether to
proceed with installing the app. See <a href=
"#installation-sec">privacy and security considerations</a> for
recommendations relating to this UI. The <var>result</var> of this
choice is either <a data-link-for=
"AppBannerPromptOutcome">accepted</a> or <a data-link-for=
"AppBannerPromptOutcome">dismissed</a>.
</li>
<li>If <var>result</var> is <a data-link-for=
"AppBannerPromptOutcome">accepted</a>, then in parallel, run the <a>
steps to install the web application</a>.
</li>
<li>Return <var>result</var>.
Copy link
Member

Choose a reason for hiding this comment

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

This is ambiguous: is result returned before "in parallel" runs, or after? As it reads (to me), it's returning before, which I think is incorrect, right?

Copy link
Collaborator Author

@mgiuca mgiuca Sep 12, 2019

Choose a reason for hiding this comment

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

It's intended to be before (i.e., your reading is correct). I don't think it's ambiguous: that's precisely the meaning of "in parallel" (otherwise I wouldn't have said "in parallel").

The result of "present an install prompt" should be the user's choice, not the success of the installation. The result of this promise reflects the user's choice, whereas the appinstalled event reflects whether it was actually installed.

At least, that was my intention. Now I'm not so sure. Looking at Chrome's app_banner_manager, the code that sends BannerAccepted (which results in the promise resolving with "accepted") has a comment:

  // Catch only kSuccessNewInstall and kUserInstallDeclined. Report nothing on
  // all other errors.

implying that maybe we resolve with "accepted" if the user accepts AND installation is success, and perhaps we never resole if the user accepts and installation fails??? @dominickng Can you confirm what Chrome is doing here?

We should decide what the (currently unspecified) behaviour should be if the user accepts the banner but the installation fails: if we want to resolve with "accepted" then the proposed text is correct. If not, we should delete "in parallel" and figure out what to resolve with (perhaps we should introduce a new "accepted-but-failed" result)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Discussed with @dominickng. Chrome does:

  • On Android, it resolves with "accepted" as soon as the user chooses to install, regardless of whether the installation actually succeeds (matching the proposed "in parallel" text).
  • On Windows / Chrome OS / Linux / macOS, if the user accepts and the install "fails", the promise won't resolve. But the failures are all very much edge cases (like something has gone horribly wrong, or the web contents is destroyed, etc), not expected to happen in normal situations. We would consider these edge cases Chrome bugs if they happened. For all intents and purposes, the proposed "in parallel" text matches our behaviour.

So I would prefer to keep this as-is.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, alternative:

<li>Return |result| and in parallel: .... 

That way it's clear that in parallel goes off to do other things independently of |result|.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

OK that works.

</li>
</ol>
<p>
The <dfn>steps to notify that an install prompt is available</dfn>
are given by the following algorithm:
Expand All @@ -457,9 +479,10 @@ <h2>
<li>Wait until the {{Document}} of the <a>top-level browsing
context</a> is <a>completely loaded</a>.
</li>
<li>If there is already an <a>installation process</a> being
<a data-lt="present an install prompt">presented</a>, terminate this
algorithm.
<li>If there is already an <a data-lt=
Copy link
Member

Choose a reason for hiding this comment

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

We probably need need some kind of internal slot to track this, which can be reset as part of task once installation completes (and can hook into manual installation)... we don't need to do it as part of this PR tho.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yep. You're tracking this at #761 so I thought I'd just leave it for now.

Similarly, we should probably add an internal slot for "is installable" since that's a document-global property that I'm adding, but I didn't want to do it in this PR.

"present an install prompt">install prompt being presented</a> or if
marcoscaceres marked this conversation as resolved.
Show resolved Hide resolved
the <a>steps to install the web application</a> are currently being
executed, terminate this algorithm.
</li>
<li>
<a>Queue a task</a> on the <a>application life-cycle task
Expand Down Expand Up @@ -487,14 +510,15 @@ <h3 id="installation-sec">
Privacy and security considerations
</h3>
<p>
During the <a>installation process</a>, it is RECOMMENDED that the
user agent allow the end-user to inspect the icon, name, <a>start
URL</a>, origin, etc. pertaining to a web application. This is to
give an end-user an opportunity to make a conscious decision to
approve, and possibly modify, the information pertaining to the web
application before installing it. This also gives the end-user an
opportunity to discern if the web application is spoofing another web
application, by, for example, using an unexpected icon or name.
During the <a data-lt="present an install prompt">presentation of the
mgiuca marked this conversation as resolved.
Show resolved Hide resolved
install prompt</a>, it is RECOMMENDED that the user agent allow the
end-user to inspect the icon, name, <a>start URL</a>, origin, etc.
pertaining to a web application. This is to give an end-user an
opportunity to make a conscious decision to approve, and possibly
modify, the information pertaining to the web application before
installing it. This also gives the end-user an opportunity to discern
if the web application is spoofing another web application, by, for
example, using an unexpected icon or name.
</p>
<p>
It is RECOMMENDED that user agents prevent other applications from
Expand Down Expand Up @@ -608,10 +632,10 @@ <h3>
<div class="note">
If the <a>BeforeInstallPromptEvent</a> is <em>not</em> cancelled, the
user agent is allowed to <a data-lt=
"presents an install prompt">present an automated install prompt</a>
"present an install prompt">present an automated install prompt</a>
to the end-user. Canceling the default action (via <a data-cite=
"DOM#dom-event-preventdefault">preventDefault</a>) prevents the user
agent from <a data-lt="presents an install prompt">presenting an
agent from <a data-lt="present an install prompt">presenting an
automated install prompt</a>. The user agent is free to run <a>steps
to notify that an install prompt is available</a> again at a later
time.
Expand Down Expand Up @@ -728,8 +752,8 @@ <h4>
</h4>
<p>
The <dfn>AppBannerPromptOutcome</dfn> enum's values represent the
outcomes from <a data-lt="presents an install prompt">presenting
the end-user with an install prompt</a>.
outcomes from <a data-lt="present an install prompt">presenting the
end-user with an install prompt</a>.
</p>
<dl data-dfn-for="AppBannerPromptOutcome">
<dt>
Expand Down Expand Up @@ -786,8 +810,8 @@ <h4>
attribute</a> for the "<dfn>appinstalled</dfn>" event type. The
interface used for these events is the <a><code>Event</code>
interface</a> [[DOM]]. This event is dispatched as a result of a
<a data-lt="installation succeeded">successful installation</a>
(see the <a>steps to install the web application</a>).
successful installation (see the <a>steps to install the web
application</a>).
</p>
</section>
<section data-dfn-for="Window">
Expand Down