From babddbf811f17bc7b9d91880d3055b218d69cb5c Mon Sep 17 00:00:00 2001 From: Mister Magoo Date: Thu, 15 Aug 2019 02:38:54 +0100 Subject: [PATCH] See CHANGELOG for details - added Blazor interop for install notification --- .../Blazor.PWA.MSBuild.Tasks.csproj | 2 + ...w_register-beforeinstallprompt.template.js | 9 +++ ...sw_register-installable-banner.template.js | 10 +-- ...sw_register-installable-blazor.template.js | 17 +++++ .../ServiceWorker/sw_register.template.js | 9 --- ...rPWA.MSBuild.ServiceWorkerRegister.targets | 32 ++++++++- CHANGELOG.md | 12 +++- README.md | 67 ++++++++++++++++++- 8 files changed, 139 insertions(+), 19 deletions(-) create mode 100644 Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-beforeinstallprompt.template.js create mode 100644 Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-installable-blazor.template.js diff --git a/Blazor.PWA.MSBuild.Tasks/Blazor.PWA.MSBuild.Tasks.csproj b/Blazor.PWA.MSBuild.Tasks/Blazor.PWA.MSBuild.Tasks.csproj index 3ca3918..51883d9 100644 --- a/Blazor.PWA.MSBuild.Tasks/Blazor.PWA.MSBuild.Tasks.csproj +++ b/Blazor.PWA.MSBuild.Tasks/Blazor.PWA.MSBuild.Tasks.csproj @@ -69,7 +69,9 @@ I will add more network caching strategies, but for now it has just one - cache + + diff --git a/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-beforeinstallprompt.template.js b/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-beforeinstallprompt.template.js new file mode 100644 index 0000000..cca06aa --- /dev/null +++ b/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-beforeinstallprompt.template.js @@ -0,0 +1,9 @@ +window.addEventListener('beforeinstallprompt', function (e) { + // Prevent Chrome 67 and earlier from automatically showing the prompt + e.preventDefault(); + // Stash the event so it can be triggered later. + window.PWADeferredPrompt = e; + + showAddToHomeScreen(); + +}); diff --git a/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-installable-banner.template.js b/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-installable-banner.template.js index 16ec412..10d5456 100644 --- a/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-installable-banner.template.js +++ b/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-installable-banner.template.js @@ -6,15 +6,15 @@ function showAddToHomeScreen() { pwaInstallPrompt.id = 'pwa-install-prompt'; pwaInstallPrompt.style.position = 'absolute'; - pwaInstallPrompt.style.bottom = '1rem'; - pwaInstallPrompt.style.left = '1rem'; - pwaInstallPrompt.style.right = '1rem'; - pwaInstallPrompt.style.padding = '0.3rem'; + pwaInstallPrompt.style.bottom = '0.1rem'; + pwaInstallPrompt.style.left = '0.1rem'; + pwaInstallPrompt.style.right = '0.1rem'; + pwaInstallPrompt.style.padding = '0.5rem'; pwaInstallPrompt.style.display = 'flex'; pwaInstallPrompt.style.backgroundColor = 'lightslategray'; pwaInstallPrompt.style.color = 'white'; pwaInstallPrompt.style.fontFamily = 'sans-serif'; - pwaInstallPrompt.style.fontSize = '1.2rem'; + pwaInstallPrompt.style.fontSize = '1.3rem'; pwaInstallPrompt.style.borderRadius = '4px'; pwaInstallButton.style.marginLeft = 'auto'; diff --git a/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-installable-blazor.template.js b/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-installable-blazor.template.js new file mode 100644 index 0000000..205b773 --- /dev/null +++ b/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register-installable-blazor.template.js @@ -0,0 +1,17 @@ + +function showAddToHomeScreen() { + DotNet.invokeMethodAsync(blazorAssembly, blazorInstallMethod) + .then(function () { }, function (er) { setTimeout(showAddToHomeScreen, 1000); }); +} + +window.BlazorPWA = { + installPWA: function () { + if (window.PWADeferredPrompt) { + window.PWADeferredPrompt.prompt(); + window.PWADeferredPrompt.userChoice + .then(function (choiceResult) { + window.PWADeferredPrompt = null; + }); + } + } +}; diff --git a/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register.template.js b/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register.template.js index 4841f70..f107874 100644 --- a/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register.template.js +++ b/Blazor.PWA.MSBuild.Tasks/Templates/ServiceWorker/sw_register.template.js @@ -24,12 +24,3 @@ } }); -window.addEventListener('beforeinstallprompt', function (e) { - // Prevent Chrome 67 and earlier from automatically showing the prompt - e.preventDefault(); - // Stash the event so it can be triggered later. - window.PWADeferredPrompt = e; - - showAddToHomeScreen(); - -}); diff --git a/Blazor.PWA.MSBuild.Tasks/build/BlazorPWA.MSBuild.ServiceWorkerRegister.targets b/Blazor.PWA.MSBuild.Tasks/build/BlazorPWA.MSBuild.ServiceWorkerRegister.targets index 2f87cee..229734d 100644 --- a/Blazor.PWA.MSBuild.Tasks/build/BlazorPWA.MSBuild.ServiceWorkerRegister.targets +++ b/Blazor.PWA.MSBuild.Tasks/build/BlazorPWA.MSBuild.ServiceWorkerRegister.targets @@ -20,17 +20,30 @@ installable-banner $(ServiceWorkerRegisterTemplatePath)sw_register-$(ServiceWorkerRegisterInstallableType).template.js + + beforeinstallprompt + + $(ServiceWorkerRegisterTemplatePath)sw_register-$(ServiceWorkerRegisterBeforeInstallPromptType).template.js installed Update available. Reload the page when convenient. + + $(ProjectName) + + PWAInstallable - + const serviceWorkerFileName = '$(ServiceWorkerBaseURL)$(ServiceWorkerFileName)'%3B; const swInstalledEvent = '$(ServiceWorkerInstalledEvent)'%3B; const staticCachePrefix = '$(ServiceWorkerCacheName)-v'%3B; const updateAlertMessage = '$(ServiceWorkerUpdateAlertText)'%3B; + + $(ServiceWorkerRegisterConstants); + const blazorAssembly = '$(ServiceWorkerBlazorAssembly)'%3B; + const blazorInstallMethod = '$(ServiceWorkerBlazorInstallMethod)'%3B; + @@ -45,7 +58,24 @@ + + + + + + + +

Install this app?

+ + +} +``` +This will display a bar at the bottom of the browser, which can be dismissed or clicked. + + +The `code` section has the `JSInvokable` method **InstallPWS** that we called +earlier from the browser and some supporting code to toggle the display and +make an interop call back to the browser to trigger the app installation. +``` C# +@code +{ + [Inject] IJSRuntime JSRuntime { get; set; } + + static bool Installable = false; + static Action ml; + protected override void OnInitialized() + { + ml = () => InvokeAsync(StateHasChanged); + } + [JSInvokable] + public static Task InstallPWA() + { + Installable = true; + ml.Invoke(); + return Task.CompletedTask; + } + Task InstallClicked(UIMouseEventArgs args) + { + Installable = false; + return JSRuntime.InvokeAsync("BlazorPWA.installPWA"); + } +} +``` + ## Roadmap - [ ] At the moment, there is only one choice for caching strategy - Cache First/Network Fallback - I will add more (https://developers.google.com/web/ilt/pwa/introduction-to-progressive-web-app-architectures#caching_strategies_supported_by_sw-toolbox) -- [ ] The current methods for alerting the user are semi-hard coded (you can adjust them manually after generation) - this will change to allow hooks/callbacks into Blazor via project properties +- [x] The current method for alerting the user that the app is installable is semi-hard coded (you can adjust it manually after generation) - this will change to allow hooks/callbacks into Blazor via project properties +- [ ] The current method for alerting the user when an update is available is semi-hard coded (you can adjust it manually after generation) - this will change to allow hooks/callbacks into Blazor via project properties - [ ] Document all of the configuration Properties (they all have comments in the code - so you are able to understand their purpose without documentation...) - [ ] Bug fixes