David Bienvenu | 4e6b7d2 | 2020-09-25 02:11:38 | [diff] [blame] | 1 | # Windows Progressive Web App integration |
| 2 | |
| 3 | ## Desktop Shortcuts |
| 4 | When a Progressive Web App (PWA) is installed on Windows, Chrome creates a |
| 5 | desktop shortcut to the PWA, with the PWA icon. The shortcut launches a small |
| 6 | Chrome binary chrome_proxy.exe with the app id of the PWA, and the Chrome |
| 7 | profile the PWA is installed in. When chrome_proxy.exe runs, it launches Chrome |
| 8 | with the same command line options. The shortcut links to chrome_proxy.exe |
| 9 | instead of chrome.exe because of |
| 10 | [a bug in Windows 10 start menu pinning](https://source.chromium.org/chromium/chromium/src/+/master:chrome/chrome_proxy/chrome_proxy_main_win.cc;l=23). |
| 11 | |
| 12 | ## File handling support |
| 13 | In order to make Progressive Web Apps (PWA's) more like traditional apps, PWA's |
| 14 | support opening files on the user's desktop. On Windows, when a PWA is |
| 15 | installed, if the PWA's manifest lists one or more file extension types that it |
| 16 | supports opening, Chrome registers the PWA as a handler for the file |
| 17 | extension(s), in the Windows registry. When the user right clicks on a file with |
| 18 | a registered extension, the PWA name and custom icon appears in the list of |
| 19 | applications that can open the file. The user can also set the PWA as the |
| 20 | default handler for the file extension. |
| 21 | |
| 22 | Because of a limitation of the Windows shell, Chrome registers a per-PWA install |
| 23 | [launcher app](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/web_applications/chrome_pwa_launcher/README.md;l=1) |
| 24 | as a handler for the file extension. Chrome ships with a canonical launcher app |
| 25 | called chrome_pwa_launcher.exe, which lives in the version sub-directory of the |
| 26 | Chrome install dir. When a PWA is installed, we create a hard link from the |
| 27 | PWA install dir `<profile_dir>/Web Applications/<app_id>` to the canonical launcher |
| 28 | app. If the hard link fails (e.g., Chrome install dir is on a different drive |
| 29 | than the profile dir), we copy the launcher app to the PWA install dir. In either |
| 30 | case, the name of the launcher app in the PWA install dir is a sanitized version |
| 31 | of the PWA name. |
| 32 | |
| 33 | Registration starts in [web_app::RegisterFileHandlersWithOS](https://source.chromium.org/search?q=RegisterFileHandlersWithOS%20file:_win.cc&sq=), |
| 34 | and works as follows: we create a unique |
| 35 | [ProgID](https://docs.microsoft.com/en-us/windows/win32/com/-progid--key) |
| 36 | for the PWA installation with the following format: |
| 37 | `<BaseAppId>.<hash(Profile + AppID)>` |
| 38 | We use the hash due to 32-character limit for ProgID's. The registry work is |
| 39 | done in |
| 40 | [ShellUtil::AddFileAssociations](https://source.chromium.org/chromium/chromium/src/+/master:chrome/installer/util/shell_util.cc?q=%20ShellUtil::AddFileAssociations): |
| 41 | |
| 42 | * Register the ProgID by adding `key HKCU\Software\Classes\<progID>` to the registry. |
| 43 | * Set the application name and icon for the PWA with these two keys: |
| 44 | * `HKCU\Software\Classes\<progID>\Application::ApplicationIcon = <path to icon in PWA install dir>,0` |
| 45 | * `HKCU\Software\Classes\<progID>\Application::ApplicationName = <PWA name>` |
| 46 | * Hook up the command to launch the launcher app |
| 47 | * `HKCU\Software\Classes\<progID>\shell\open\command = <launcher_app_path_in_profile> --app-id=<app_id> --profile-directory=<profile_dir>` |
| 48 | * Add a key to keep track of the file extensions registered for a progId, |
| 49 | for ease of uninstallation: |
| 50 | * `HKCU\Software\Classes\<progId>\File Extensions = <semicolon delimited list of extensions>` |
| 51 | |
| 52 | When Chrome is launched, it writes its path into the "Last Browser" file in |
| 53 | the User Data dir. |
| 54 | When the launcher app is run, it launches Chrome using the path written into the |
| 55 | "Last Browser" file. Because the launcher app is in a sub-directory of the profile |
| 56 | directory, the "Last Browser" file is in its great grandparent directory. |
| 57 | |
| 58 | When a new version of Chrome is installed, we need to update the hard links |
| 59 | to and copies of the installed launcher apps to use the newly installed canonical |
| 60 | launcher app. This is done by having the launcher app pass its version to Chrome, when |
| 61 | launching Chrome. If the launcher app is out of date, Chrome updates all the |
| 62 | launcher apps in the current user data dir. |
| 63 | |
| 64 | When a PWA is uninstalled, we unregister the PWA as a handler for the file |
| 65 | extensions it was registered for. When a PWA changes the file extensions it can |
| 66 | handle, we update the registry. |
| 67 | |
| 68 | ## Miscellaneous |
| 69 | * If the same PWA is registered in multiple profiles, we distinguish them by |
| 70 | adding the profile name in parentheses to the PWA name, e.g, |
| 71 | "Example PWA (profile1)". If a PWA is uninstalled from a profile, and there is |
| 72 | one remaining install in another profile, we remove the profile name from the |
| 73 | application name. |
| 74 | * Windows 7 does not support some of the registry entries needed to set the |
| 75 | name and icon for a PWA. So, the file open context menu item for a PWA on |
| 76 | Windows 7 gets its name from the launcher app created for the PWA, and uses a |
| 77 | generic PWA icon. |
| 78 | |