├── wwwroot ├── src │ ├── images │ │ ├── StoreLogo.png │ │ ├── SplashScreen.scale-200.png │ │ ├── LockScreenLogo.scale-200.png │ │ ├── Square44x44Logo.scale-200.png │ │ ├── Wide310x150Logo.scale-200.png │ │ ├── Square150x150Logo.scale-200.png │ │ └── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── css │ │ └── global.css │ ├── index.html │ └── js │ │ └── activation.js └── package.appxmanifest ├── SampleApp_JS ├── App.cs ├── Properties │ ├── AssemblyInfo.cs │ └── Default.rd.xml ├── Package.appxmanifest └── SampleApp_JS.csproj ├── WebView.Interop ├── EventDispatcher.cs ├── Properties │ ├── AssemblyInfo.cs │ └── HybridWebApplication.rd.xml ├── ContactPanelActivatedEventArgs.cs ├── BackgroundActivatedEventArgs.cs ├── ContactPanel.cs ├── WebViewPage.cs ├── WebView.Interop.csproj └── WebUIApplication.cs ├── WebView.Interop.UWP ├── Properties │ ├── AssemblyInfo.cs │ └── WebView.Interop.UWP.rd.xml ├── HybridWebApplication.cs └── WebView.Interop.UWP.csproj ├── LICENSE ├── README.md ├── .gitignore └── WebView.Interop.sln /wwwroot/src/images/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shweaver-MSFT/WebView.Interop/HEAD/wwwroot/src/images/StoreLogo.png -------------------------------------------------------------------------------- /wwwroot/src/images/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shweaver-MSFT/WebView.Interop/HEAD/wwwroot/src/images/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /wwwroot/src/images/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shweaver-MSFT/WebView.Interop/HEAD/wwwroot/src/images/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /wwwroot/src/images/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shweaver-MSFT/WebView.Interop/HEAD/wwwroot/src/images/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /wwwroot/src/images/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shweaver-MSFT/WebView.Interop/HEAD/wwwroot/src/images/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /wwwroot/src/images/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shweaver-MSFT/WebView.Interop/HEAD/wwwroot/src/images/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /wwwroot/src/css/global.css: -------------------------------------------------------------------------------- 1 | /* Element styles */ 2 | body { 3 | margin: 0; 4 | font-family: 'Segoe UI'; 5 | font-size: 10px; 6 | line-height: 14px; 7 | color: #323232; 8 | } 9 | -------------------------------------------------------------------------------- /wwwroot/src/images/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shweaver-MSFT/WebView.Interop/HEAD/wwwroot/src/images/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /wwwroot/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Hybrid Web Application 8 | 9 | 10 | 11 | 12 |
13 | Hello World 14 |
15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /SampleApp_JS/App.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using WebView.Interop.UWP; 3 | 4 | namespace SampleApp_JS 5 | { 6 | sealed partial class App : HybridWebApplication 7 | { 8 | // If building with web code local to the package, make sure to grant WebView access in the appxmanifest. 9 | // 10 | // 11 | // 12 | private static readonly Uri _appSource = new Uri("ms-appx-web:///index.html"); 13 | 14 | static void Main(string[] args) 15 | { 16 | Start(_ => new App()); 17 | } 18 | 19 | public App() : base(_appSource) { } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /WebView.Interop/EventDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Windows.UI.Core; 4 | 5 | namespace WebView.Interop 6 | { 7 | internal static class EventDispatcher 8 | { 9 | private static CoreDispatcher _dispatcher => CoreWindow.GetForCurrentThread()?.Dispatcher; 10 | 11 | public static async void Dispatch(Action action) 12 | { 13 | // already in UI thread: 14 | if (_dispatcher == null || _dispatcher.HasThreadAccess) 15 | { 16 | await Task.Run(action); 17 | } 18 | // not in UI thread, ensuring UI thread: 19 | else 20 | { 21 | await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SampleApp_JS/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SampleApp_JS")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SampleApp_JS")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /WebView.Interop/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("HybridWebApplication")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("HybridWebApplication")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /WebView.Interop.UWP/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WebView.Interop.UWP")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebView.Interop.UWP")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /WebView.Interop/ContactPanelActivatedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using Windows.ApplicationModel.Activation; 2 | using Windows.ApplicationModel.Contacts; 3 | using Windows.Foundation.Metadata; 4 | 5 | namespace WebView.Interop 6 | { 7 | [AllowForWeb] 8 | public sealed class ContactPanelActivatedEventArgs : IActivatedEventArgs 9 | { 10 | private Windows.ApplicationModel.Activation.ContactPanelActivatedEventArgs _contactPanelActivatedEventArgs; 11 | 12 | // IActivatedEventArgs members 13 | public ActivationKind Kind => _contactPanelActivatedEventArgs.Kind; 14 | public ApplicationExecutionState PreviousExecutionState => _contactPanelActivatedEventArgs.PreviousExecutionState; 15 | public SplashScreen SplashScreen => _contactPanelActivatedEventArgs.SplashScreen; 16 | 17 | // IContactPanelActivatedEventArgs members 18 | public Contact Contact => _contactPanelActivatedEventArgs.Contact; 19 | public ContactPanel ContactPanel { get; } 20 | 21 | public ContactPanelActivatedEventArgs(Windows.ApplicationModel.Activation.ContactPanelActivatedEventArgs contactPanelActivatedEventArgs) 22 | { 23 | _contactPanelActivatedEventArgs = contactPanelActivatedEventArgs; 24 | ContactPanel = new ContactPanel(contactPanelActivatedEventArgs.ContactPanel); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SampleApp_JS/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /WebView.Interop/BackgroundActivatedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using Windows.ApplicationModel.Activation; 2 | using Windows.ApplicationModel.Background; 3 | 4 | namespace WebView.Interop 5 | { 6 | /// 7 | /// For whatever reason, BackgroundActivatedEventArgs doesn't extend IActivatedEventArgs like 8 | /// all the other EventArgs classes in Windows.ApplicaitonModel.Activation. 9 | /// 10 | /// This class mushes activation args with the BackgroundActivatedEventArgs for use during app activation in JavaScript. 11 | /// 12 | public sealed class BackgroundActivatedEventArgs : IActivatedEventArgs, IBackgroundActivatedEventArgs 13 | { 14 | private IActivatedEventArgs _activatedEventArgs; 15 | private IBackgroundActivatedEventArgs _backgroundActivatedEventArgs; 16 | 17 | // IActivatedEventArgs members 18 | public ActivationKind Kind => _activatedEventArgs.Kind; 19 | public ApplicationExecutionState PreviousExecutionState => _activatedEventArgs.PreviousExecutionState; 20 | public SplashScreen SplashScreen => _activatedEventArgs.SplashScreen; 21 | 22 | // IBackgroundActivatedEventArgs members 23 | public IBackgroundTaskInstance TaskInstance => _backgroundActivatedEventArgs.TaskInstance; 24 | 25 | public BackgroundActivatedEventArgs(IActivatedEventArgs activatedEventArgs, IBackgroundActivatedEventArgs backgroundActivatedEventArgs) 26 | { 27 | _activatedEventArgs = activatedEventArgs; 28 | _backgroundActivatedEventArgs = backgroundActivatedEventArgs; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /WebView.Interop/ContactPanel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Windows.ApplicationModel.Contacts; 3 | using Windows.Foundation.Metadata; 4 | using Windows.UI; 5 | 6 | namespace WebView.Interop 7 | { 8 | [AllowForWeb] 9 | public sealed class ContactPanel 10 | { 11 | private Windows.ApplicationModel.Contacts.ContactPanel _contactPanel; 12 | 13 | public event EventHandler Closing; 14 | public event EventHandler LaunchFullAppRequested; 15 | 16 | public Color? HeaderColor 17 | { 18 | get => _contactPanel.HeaderColor; 19 | set => _contactPanel.HeaderColor = value; 20 | } 21 | 22 | public ContactPanel(Windows.ApplicationModel.Contacts.ContactPanel contactPanel) 23 | { 24 | _contactPanel = contactPanel; 25 | _contactPanel.LaunchFullAppRequested += ContactPanel_LaunchFullAppRequested; 26 | _contactPanel.Closing += ContactPanel_Closing; 27 | } 28 | 29 | public void ClosePanel() => _contactPanel.ClosePanel(); 30 | 31 | private void ContactPanel_LaunchFullAppRequested(Windows.ApplicationModel.Contacts.ContactPanel sender, ContactPanelLaunchFullAppRequestedEventArgs args) 32 | { 33 | EventDispatcher.Dispatch(() => LaunchFullAppRequested?.Invoke(sender, args)); 34 | } 35 | 36 | private void ContactPanel_Closing(Windows.ApplicationModel.Contacts.ContactPanel sender, ContactPanelClosingEventArgs args) 37 | { 38 | EventDispatcher.Dispatch(() => Closing?.Invoke(sender, args)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /WebView.Interop/Properties/HybridWebApplication.rd.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /wwwroot/src/js/activation.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | var ActivationKind = { 4 | launch: 0 5 | }; 6 | 7 | var ActivationService = function () { 8 | 9 | // Handle app launch activation 10 | function onLaunched(args) { 11 | console.log("Launch activated"); 12 | } 13 | 14 | // Handle a web activation 15 | function onWebActivated(args) { 16 | console.log("Web Activated"); 17 | } 18 | 19 | // The most recent activation args 20 | this.LastActivationArgs; 21 | 22 | // Handles app activation 23 | this.OnActivated = function (args) { 24 | 25 | this.LastActivationArgs = args; 26 | 27 | if (!WebUIApplication) { 28 | onWebActivated(args); 29 | return; 30 | } 31 | 32 | if (args && args.kind !== undefined) { 33 | 34 | switch (args.kind) { 35 | case ActivationKind.launch: onLaunched(args); return; 36 | } 37 | } 38 | 39 | // TODO: Handle activation with invalid/missing args 40 | console.log("Unhandled activation"); 41 | 42 | }.bind(this); 43 | }; 44 | 45 | var activationService = new ActivationService(); 46 | document.activation = activationService; 47 | 48 | // Register for activation 49 | if (WebUIApplication) { 50 | // Hybrid Web Application (WebView) 51 | // Register for activation on injected IWebUIApplication implementation 52 | WebUIApplication.onactivated = activationService.OnActivated; 53 | } 54 | else { 55 | // Running on web, not WebView 56 | activationService.OnActivated(); 57 | } 58 | })(); -------------------------------------------------------------------------------- /WebView.Interop.UWP/Properties/WebView.Interop.UWP.rd.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /SampleApp_JS/Package.appxmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SampleApp_JS 7 | shweaver 8 | images\StoreLogo.png 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /wwwroot/package.appxmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SampleApp_JS 7 | shweaver 8 | images\storelogo.png 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /WebView.Interop/WebViewPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using Windows.ApplicationModel.Activation; 4 | using Windows.UI.Xaml; 5 | using Windows.UI.Xaml.Controls; 6 | 7 | namespace WebView.Interop 8 | { 9 | internal class WebViewPage : Page 10 | { 11 | private readonly Uri _sourceUri = null; 12 | private readonly IActivatedEventArgs _activationArgs = null; 13 | private Windows.UI.Xaml.Controls.WebView _webView = null; 14 | private WebUIApplication _webApp = null; 15 | 16 | public WebViewPage(WebUIApplication webApp, Uri sourceUri, IActivatedEventArgs activationArgs) 17 | { 18 | _webApp = webApp; 19 | _sourceUri = sourceUri; 20 | _activationArgs = activationArgs; 21 | 22 | Loaded += OnLoaded; 23 | } 24 | 25 | private void OnLoaded(object sender, RoutedEventArgs e) 26 | { 27 | Load(); 28 | } 29 | 30 | public void Load() 31 | { 32 | if (_webView == null) 33 | { 34 | _webView = CreateWebView(); 35 | _webView.AddWebAllowedObject(_webApp.GetType().Name, _webApp); 36 | _webView.Source = _sourceUri; 37 | 38 | Content = _webView; 39 | } 40 | } 41 | 42 | public void Unload() 43 | { 44 | Content = null; 45 | UnwireWebViewDiagnostics(_webView); 46 | 47 | if (_webView != null) 48 | { 49 | _webView = null; 50 | } 51 | 52 | GC.Collect(); 53 | } 54 | 55 | private Windows.UI.Xaml.Controls.WebView CreateWebView() 56 | { 57 | var wv = new Windows.UI.Xaml.Controls.WebView(WebViewExecutionMode.SeparateProcess); 58 | wv.Settings.IsJavaScriptEnabled = true; 59 | WireUpWebViewDiagnostics(wv); 60 | return wv; 61 | } 62 | 63 | private void WireUpWebViewDiagnostics(Windows.UI.Xaml.Controls.WebView webView) 64 | { 65 | webView.NavigationStarting += OnWebViewNavigationStarting; 66 | webView.SeparateProcessLost += OnWebViewSeparateProcessLost; 67 | webView.ScriptNotify += OnWebViewScriptNotify; 68 | } 69 | 70 | private void UnwireWebViewDiagnostics(Windows.UI.Xaml.Controls.WebView webView) 71 | { 72 | webView.NavigationStarting -= OnWebViewNavigationStarting; 73 | webView.SeparateProcessLost -= OnWebViewSeparateProcessLost; 74 | webView.ScriptNotify -= OnWebViewScriptNotify; 75 | } 76 | 77 | private async void OnWebViewScriptNotify(object sender, NotifyEventArgs e) 78 | { 79 | if (sender is Windows.UI.Xaml.Controls.WebView wv) 80 | { 81 | //If you want to trigger an exteranl event without passing in a WinRT object, 82 | // use window.external.notify("some string") which will call this method. The string will 83 | // be accessible via e.Value. 84 | } 85 | } 86 | 87 | private void OnWebViewSeparateProcessLost(Windows.UI.Xaml.Controls.WebView sender, WebViewSeparateProcessLostEventArgs args) 88 | { 89 | UnwireWebViewDiagnostics(sender); 90 | } 91 | 92 | private void OnWebViewNavigationStarting(Windows.UI.Xaml.Controls.WebView sender, WebViewNavigationStartingEventArgs args) 93 | { 94 | Debug.WriteLine(args.Uri?.ToString()); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebView.Interop for Windows Web Applications! 2 | 3 | Progressive Web Applications are awesome! They allow a single JavaScript codebase to manifest itself as a native app on multiple platforms. This is super time and cost effective, because devs can spend less time duplicating the same feature on multiple native codebases. On Windows, we achieve this by loading the target web endpoint in a **WWAHost (Windows Web Application Host)** container. This provides the '*same*' experience as a native JavaScript application running on the platform. 4 | 5 | So far so good. So what's the problem? 6 | 7 | ## WWAHost: The real story 8 | 9 | You may have heard that JavaScript apps running in a WWAHost have access to the full set Windows APIs via the injected `window.Windows` object, and can behave like a first class app just like any C# equivalent because they share the same API set... 10 | 11 | This is a lie. 12 | 13 | But a small one. The truth is, the WWAHost does not expose absolutely ALL that the platform has to offer. In a few cases, there are parts of the Windows Universal Platform that simply cannot be interacted with directly from JavaScript. For instance, the My People Contact Panel. Since no option exists on the platform for activating a WWAHost based app in the Contact Panel, this is seemingly a show stopper for apps wanting to leverage the feature, without also forcing them to use a different language (not JavaScript). 14 | 15 | But you may be thinking, 16 | 17 | > "Hey! Why don't I just make a native XAML app with a full view WebView to load my PWA, then interop between the layers to provide support as needed?" 18 | 19 | Those were my thoughts too... 20 | 21 | ## WWAHost != WebView 22 | 23 | I mentioned that PWAs are run in a WWAHost, and a workaround is to use a WebView. Problem is, WWAHost and WebView are not the same thing, and will run the JavaScript app in a slightly different context. Because of this, some actions (like simply registering for activation events) in JavaScript will throw exceptions. 24 | 25 | # Introducing WebView.Interop 26 | 27 | WebView.Interop is an answer to this problem and consists of two primary parts: 28 | 29 | ## 1. WebView.Interop.UWP.HybridWebApplication 30 | 31 | HybridWebApplication extends Windows.UI.Xaml.Application and manages the eventing between the Xaml Application object (which is getting all of the lifecycle events) and the WebView. 32 | 33 | ## 2. WebView.Interop.WebUIApplication 34 | 35 | WebUIApplication may sound familiar. That it is because it shares a class name with the Windows.UI.WebUI.WebUIApplication [https://docs.microsoft.com/en-us/uwp/api/windows.ui.webui.webuiapplication]. It also extends the IWebUIApplication interface, giving it the same signature as well. 36 | 37 | ## How does it work? 38 | 39 | During activation, the HybridWebApplication creates a new WebView and injects it into the window. It then creates a new WebView.Interop.WebUIApplication `[AllowForWeb]` object and injects that into the WebView. From there, the WebView is navigated to the endpoint and the JavaScript app activates within the WebView just as if it were living in a real WWAHost! 40 | 41 | Tadaa! Now you can start integrating your PWA with ALL Windows Universal features, and even create new and exciting hybrid application types. 42 | 43 | # Contributing 44 | This project has adopted the [Microsoft Open Source Code of 45 | Conduct](https://opensource.microsoft.com/codeofconduct/). 46 | For more information see the [Code of Conduct 47 | FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 48 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) 49 | with any additional questions or comments. 50 | -------------------------------------------------------------------------------- /WebView.Interop.UWP/HybridWebApplication.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Windows.ApplicationModel.Activation; 3 | using Windows.UI.Xaml; 4 | 5 | namespace WebView.Interop.UWP 6 | { 7 | public class HybridWebApplication : Application 8 | { 9 | private readonly Uri _source; 10 | private readonly Uri _contactPanelSource; 11 | private readonly WebUIApplication _webUIApplication; 12 | private IActivatedEventArgs _activationArgs; 13 | 14 | public HybridWebApplication(Uri source, Uri contactPanelSource = null) 15 | { 16 | _source = source; 17 | _contactPanelSource = contactPanelSource; 18 | _webUIApplication = new WebUIApplication(this); 19 | 20 | EnteredBackground += HybridWebApplication_EnteredBackground; 21 | LeavingBackground += HybridWebApplication_LeavingBackground; 22 | } 23 | 24 | private void HybridWebApplication_EnteredBackground(object sender, Windows.ApplicationModel.EnteredBackgroundEventArgs e) 25 | { 26 | _webUIApplication.OnEnteredBackground(e); 27 | } 28 | 29 | private void HybridWebApplication_LeavingBackground(object sender, Windows.ApplicationModel.LeavingBackgroundEventArgs e) 30 | { 31 | _webUIApplication.OnLeavingBackground(e); 32 | } 33 | 34 | /// 35 | /// Invoked when the application is launched normally by the end user. Other entry points 36 | /// will be used such as when the application is launched to open a specific file. 37 | /// 38 | /// Details about the launch request and process. 39 | protected override void OnLaunched(LaunchActivatedEventArgs e) 40 | { 41 | OnActivated(e); 42 | } 43 | 44 | protected override void OnActivated(IActivatedEventArgs e) 45 | { 46 | // The ContactPanel cannot be interacted with from JS. Call Launch to load the ContactPanel page in a new WebView. 47 | if (e.Kind == ActivationKind.ContactPanel && _contactPanelSource != null) 48 | { 49 | _webUIApplication.Launch(_contactPanelSource, new ContactPanelActivatedEventArgs(e as Windows.ApplicationModel.Activation.ContactPanelActivatedEventArgs)); 50 | return; 51 | } 52 | 53 | _activationArgs = e; 54 | 55 | if (e.PreviousExecutionState != ApplicationExecutionState.Running || e.PreviousExecutionState != ApplicationExecutionState.Suspended) 56 | { 57 | _webUIApplication.Launch(_source, e); 58 | } 59 | else 60 | { 61 | _webUIApplication.Activate(e); 62 | } 63 | } 64 | 65 | protected void Reactivate() 66 | { 67 | _webUIApplication.Activate(_activationArgs); 68 | } 69 | 70 | protected override void OnBackgroundActivated(Windows.ApplicationModel.Activation.BackgroundActivatedEventArgs args) 71 | { 72 | _webUIApplication.BackgroundActivate(args); 73 | base.OnBackgroundActivated(args); 74 | } 75 | 76 | protected override void OnCachedFileUpdaterActivated(CachedFileUpdaterActivatedEventArgs args) 77 | { 78 | _webUIApplication.CachedFileUpdaterActivate(args); 79 | base.OnCachedFileUpdaterActivated(args); 80 | } 81 | 82 | protected override void OnFileActivated(FileActivatedEventArgs args) 83 | { 84 | _webUIApplication.FileActivate(args); 85 | base.OnFileActivated(args); 86 | } 87 | 88 | protected override void OnFileOpenPickerActivated(FileOpenPickerActivatedEventArgs args) 89 | { 90 | _webUIApplication.FileOpenPickerActivate(args); 91 | base.OnFileOpenPickerActivated(args); 92 | } 93 | 94 | protected override void OnFileSavePickerActivated(FileSavePickerActivatedEventArgs args) 95 | { 96 | _webUIApplication.FileSavePickerActivate(args); 97 | base.OnFileSavePickerActivated(args); 98 | } 99 | 100 | protected override void OnSearchActivated(SearchActivatedEventArgs args) 101 | { 102 | _webUIApplication.SearchActivate(args); 103 | base.OnSearchActivated(args); 104 | } 105 | 106 | protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args) 107 | { 108 | _webUIApplication.ShareTargetActivate(args); 109 | base.OnShareTargetActivated(args); 110 | } 111 | 112 | protected override void OnWindowCreated(WindowCreatedEventArgs args) 113 | { 114 | _webUIApplication.OnWindowCreated(args); 115 | base.OnWindowCreated(args); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /WebView.Interop.UWP/WebView.Interop.UWP.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0} 8 | Library 9 | Properties 10 | WebView.Interop.UWP 11 | WebView.Interop.UWP 12 | en-US 13 | UAP 14 | 10.0.17134.0 15 | 10.0.16299.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | 20 | 21 | AnyCPU 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 27 | prompt 28 | 4 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE;NETFX_CORE;WINDOWS_UWP 36 | prompt 37 | 4 38 | 39 | 40 | x86 41 | true 42 | bin\x86\Debug\ 43 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 44 | ;2008 45 | full 46 | x86 47 | false 48 | prompt 49 | 50 | 51 | x86 52 | bin\x86\Release\ 53 | TRACE;NETFX_CORE;WINDOWS_UWP 54 | true 55 | ;2008 56 | pdbonly 57 | x86 58 | false 59 | prompt 60 | 61 | 62 | ARM 63 | true 64 | bin\ARM\Debug\ 65 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 66 | ;2008 67 | full 68 | ARM 69 | false 70 | prompt 71 | 72 | 73 | ARM 74 | bin\ARM\Release\ 75 | TRACE;NETFX_CORE;WINDOWS_UWP 76 | true 77 | ;2008 78 | pdbonly 79 | ARM 80 | false 81 | prompt 82 | 83 | 84 | x64 85 | true 86 | bin\x64\Debug\ 87 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 88 | ;2008 89 | full 90 | x64 91 | false 92 | prompt 93 | 94 | 95 | x64 96 | bin\x64\Release\ 97 | TRACE;NETFX_CORE;WINDOWS_UWP 98 | true 99 | ;2008 100 | pdbonly 101 | x64 102 | false 103 | prompt 104 | 105 | 106 | PackageReference 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 6.1.5 116 | 117 | 118 | 119 | 120 | {a6c2cc46-285a-4ed6-be42-920664844a3d} 121 | WebView.Interop 122 | 123 | 124 | 125 | 14.0 126 | 127 | 128 | 135 | -------------------------------------------------------------------------------- /WebView.Interop/WebView.Interop.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A6C2CC46-285A-4ED6-BE42-920664844A3D} 8 | winmdobj 9 | Properties 10 | WebView.Interop 11 | WebView.Interop 12 | en-US 13 | UAP 14 | 10.0.17134.0 15 | 10.0.17134.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | 20 | 21 | AnyCPU 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 27 | prompt 28 | 4 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE;NETFX_CORE;WINDOWS_UWP 36 | prompt 37 | 4 38 | 39 | 40 | x86 41 | true 42 | bin\x86\Debug\ 43 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 44 | ;2008 45 | full 46 | x86 47 | false 48 | prompt 49 | 50 | 51 | x86 52 | bin\x86\Release\ 53 | TRACE;NETFX_CORE;WINDOWS_UWP 54 | true 55 | ;2008 56 | pdbonly 57 | x86 58 | false 59 | prompt 60 | 61 | 62 | ARM 63 | true 64 | bin\ARM\Debug\ 65 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 66 | ;2008 67 | full 68 | ARM 69 | false 70 | prompt 71 | 72 | 73 | ARM 74 | bin\ARM\Release\ 75 | TRACE;NETFX_CORE;WINDOWS_UWP 76 | true 77 | ;2008 78 | pdbonly 79 | ARM 80 | false 81 | prompt 82 | 83 | 84 | x64 85 | true 86 | bin\x64\Debug\ 87 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 88 | ;2008 89 | full 90 | x64 91 | false 92 | prompt 93 | 94 | 95 | x64 96 | bin\x64\Release\ 97 | TRACE;NETFX_CORE;WINDOWS_UWP 98 | true 99 | ;2008 100 | pdbonly 101 | x64 102 | false 103 | prompt 104 | 105 | 106 | PackageReference 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 6.1.5 121 | 122 | 123 | 124 | 14.0 125 | 126 | 127 | 128 | 129 | 130 | 137 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | -------------------------------------------------------------------------------- /WebView.Interop.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27729.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebView.Interop", "WebView.Interop\WebView.Interop.csproj", "{A6C2CC46-285A-4ED6-BE42-920664844A3D}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebView.Interop.UWP", "WebView.Interop.UWP\WebView.Interop.UWP.csproj", "{5B1C674E-6013-4A56-8E83-6FDCD8C808B0}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleApp_JS", "SampleApp_JS\SampleApp_JS.csproj", "{0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}" 11 | EndProject 12 | Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "wwwroot", "wwwroot\", "{3D08B5A2-5050-4900-B6E2-291CDEFAACB2}" 13 | ProjectSection(WebsiteProperties) = preProject 14 | TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.0" 15 | Debug.AspNetCompiler.VirtualPath = "/localhost_49474" 16 | Debug.AspNetCompiler.PhysicalPath = "wwwroot\" 17 | Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_49474\" 18 | Debug.AspNetCompiler.Updateable = "true" 19 | Debug.AspNetCompiler.ForceOverwrite = "true" 20 | Debug.AspNetCompiler.FixedNames = "false" 21 | Debug.AspNetCompiler.Debug = "True" 22 | Release.AspNetCompiler.VirtualPath = "/localhost_49474" 23 | Release.AspNetCompiler.PhysicalPath = "wwwroot\" 24 | Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_49474\" 25 | Release.AspNetCompiler.Updateable = "true" 26 | Release.AspNetCompiler.ForceOverwrite = "true" 27 | Release.AspNetCompiler.FixedNames = "false" 28 | Release.AspNetCompiler.Debug = "False" 29 | VWDPort = "49474" 30 | SlnRelativePath = "wwwroot\" 31 | EndProjectSection 32 | EndProject 33 | Global 34 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 35 | Debug|Any CPU = Debug|Any CPU 36 | Debug|ARM = Debug|ARM 37 | Debug|x64 = Debug|x64 38 | Debug|x86 = Debug|x86 39 | Release|Any CPU = Release|Any CPU 40 | Release|ARM = Release|ARM 41 | Release|x64 = Release|x64 42 | Release|x86 = Release|x86 43 | EndGlobalSection 44 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 45 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Debug|ARM.ActiveCfg = Debug|Any CPU 48 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Debug|ARM.Build.0 = Debug|Any CPU 49 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Debug|x64.ActiveCfg = Debug|Any CPU 50 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Debug|x64.Build.0 = Debug|Any CPU 51 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Debug|x86.ActiveCfg = Debug|Any CPU 52 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Debug|x86.Build.0 = Debug|Any CPU 53 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Release|Any CPU.ActiveCfg = Release|Any CPU 54 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Release|Any CPU.Build.0 = Release|Any CPU 55 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Release|ARM.ActiveCfg = Release|Any CPU 56 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Release|ARM.Build.0 = Release|Any CPU 57 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Release|x64.ActiveCfg = Release|Any CPU 58 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Release|x64.Build.0 = Release|Any CPU 59 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Release|x86.ActiveCfg = Release|Any CPU 60 | {A6C2CC46-285A-4ED6-BE42-920664844A3D}.Release|x86.Build.0 = Release|Any CPU 61 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 62 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Debug|Any CPU.Build.0 = Debug|Any CPU 63 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Debug|ARM.ActiveCfg = Debug|ARM 64 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Debug|ARM.Build.0 = Debug|ARM 65 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Debug|x64.ActiveCfg = Debug|x64 66 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Debug|x64.Build.0 = Debug|x64 67 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Debug|x86.ActiveCfg = Debug|x86 68 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Debug|x86.Build.0 = Debug|x86 69 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Release|Any CPU.ActiveCfg = Release|Any CPU 70 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Release|Any CPU.Build.0 = Release|Any CPU 71 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Release|ARM.ActiveCfg = Release|ARM 72 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Release|ARM.Build.0 = Release|ARM 73 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Release|x64.ActiveCfg = Release|x64 74 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Release|x64.Build.0 = Release|x64 75 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Release|x86.ActiveCfg = Release|x86 76 | {5B1C674E-6013-4A56-8E83-6FDCD8C808B0}.Release|x86.Build.0 = Release|x86 77 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Debug|Any CPU.ActiveCfg = Debug|x86 78 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Debug|ARM.ActiveCfg = Debug|ARM 79 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Debug|ARM.Build.0 = Debug|ARM 80 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Debug|ARM.Deploy.0 = Debug|ARM 81 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Debug|x64.ActiveCfg = Debug|x64 82 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Debug|x64.Build.0 = Debug|x64 83 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Debug|x64.Deploy.0 = Debug|x64 84 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Debug|x86.ActiveCfg = Debug|x86 85 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Debug|x86.Build.0 = Debug|x86 86 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Debug|x86.Deploy.0 = Debug|x86 87 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Release|Any CPU.ActiveCfg = Release|x86 88 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Release|ARM.ActiveCfg = Release|ARM 89 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Release|ARM.Build.0 = Release|ARM 90 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Release|ARM.Deploy.0 = Release|ARM 91 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Release|x64.ActiveCfg = Release|x64 92 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Release|x64.Build.0 = Release|x64 93 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Release|x64.Deploy.0 = Release|x64 94 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Release|x86.ActiveCfg = Release|x86 95 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Release|x86.Build.0 = Release|x86 96 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A}.Release|x86.Deploy.0 = Release|x86 97 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 98 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Debug|Any CPU.Build.0 = Debug|Any CPU 99 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Debug|ARM.ActiveCfg = Debug|Any CPU 100 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Debug|ARM.Build.0 = Debug|Any CPU 101 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Debug|x64.ActiveCfg = Debug|Any CPU 102 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Debug|x64.Build.0 = Debug|Any CPU 103 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Debug|x86.ActiveCfg = Debug|Any CPU 104 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Debug|x86.Build.0 = Debug|Any CPU 105 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Release|Any CPU.ActiveCfg = Debug|Any CPU 106 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Release|Any CPU.Build.0 = Debug|Any CPU 107 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Release|ARM.ActiveCfg = Debug|Any CPU 108 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Release|ARM.Build.0 = Debug|Any CPU 109 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Release|x64.ActiveCfg = Debug|Any CPU 110 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Release|x64.Build.0 = Debug|Any CPU 111 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Release|x86.ActiveCfg = Debug|Any CPU 112 | {3D08B5A2-5050-4900-B6E2-291CDEFAACB2}.Release|x86.Build.0 = Debug|Any CPU 113 | EndGlobalSection 114 | GlobalSection(SolutionProperties) = preSolution 115 | HideSolutionNode = FALSE 116 | EndGlobalSection 117 | GlobalSection(ExtensibilityGlobals) = postSolution 118 | SolutionGuid = {90F2C0C9-07C2-4861-AA56-3D7DEF63FAEB} 119 | EndGlobalSection 120 | EndGlobal 121 | -------------------------------------------------------------------------------- /SampleApp_JS/SampleApp_JS.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x86 7 | {0491D9B7-2989-4DA5-8F80-D19D1DA0E40A} 8 | AppContainerExe 9 | Properties 10 | SampleApp_JS 11 | SampleApp_JS 12 | en-US 13 | UAP 14 | 10.0.17134.0 15 | 10.0.17134.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | true 20 | SampleApp_JS_TemporaryKey.pfx 21 | 22 | 23 | true 24 | bin\x86\Debug\ 25 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 26 | ;2008 27 | full 28 | x86 29 | false 30 | prompt 31 | true 32 | 33 | 34 | bin\x86\Release\ 35 | TRACE;NETFX_CORE;WINDOWS_UWP 36 | true 37 | ;2008 38 | pdbonly 39 | x86 40 | false 41 | prompt 42 | true 43 | true 44 | 45 | 46 | true 47 | bin\ARM\Debug\ 48 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 49 | ;2008 50 | full 51 | ARM 52 | false 53 | prompt 54 | true 55 | 56 | 57 | bin\ARM\Release\ 58 | TRACE;NETFX_CORE;WINDOWS_UWP 59 | true 60 | ;2008 61 | pdbonly 62 | ARM 63 | false 64 | prompt 65 | true 66 | true 67 | 68 | 69 | true 70 | bin\x64\Debug\ 71 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 72 | ;2008 73 | full 74 | x64 75 | false 76 | prompt 77 | true 78 | 79 | 80 | bin\x64\Release\ 81 | TRACE;NETFX_CORE;WINDOWS_UWP 82 | true 83 | ;2008 84 | pdbonly 85 | x64 86 | false 87 | prompt 88 | true 89 | true 90 | 91 | 92 | PackageReference 93 | 94 | 95 | 96 | css\global.css 97 | PreserveNewest 98 | 99 | 100 | images\LockScreenLogo.scale-200.png 101 | PreserveNewest 102 | 103 | 104 | images\SplashScreen.scale-200.png 105 | PreserveNewest 106 | 107 | 108 | images\Square150x150Logo.scale-200.png 109 | PreserveNewest 110 | 111 | 112 | images\Square44x44Logo.scale-200.png 113 | PreserveNewest 114 | 115 | 116 | images\Square44x44Logo.targetsize-24_altform-unplated.png 117 | PreserveNewest 118 | 119 | 120 | images\StoreLogo.png 121 | PreserveNewest 122 | 123 | 124 | images\Wide310x150Logo.scale-200.png 125 | PreserveNewest 126 | 127 | 128 | index.html 129 | PreserveNewest 130 | 131 | 132 | js\activation.js 133 | PreserveNewest 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | Designer 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 6.1.4 152 | 153 | 154 | 155 | 156 | {5b1c674e-6013-4a56-8e83-6fdcd8c808b0} 157 | WebView.Interop.UWP 158 | 159 | 160 | 161 | 14.0 162 | 163 | 164 | 171 | -------------------------------------------------------------------------------- /WebView.Interop/WebUIApplication.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Windows.ApplicationModel.Activation; 3 | using Windows.ApplicationModel.Core; 4 | using Windows.Foundation; 5 | using Windows.Foundation.Metadata; 6 | using Windows.System; 7 | using Windows.UI.Xaml; 8 | 9 | namespace WebView.Interop 10 | { 11 | [AllowForWeb] 12 | public sealed class WebUIApplication 13 | { 14 | private bool _isInBackground = false; 15 | private Application _app; 16 | public IActivatedEventArgs LaunchArgs { get; private set; } 17 | 18 | // Occurs when the app is activated. 19 | public event EventHandler Activated; 20 | 21 | // Occurs when the app has begins running in the background (no UI is shown for the app). 22 | public event EventHandler EnteredBackground; 23 | 24 | // Occurs when the app is about to leave the background and before the app's UI is shown. 25 | public event EventHandler LeavingBackground; 26 | 27 | // Occurs when the app is resuming. 28 | public event EventHandler Resuming; 29 | 30 | // Occurs when the app is suspending. 31 | public event EventHandler Suspending; 32 | 33 | // Occurs when the app creates a new window. 34 | public event EventHandler WindowCreated; 35 | 36 | public WebUIApplication(Application app) 37 | { 38 | _app = app; 39 | 40 | _app.EnteredBackground += App_EnteredBackground; 41 | _app.LeavingBackground += App_LeavingBackground; 42 | _app.Resuming += App_Resuming; 43 | _app.Suspending += App_Suspending; 44 | _app.UnhandledException += App_UnhandledException; 45 | } 46 | 47 | ~WebUIApplication() 48 | { 49 | LaunchArgs = null; 50 | 51 | if (Window.Current.Content != null) 52 | { 53 | Window.Current.Content = null; 54 | } 55 | 56 | if (_app != null) 57 | { 58 | _app.EnteredBackground -= App_EnteredBackground; 59 | _app.LeavingBackground -= App_LeavingBackground; 60 | _app.Resuming -= App_Resuming; 61 | _app.Suspending -= App_Suspending; 62 | _app.UnhandledException -= App_UnhandledException; 63 | _app = null; 64 | } 65 | } 66 | 67 | private WebViewPage CreateWebViewPage(Uri sourceUri, IActivatedEventArgs args) 68 | { 69 | var webViewPage = new WebViewPage(this, sourceUri, args); 70 | return webViewPage; 71 | } 72 | 73 | /// 74 | /// 75 | /// 76 | /// 77 | /// 78 | /// 79 | /// 80 | [DefaultOverload] 81 | public void Launch(Uri source, IActivatedEventArgs e) 82 | { 83 | if (e != null) 84 | { 85 | LaunchArgs = e; 86 | } 87 | 88 | // Do not repeat app initialization when the Window already has content, 89 | // just ensure that the window is active 90 | if (!(Window.Current.Content is WebViewPage)) 91 | { 92 | Window.Current.Content = CreateWebViewPage(source, LaunchArgs); 93 | } 94 | 95 | if (!(e is IPrelaunchActivatedEventArgs) || 96 | e is IPrelaunchActivatedEventArgs && (e as IPrelaunchActivatedEventArgs).PrelaunchActivated == false) 97 | { 98 | // Ensure the current window is active 99 | Window.Current.Activate(); 100 | } 101 | } 102 | 103 | /// 104 | /// 105 | /// 106 | /// 107 | /// 108 | public void Launch(Uri source, ContactPanelActivatedEventArgs e) 109 | { 110 | Window.Current.Content = CreateWebViewPage(source, e); 111 | 112 | // Ensure the current window is active 113 | Window.Current.Activate(); 114 | } 115 | 116 | /// 117 | /// Activation handlers 118 | /// 119 | /// 120 | public void Activate(IActivatedEventArgs e) => EventDispatcher.Dispatch(() => Activated?.Invoke(this, e)); 121 | 122 | public void BackgroundActivate(Windows.ApplicationModel.Activation.BackgroundActivatedEventArgs e) 123 | { 124 | EventDispatcher.Dispatch(() => Activated?.Invoke(this, new BackgroundActivatedEventArgs(LaunchArgs, e))); 125 | } 126 | 127 | public void CachedFileUpdaterActivate(CachedFileUpdaterActivatedEventArgs e) 128 | { 129 | EventDispatcher.Dispatch(() => Activated?.Invoke(this, e)); 130 | } 131 | 132 | public void FileActivate(FileActivatedEventArgs e) 133 | { 134 | EventDispatcher.Dispatch(() => Activated?.Invoke(this, e)); 135 | } 136 | 137 | public void FileOpenPickerActivate(FileOpenPickerActivatedEventArgs e) 138 | { 139 | EventDispatcher.Dispatch(() => Activated?.Invoke(this, e)); 140 | } 141 | 142 | public void FileSavePickerActivate(FileSavePickerActivatedEventArgs e) 143 | { 144 | EventDispatcher.Dispatch(() => Activated?.Invoke(this, e)); 145 | } 146 | 147 | public void SearchActivate(SearchActivatedEventArgs e) 148 | { 149 | EventDispatcher.Dispatch(() => Activated?.Invoke(this, e)); 150 | } 151 | 152 | public void ShareTargetActivate(ShareTargetActivatedEventArgs e) 153 | { 154 | EventDispatcher.Dispatch(() => Activated?.Invoke(this, e)); 155 | } 156 | 157 | public void OnWindowCreated(WindowCreatedEventArgs e) 158 | { 159 | EventDispatcher.Dispatch(() => WindowCreated?.Invoke(this, e)); 160 | } 161 | 162 | public void OnEnteredBackground(Windows.ApplicationModel.EnteredBackgroundEventArgs args) 163 | { 164 | _isInBackground = true; 165 | 166 | if (Window.Current.Content is WebViewPage webViewPage) 167 | { 168 | webViewPage.Unload(); 169 | } 170 | } 171 | 172 | public void OnLeavingBackground(Windows.ApplicationModel.LeavingBackgroundEventArgs args) 173 | { 174 | if (_isInBackground && Window.Current.Content is WebViewPage webViewPage) 175 | { 176 | webViewPage.Load(); 177 | } 178 | 179 | _isInBackground = false; 180 | } 181 | 182 | /// 183 | /// Enable or disable the operating system's ability to prelaunch your app. 184 | /// 185 | /// 186 | public void EnablePrelaunch(bool value) 187 | { 188 | CoreApplication.EnablePrelaunch(value); 189 | } 190 | 191 | /// 192 | /// Restart the app. 193 | /// 194 | /// 195 | /// 196 | public IAsyncOperation RequestRestartAsync(string launchArguments) 197 | { 198 | return CoreApplication.RequestRestartAsync(launchArguments); 199 | } 200 | 201 | /// 202 | /// Restart the app in the context of a different user. 203 | /// 204 | /// 205 | /// 206 | /// 207 | public IAsyncOperation RequestRestartForUserAsync(User user, String launchArguments) 208 | { 209 | return CoreApplication.RequestRestartForUserAsync(user, launchArguments); 210 | } 211 | 212 | #region Application event handlers 213 | private void App_EnteredBackground(object sender, Windows.ApplicationModel.EnteredBackgroundEventArgs e) 214 | { 215 | EventDispatcher.Dispatch(() => EnteredBackground?.Invoke(this, e)); 216 | } 217 | 218 | private void App_LeavingBackground(object sender, Windows.ApplicationModel.LeavingBackgroundEventArgs e) 219 | { 220 | EventDispatcher.Dispatch(() => LeavingBackground?.Invoke(this, e)); 221 | } 222 | 223 | private void App_Resuming(object sender, object e) 224 | { 225 | EventDispatcher.Dispatch(() => Resuming?.Invoke(this, e)); 226 | } 227 | 228 | private void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e) 229 | { 230 | EventDispatcher.Dispatch(() => Suspending?.Invoke(this, e)); 231 | } 232 | 233 | private async void App_UnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) 234 | { 235 | // Windows Runtime HRESULTs in the range over 0x80070000 are converted to JavaScript errors 236 | // by taking the hexadecimal value of the low bits and converting it to a decimal. 237 | // For example, the HRESULT 0x80070032 is converted to the decimal value 50, and the JavaScript error is SCRIPT50. 238 | // The HRESULT 0x80074005 is converted to the decimal value 16389, and the JavaScript error is SCRIPT16389. 239 | // https://docs.microsoft.com/en-us/scripting/javascript/reference/javascript-run-time-errors 240 | 241 | var hResult = e.Exception.HResult; 242 | var lowBits = hResult & 0xFF; 243 | var number = "SCRIPT" + int.Parse(Convert.ToString(lowBits), System.Globalization.NumberStyles.HexNumber); 244 | var description = e.Message; 245 | 246 | // TODO: Fix error bubbling 247 | //await _webView.InvokeScriptAsync("eval", new string[] { $"throw new Error('{number}', '{description}')" }); 248 | 249 | e.Handled = true; 250 | } 251 | #endregion Application event handlers 252 | } 253 | } 254 | --------------------------------------------------------------------------------