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

docs / windows_pwa_integration.md [blame]

# Windows Progressive Web App integration

## Desktop Shortcuts
When a Progressive Web App (PWA) is installed on Windows, Chrome creates a
desktop shortcut to the PWA, with the PWA icon. The shortcut launches a small
Chrome binary chrome_proxy.exe with the app id of the PWA, and the Chrome
profile the PWA is installed in. When chrome_proxy.exe runs, it launches Chrome
with the same command line options. The shortcut links to chrome_proxy.exe
instead of chrome.exe because of
 [a bug in Windows 10 start menu pinning](https://source.chromium.org/chromium/chromium/src/+/main:chrome/chrome_proxy/chrome_proxy_main_win.cc;l=23).

## File handling support
In order to make Progressive Web Apps (PWA's) more like traditional apps, PWA's
support opening files on the user's desktop. On Windows, when a PWA is
installed, if the PWA's manifest lists one or more file extension types that it
supports opening, Chrome registers the PWA as a handler for the file
extension(s), in the Windows registry. When the user right clicks on a file with
a registered extension, the PWA name and custom icon appears in the list of
applications that can open the file. The user can also set the PWA as the
default handler for the file extension.

Because of a limitation of the Windows shell, Chrome registers a per-PWA install 
[launcher app](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/web_applications/chrome_pwa_launcher/README.md;l=1) 
 as a handler for the file extension. Chrome ships with a canonical launcher app
 called chrome_pwa_launcher.exe, which lives in the version sub-directory of the
 Chrome install dir. When a PWA is installed, we create a hard link from the
 PWA install dir `<profile_dir>/Web Applications/<app_id>` to the canonical launcher
 app. If the hard link fails (e.g., Chrome install dir is on a different drive
 than the profile dir), we copy the launcher app to the PWA install dir. In either
 case, the name of the launcher app in the PWA install dir is a sanitized version
 of the PWA name.

Registration starts in [web_app::RegisterFileHandlersWithOS](https://source.chromium.org/search?q=RegisterFileHandlersWithOS%20file:_win.cc&sq=),
 and works as follows: we create a unique
 [ProgID](https://docs.microsoft.com/en-us/windows/win32/com/-progid--key)
 for the PWA installation with the following format:
`<BaseAppId>.<hash(Profile + AppID)>`
We use the hash due to 32-character limit for ProgID's. The registry work is
done in
[ShellUtil::AddFileAssociations](https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/util/shell_util.cc?q=%20ShellUtil::AddFileAssociations):

* Register the ProgID by adding key `HKCU\Software\Classes\<progID>` to the registry.
* Set the application name and icon for the PWA with these two keys:
    * `HKCU\Software\Classes\<progID>\Application::ApplicationIcon = <path to icon in PWA install dir>,0`
    * `HKCU\Software\Classes\<progID>\Application::ApplicationName = <PWA name>`
* Hook up the command to launch the launcher app
    * `HKCU\Software\Classes\<progID>\shell\open\command = <launcher_app_path_in_profile> --app-id=<app_id> --profile-directory=<profile_dir>`
* Add a key to keep track of the file extensions registered for a progId,
for ease of uninstallation:
    * `HKCU\Software\Classes\<progID>\File Extensions = <semicolon delimited list of extensions>`

When Chrome is launched, it writes its path into the "Last Browser" file in
the User Data dir.
When the launcher app is run, it launches Chrome using the path written into the
"Last Browser" file. Because the launcher app is in a sub-directory of the profile
directory, the "Last Browser" file is in its great grandparent directory.

When a new version of Chrome is installed, we need to update the hard links
to and copies of the installed launcher apps to use the newly installed canonical
launcher app. This is done by having the launcher app pass its version to Chrome, when
launching Chrome. If the launcher app is out of date, Chrome updates all the
launcher apps in the current user data dir.

When a PWA is uninstalled, we unregister the PWA as a handler for the file
extensions it was registered for. When a PWA changes the file extensions it can
handle, we update the registry.

## Miscellaneous
 * If the same PWA is registered in multiple profiles, we distinguish them by
adding the profile name in parentheses to the PWA name, e.g,
"Example PWA (profile1)". If a PWA is uninstalled from a  profile, and there is
one remaining install in another profile, we remove the profile name from the
application name.
 * Windows 7 does not support some of the registry entries needed to set the
 name and icon for a PWA. So, the file open context menu item for a PWA on
 Windows 7 gets its name from the launcher app created for the PWA, and uses a
 generic PWA icon.