-
Notifications
You must be signed in to change notification settings - Fork 160
/
index.html
3910 lines (3894 loc) · 155 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>
Web App Manifest
</title>
<script src="https://www.w3.org/Tools/respec/respec-w3c" class=
"remove"></script>
<script class='remove'>
var respecConfig = {
mdn: true,
previousPublishDate: "2013-12-17",
specStatus: "LD",
shortName: "appmanifest",
prevVersion: "FPWD",
previousMaturity: "WD",
formerEditors: [
{
name: "Rob Dolin",
company: "Microsoft Corporation",
companyURL: "https://www.microsoft.com/en-us/",
},
],
editors: [
{
name: "Marcos Caceres",
company: "Mozilla Corporation",
companyURL: "https://mozilla.org/",
w3cid: 39125,
},
{
name: "Kenneth Rohde Christiansen",
company: "Intel Corporation",
companyURL: "https://intel.com/",
w3cid: 57705,
},
{
name: "Mounir Lamouri",
company: "Google Inc.",
companyURL: "https://www.google.com/",
w3cid: 45389,
},
{
name: "Anssi Kostiainen",
company: "Intel Corporation",
companyURL: "https://intel.com/",
w3cid: 41974,
},
{
name: "Matt Giuca",
company: "Google Inc.",
companyURL: "https://www.google.com/",
w3cid: 91260,
},
{
name: "Aaron Gustafson",
company: "Microsoft Corporation",
companyURL: "https://microsoft.com/",
w3cid: 43672,
},
],
wg: "Web Applications Working Group",
wgURI: "https://www.w3.org/2019/webapps/",
wgPatentURI: "https://www.w3.org/2004/01/pp-impl/114929/status",
otherLinks: [
{
key: "Implementation status",
data: [
{
value: "Blink",
href: "https://www.chromestatus.com/feature/6488656873259008",
},
{
value: "EdgeHTML",
href:
"https://developer.microsoft.com/en-us/microsoft-edge/platform/status/webapplicationmanifest/",
},
{
value: "Gecko",
href: "https://bugzilla.mozilla.org/show_bug.cgi?id=997779",
},
{
value: "WebKit",
href: "https://bugs.webkit.org/show_bug.cgi?id=158205",
},
],
},
],
github: "https://github.com/w3c/manifest/",
caniuse: {
feature: "web-app-manifest",
browsers: [
"chrome",
"firefox",
"safari",
"edge",
"and_chr",
"and_ff",
"ios_saf",
],
},
xref: "web-platform"
};
</script>
<style>
.icon-title {
text-transform: uppercase;
font-weight: bold;
}
.icons {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.icons > div {
text-align: left;
padding: 10px;
width: 188px;
}
.icons > div > img {
width: 188px;
height: 188px;
min-width: 188px;
min-height: 188px;
}
</style>
</head>
<body data-cite="ENCODING">
<section id='abstract'>
<p>
This specification defines a JSON-based manifest file that provides
developers with a centralized place to put metadata associated with a
web application. This metadata includes, but is not limited to, the web
application's name, links to icons, as well as the preferred URL to
open when a user launches the web application. The manifest also allows
developers to declare a default orientation for their web application,
as well as providing the ability to set the display mode for the
application (e.g., in fullscreen). Additionally, the manifest allows a
developer to "scope" a web application to a URL. This restricts the
URLs to which the manifest is applied and provides a means to "deep
link" into a web application from other applications.
</p>
<p>
Using this metadata, user agents can provide developers with means to
create user experiences that are more comparable to that of a native
application.
</p>
<p>
This specification also defines the `manifest` link type as a
declarative means to associate a document with a manifest.
</p>
</section>
<section id="sotd">
<div class="warning">
<p>
Implementors need to be aware that this specification is not stable.
However, aspects of this specification are shipping in at least one
browser (see links to implementation status at the top of this
document). <strong>Implementors who are not taking part in the
discussions will find the specification changing out from under them
in incompatible ways.</strong> Vendors interested in implementing
this specification before it eventually reaches the Candidate
Recommendation phase should <a href=
"https://github.com/w3c/manifest/issues">subscribe to the repository
on GitHub</a> and take part in the discussions.
</p>
</div>
</section>
<section class="informative">
<h2>
Usage Examples
</h2>
<p>
This section shows how developers can make use of the various features
of this specification.
</p>
<section class="informative">
<h3>
Example manifests
</h3>
<p>
The following shows a very simple <a>manifest</a>.
</p>
<pre class="example json" title="very simple manifest">
{
"name": "Donate App",
"description": "This app helps you donate to worthy causes.",
"icons": [{
"src": "images/icon.png",
"sizes": "192x192"
}]
}
</pre>
<p>
The following shows a more typical <a>manifest</a>.
</p>
<pre class="example json" title="typical manifest">
{
"lang": "en",
"dir": "ltr",
"name": "Super Racer 3000",
"description": "The ultimate futuristic racing game from the future!",
"short_name": "Racer3K",
"icons": [{
"src": "icon/lowres.webp",
"sizes": "64x64",
"type": "image/webp"
},{
"src": "icon/lowres.png",
"sizes": "64x64"
}, {
"src": "icon/hd_hi",
"sizes": "128x128"
}],
"scope": "/racer/",
"start_url": "/racer/start.html",
"display": "fullscreen",
"orientation": "landscape",
"theme_color": "aliceblue",
"background_color": "red",
"serviceworker": {
"src": "sw.js",
"scope": "/racer/",
"update_via_cache": "none"
},
"screenshots": [{
"src": "screenshots/in-game-1x.jpg",
"sizes": "640x480",
"type": "image/jpeg"
},{
"src": "screenshots/in-game-2x.jpg",
"sizes": "1280x920",
"type": "image/jpeg"
}]
}
</pre>
</section>
<section class="informative">
<h3>
Using a `link` element to link to a manifest
</h3>
<p>
Example of using a [^link^] element to associate a website with a
<a>manifest</a>. The example also shows how to use [[HTML]]'s
[^link^] and <a data-tl="meta element">`meta`</a> elements to give
the web application a fallback name and set of icons.
</p>
<pre class="example html" title="linking to a manifest">
<!doctype>
<html>
<title>Racer 3K</title>
<!-- Startup configuration -->
<link rel="manifest" href="manifest.webmanifest">
<!-- Fallback application metadata for legacy browsers -->
<meta name="application-name" content="Racer3K">
<link rel="icon" sizes="16x16 32x32 48x48" href="lo_def.ico">
<link rel="icon" sizes="512x512" href="hi_def.png">
</pre>
<div class="note" title="manifest.webmanifest or manifest.json?">
The official file extension for the manifest is `.webmanifest`. Some
web servers recognize this extension and transfer the file using the
standardized <a>media type for a manifest</a>
(`application/manifest+json`). Developers can also choose a different
extension (e.g. `.json`) or none at all (e.g. `/api/GetManifest`),
but are strongly encouraged to transfer the manifest using the
`application/manifest+json` media type.
</div>
</section>
</section>
<section>
<h2>
Installable web applications
</h2>
<p>
A common use case of a manifest is for a user agent to <dfn data-lt=
"installing|installed|installation" data-export="">install</dfn> a web
application; whereby the user agent provides the end-user with a means
of instantiating a new <a>top-level browsing context</a> that has the
manifest's members <a>applied</a> to it. That is, the manifest's
members, or their defaults, are in effect on the <a>top-level browsing
context</a>. This distinguishes an installed web application from a
traditional bookmark, as opening a web page from a traditional bookmark
will not have the manifest's properties <a>applied</a> to it.
</p>
<p>
For example, on user agents that support installation, a web
application could be presented and launched in a way that, to the
end-user, is indistinguishable from native applications: such as
appearing as a labeled icon on the home screen, launcher, or start
menu. When launched, the manifest is <a>applied</a> by the user agent
to the <a>top-level browsing context</a> prior to the <a>start URL</a>
being loaded. This gives the user agent an opportunity to apply the
relevant values of the manifest, possibly changing the <a>display
mode</a> and screen orientation of the web application. Alternatively,
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 not <a>installable</a>.
</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
|manifest|.{{WebAppManifest/name}} to the document <a data-cite=
"HTML#the-title-element">`title`</a>) and considering the document
<a>installable</a>.
</li>
<li>Or, consider the document not <a>installable</a>.
</li>
</ol>
</li>
<li>Otherwise, the {{Document}} MAY be considered <a>installable</a>
(at the user agent's discretion; see [[[#installability-signals]]]).
</li>
</ol>
<section>
<h3>
Authority of the manifest's metadata
</h3>
<p>
When a <a>manifest</a> is linked from a {{Document}}, it indicates to
the user agent that the metadata is <dfn>authoritative</dfn>: that
is, the user agent SHOULD use the metadata of the manifest instead of
the one in the {{Document}}. However, in cases where metadata is
missing, or in error, a user agent MAY fallback to the {{Document}}
to find suitable replacements for missing manifest members (e.g.,
using `application-name` in place of `short_name`).
</p>
</section>
<section data-link-for="WebAppManifest">
<h3>
Application's name
</h3>
<p>
The <dfn>application's name</dfn> is derived from either the
<a>name</a> member or <a>short_name</a> member (if either is present)
- otherwise, it is generated by the user agent or provided by the
end-user.
</p>
<p>
When either member is missing from the manifest, a user agent MAY use
the <a>name</a> member as a fallback for the <a>short_name</a> member
or vice versa.
</p>
<p>
If the <a>name</a> and <a>short_name</a> members are undefined, the
user agent SHOULD assign a default name (e.g., "Untitled") that
follows platform conventions. Alternatively, a user agent MAY allow
the end-user to input some text that can serve as the
<a>application's name</a>.
</p>
<p>
When both the <a>name</a> and <a>short_name</a> members are present,
it is left up to implementations to decide which member is best
suited for the space available (e.g., the <a>short_name</a> member
might be better suited for the space available underneath an icon).
</p>
</section>
<section>
<h3>
Installation process
</h3>
<p>
The <dfn>steps to install the web application</dfn> are given by the
following algorithm:
</p>
<ol>
<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>.
</li>
<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>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>, <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>
<div class="issue" data-number="789"></div>
</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>
<p>
There are multiple ways that the installation process can be
triggered:
</p>
<ul>
<li>An end-user can <dfn data-lt="manual installation">manually</dfn>
trigger the installation process through the user agent's
<abbr title="User Interface">UI</abbr>, directly invoking the steps
to <a>present an install prompt</a>.
</li>
<li>The installation process can occur through an <dfn>automated
install prompt</dfn>: that is, a UI 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 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, 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>
To <dfn data-lt=
"presenting an install prompt|presentation of the 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>Return <var>result</var>, and <a>in parallel</a>:
<ol>
<li>If <var>result</var> is <a data-link-for=
"AppBannerPromptOutcome">accepted</a>, run the <a>steps to
install the web application</a>.
</li>
</ol>
</li>
</ol>
<p>
The <dfn>steps to notify that an install prompt is available</dfn>
are given by the following algorithm:
</p>
<ol>
<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 data-lt=
"present an install prompt">install prompt being presented</a> or if
the <a>steps to install the web application</a> are currently being
executed, then abort this step.
</li>
<li>
<a>Queue a task</a> on the <a>application life-cycle task
source</a> to do the following:
<ol>
<li>Let <var>event</var> be a newly constructed
<a>BeforeInstallPromptEvent</a> named
<code>beforeinstallprompt</code>, with its
<code>cancelable</code> attribute initialized to true.
</li>
<li>Let <var>mayShowPrompt</var> be the result of <a>firing</a>
<var>event</var> at the {{Window}} object of the <a>top-level
browsing context</a>.
</li>
<li>If <var>mayShowPrompt</var> is true, then the user agent MAY,
<a>in parallel</a>, <a>request to present an install prompt</a>
with <var>event</var>.
</li>
</ol>
</li>
</ol>
</section>
<section>
<h3 id="installation-sec">
Privacy and security considerations
</h3>
<p>
During the <a>presentation of the 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
determining which applications are installed on the system (e.g., via
a timing attack on the user agent's cache). This could be done by,
for example, invalidating from the user agent's cache the resources
linked to from the manifest (for example, icons) after a web
application is <a>installed</a> - or by using an entirely different
cache from that used for regular web browsing.
</p>
</section>
<section class="informative">
<h3 id="installability-signals">
Installability signals
</h3>
<p>
By design, this specification does not provide developers with an
explicit API to "install" a web application. Instead, a
<a>manifest</a> can serve as an <dfn>installability signal</dfn> to a
user agent that a web application can be <a>installed</a>.
</p>
<p>
Examples of <a>installability signals</a> for a web application:
</p>
<ul>
<li>is <a>associated with a manifest</a> with at least a
<code>name</code> member and a suitable icon.
</li>
<li>is served over a secure network connection.
</li>
<li>has a sensible content security policy.
</li>
<li>is able to responsively adapt to display on a variety of screen
sizes, catering for both mobile and desktop.
</li>
<li>is able to function without a network connection.
</li>
<li>is repeatedly used by the end-user over some extended period of
time.
</li>
<li>has been explicitly marked by the user as one that they value and
trust (e.g., by bookmarking or "starring" it).
</li>
</ul>
<p>
This list is not exhaustive and some <a>installability signals</a>
might not apply to all user agents. How a user agent makes use of
these <a>installability signals</a> to determine if a web application
can be <a>installed</a> is left to implementers.
</p>
</section>
<section>
<h3>
Uninstallation
</h3>
<p>
User agents SHOULD provide a mechanism for the user to remove the
installed application.
</p>
<p>
It is RECOMMENDED that at the time of removal, the user agent also
present the user with an opportunity to revoke other persistent data
and settings associated with the application, such as permissions and
persistent storage.
</p>
</section>
</section>
<section class="atrisk">
<h2>
Installation Events
</h2>
<p>
Installation events and supporting the {{BeforeInstallPrompt}} is
OPTIONAL.
</p>
<p>
DOM events <a>fired</a> by this specification use the <dfn>application
life-cycle task source</dfn>.
</p>
<section data-dfn-for="BeforeInstallPromptEvent" data-link-for=
"BeforeInstallPromptEvent">
<h3>
<dfn>BeforeInstallPromptEvent</dfn> Interface
</h3>
<div class="note">
The <a>beforeinstallprompt</a> event is somewhat misnamed, as it does
not necessarily signal that an <a>automated install prompt</a> will
follow (depending on the user agent, it might just be giving the site
the ability to trigger an install prompt). It is so named for
historical reasons.
</div>
<pre class="idl" data-cite="DOM">
[Exposed=Window]
interface BeforeInstallPromptEvent : Event {
constructor(DOMString type, optional EventInit eventInitDict = {});
Promise<PromptResponseObject> prompt();
};
dictionary PromptResponseObject {
AppBannerPromptOutcome userChoice;
};
enum AppBannerPromptOutcome {
"accepted",
"dismissed"
};
</pre>
<p>
The <a>BeforeInstallPromptEvent</a> is dispatched when the site is
allowed to present a <a>site-triggered install prompt</a>, or prior
to the user agent presenting an <a>automated install prompt</a>. It
allows the site to cancel the <a>automated install prompt</a>, as
well as manually present the <a>site-triggered install prompt</a>.
</p>
<div class="note">
If the <a>BeforeInstallPromptEvent</a> is <em>not</em> cancelled, the
user agent is allowed to <a>present an install prompt</a>
(specifically, an <a>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>presenting an 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.
</div>
<p data-dfn-for="PromptResponseObject">
The <dfn>PromptResponseObject</dfn> contains the result of calling
<a data-lt="BeforeInstallPromptEvent.prompt()">prompt()</a>. It
contains one member, <dfn data-link-for=
"PromptResponseObject">userChoice</dfn>, which states the user's
chosen outcome.
</p>
<p>
An instance of a <a>BeforeInstallPromptEvent</a> has the following
internal slots:
</p>
<dl>
<dt>
<dfn>[[\didPrompt]]</dfn>
</dt>
<dd>
A boolean, initially <code>false</code>. Represents whether this
event was used to <a>present an install prompt</a> to the end-user.
</dd>
<dt>
<dfn>[[\userResponsePromise]]</dfn>
</dt>
<dd>
A promise that represents the outcome of <a>presenting an install
prompt</a>.
</dd>
</dl>
<section>
<h4>
<code>prompt()</code> method
</h4>
<p>
The <dfn>prompt</dfn> method, when called, runs the following
steps:
</p>
<ol>
<li>If <var>this</var>.<a>[[\userResponsePromise]]</a> is pending:
<ol>
<li>If this event's <a data-cite=
"DOM#dom-event-istrusted"><code>isTrusted</code></a> attribute
is <code>false</code>, reject
<var>this</var>.<a>[[\userResponsePromise]]</a> with
{{"NotAllowedError"}}, optionally informing the developer that
untrusted events can't call <code>prompt()</code>.
</li>
<li>Else if <var>this</var>.<a>[[\didPrompt]]</a> is
<code>false</code>, set <var>this</var>.<a>[[\didPrompt]]</a>
to <code>true</code>, then <a>in parallel</a>, <a>request to
present an install prompt</a> with this event. Wait, possibly
indefinitely, for the end-user to make a choice.
</li>
</ol>
</li>
<li>Return <var>this</var>.<a>[[\userResponsePromise]]</a>.
</li>
</ol>
<p>
To <dfn data-noexport="">request to present an install prompt</dfn>
with <a>BeforeInstallPromptEvent</a> <var>event</var>:
</p>
<ol>
<li>
<a>Present an install prompt</a> and let <var>outcome</var> be
the result.
</li>
<li>Resolve <var>event</var>.<a>[[\userResponsePromise]]</a> with a
newly created <a>PromptResponseObject</a> whose <a data-link-for=
"PromptResponseObject">userChoice</a> member is the value of <var>
outcome</var>.
</li>
</ol>
</section>
<section class="informative">
<h4>
Usage example
</h4>
<p>
This example shows how one might prevent an automated install
prompt from showing until the user clicks a button to show a
<a>site-triggered install prompt</a>. In this way, the site can
leave installation at the user's discretion (rather than prompting
at an arbitrary time), whilst still providing a prominent UI to do
so.
</p>
<pre class="example" title=
"Using beforeinstallprompt to present an install button">
window.addEventListener("beforeinstallprompt", event => {
// Suppress automatic prompting.
event.preventDefault();
// Show the (disabled-by-default) install button. This button
// resolves the installButtonClicked promise when clicked.
installButton.disabled = false;
// Wait for the user to click the button.
installButton.addEventListener("click", async e => {
// The prompt() method can only be used once.
installButton.disabled = true;
// Show the prompt.
const { userChoice } = await event.prompt();
console.info(`user choice was: ${userChoice}`);
});
});
</pre>
</section>
<section data-dfn-for="AppBannerPromptOutcome">
<h4>
<code>AppBannerPromptOutcome</code> enum
</h4>
<p>
The <dfn>AppBannerPromptOutcome</dfn> enum's values represent the
outcomes from <a>presenting an install prompt</a>.
</p>
<dl data-dfn-for="AppBannerPromptOutcome">
<dt>
<dfn>accepted</dfn>:
</dt>
<dd>
The end-user indicated that they would like the user agent to
<a>install</a> the web application.
</dd>
<dt>
<dfn>dismissed</dfn>:
</dt>
<dd>
The end-user dismissed the install prompt.
</dd>
</dl>
</section>
</section>
<section>
<h3>
Extensions to the <code>Window</code> object
</h3>
<p>
The following extensions to the <code><dfn data-cite=
"HTML/window-object.html#window">Window</dfn></code> object specify
the <a>event handler idl attribute</a> on which events relating to
the <a>installation</a> of a web application are <a>fired</a>.
</p>
<pre class="idl" data-cite="HTML">
partial interface Window {
attribute EventHandler onappinstalled;
attribute EventHandler onbeforeinstallprompt;
};
</pre>
<pre class="example js" title=
"Two ways of handling the 'appinstalled' event">
function handleInstalled(ev) {
const date = new Date(ev.timeStamp / 1000);
console.log(`Yay! Our app got installed at ${date.toTimeString()}.`);
}
// Using the event handler IDL attribute
window.onappinstalled = handleInstalled;
// Using .addEventListener()
window.addEventListener("appinstalled", handleInstalled);
</pre>
<section data-dfn-for="Window">
<h4>
<code>onappinstalled</code> attribute
</h4>
<p>
The <dfn>onappinstalled</dfn> is an <a>event handler IDL
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
successful installation (see the <a>steps to install the web
application</a>).
</p>
</section>
<section data-dfn-for="Window">
<h4>
<code>onbeforeinstallprompt</code> attribute
</h4>
<p>
The <dfn>onbeforeinstallprompt</dfn> is an <a>event handler IDL
attribute</a> for the "<dfn>beforeinstallprompt</dfn>" event type.
The interface used for these events is the
<a>BeforeInstallPromptEvent</a> interface (see the <a>steps to
notify that an install prompt is available</a>).
</p>
</section>
</section>
</section>
<section>
<h2>
Navigation scope
</h2>
<p data-link-for="WebAppManifest">
A <dfn>navigation scope</dfn> is a <a>URL</a> that represents the set
of URLs to which an <a>application context</a> can be navigated while
the manifest is <a>applied</a>. The <a>navigation scope</a> of a
manifest <var>manifest</var> is <var>manifest</var>["<a>scope</a>"].
</p>
<div class="note" data-link-for="WebAppManifest">
<p>
If the <a>scope</a> member is not present in the manifest, it
defaults to the parent path of the <a>start_url</a> member. For
example, if <a>start_url</a> is <code>/pages/welcome.html</code>, and
<a>scope</a> is missing, the navigation scope will be
<code>/pages/</code> on the same origin. If <a>start_url</a> is
<code>/pages/</code> (the trailing slash is important!), the
navigation scope will be <code>/pages/</code>.
</p>
<p>
Developers should take care, if they rely on the default behaviour,
that all of the application's page URLs begin with the parent path of
the start URL. To be safe, explicitly specify <a>scope</a>.
</p>
</div>
<p>
A <a>URL</a> <var>target</var> is said to be <dfn>within scope</dfn> of
<a>navigation scope</a> <var>scope</var> if the following algorithm
returns <code>true</code>:
</p>
<ol>
<li>Let <var>scopePath</var> be the [=string/concatenation=] of
<var>scopes</var>'s <a data-cite="URL#concept-url-path">path</a>, using
U+002F (/).
</li>
<li>Let <var>targetPath</var> be the [=string/concatenation=] of <var>
target</var>'s <a data-cite="URL#concept-url-path">path</a>, using
U+002F (/).
</li>
<li>If <var>target</var> is <a>same origin</a> as <var>scope</var> and
<var>targetPath</var> starts with <var>scopePath</var>, return
<code>true</code>.
</li>
<li>Otherwise, return <code>false</code>.
</li>
</ol>
<p>
A <a>URL</a> <var>target</var> is said to be <dfn data-lt=
"within-scope-manifest">within scope of a manifest</dfn>
<var>manifest</var> if <var>target</var> is <a>within scope</a> of the
navigation scope of <var>manifest</var>.
</p>
<div class="note" title="Scope is a simple string match">
The URL string matching in this algorithm is prefix-based rather than
path-structural (e.g. a target URL string
<code>/prefix-of/resource.html</code> will match an app with scope
<code>/prefix</code>, even though the path segment name is not an exact
match). This is intentional for consistency with <a data-cite=
"SERVICE-WORKERS-1#scope-match-algorithm">Service Workers</a>. To avoid
unexpected behavior, use a scope ending in a <code>/</code>.
</div>
<p>
If the <a>application context</a>'s <a>active document</a>'s
[=Document/URL=] is not <a data-lt="within-scope-manifest">within
scope</a> of the <a>application context</a>'s manifest, the user agent
SHOULD show a prominent UI element indicating the [=Document/URL=] or
at least its <a>origin</a>, including whether it is served over a
secure connection. This UI SHOULD differ from any UI used when the
[=Document/URL=] is <a>within scope</a>, in order to make it obvious
that the user is navigating off scope.
</p>
<div class="note">
<p>
Nothing prevents an <a>application context</a> from navigating to a
<a>URL</a> that is outside of the application's <a>navigation
scope</a>, while still having the <a>manifest</a> <a>applied</a> to
it.
</p>
<p>
Unlike previous versions of this specification, user agents are no
longer required or allowed to block off-scope navigations, or open
them in a new <a>top-level browsing context</a>. This practice broke
some sites that navigate to an off-scope URL (e.g., to perform
third-party authentication). See <a href=
"https://github.com/w3c/manifest/issues/646">Issue 646</a>.
</p>
</div>
<section data-link-for="DisplayModeType">
<h3 id="navigation-scope-security-considerations">
Security considerations
</h3>
<p>
The above recommendation (to show some UI when the <a>application
context</a> is navigated to an out-of-scope <a>URL</a>) is for
security reasons. It ensures that users are always aware of which
<a>origin</a> they are interacting with.
</p>
</section>
<section>
<h3>
Deep links
</h3>
<p>
A <dfn>deep link</dfn> is a URL that is <a data-lt=
"within-scope-manifest">within scope</a> of an <a>installed</a> web
application's manifest.
</p>
<p>
An <a>application context</a> can be instantiated through a <a>deep
link</a>, in which case, the manifest is applied and the <a>deep
link</a> is loaded within the context of a web application.
</p>
<div class="note">
<p>
The concept of a <a>deep link</a> is useful in that it allows
hyperlinking from one installed application to another. This can be
from a native application to an <a>installed</a> web application
(and possibly vice versa!). Theoretically, this can provide
seamless context switching between native and web applications
through standard hyperlinks. And in the case where a particular web
application is not <a>installed</a>, the OS can just open the link
in the user's preferred web browser.
</p>
<p>
Implementers are encouraged make such context switching obvious to
the user, for example, by adhering to the human interface
guidelines of the underlying platform with respect to application
switching.
</p>
</div>
</section>
</section>
<section data-dfn-for="DisplayModeType" data-link-for="DisplayModeType">
<h2>
Display modes
</h2>
<p>
A <dfn>display mode</dfn> represents how the web application is being
presented within the context of an OS (e.g., in fullscreen, etc.).
Display modes correspond to user interface (UI) metaphors and
functionality in use on a given platform. The UI conventions of the
display modes are purely advisory and implementers are free to
interpret them how they best see fit.
</p>
<p>
Once a user agent applies a particular <a>display mode</a> to an
<a>application context</a>, it becomes the <dfn>default display
mode</dfn> for the <a>top-level browsing context</a> (i.e., it is used
as the display mode when the window is <a>navigated</a>). The user
agent MAY override the <a>default display mode</a> for security reasons