From d5610051e95fa02fa761ca524c8ebccf6c03ea05 Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Mon, 13 May 2024 15:10:46 -0700 Subject: [PATCH 1/7] Add workers spec --- specs/Workers.md | 1035 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1035 insertions(+) create mode 100644 specs/Workers.md diff --git a/specs/Workers.md b/specs/Workers.md new file mode 100644 index 000000000..7037ec040 --- /dev/null +++ b/specs/Workers.md @@ -0,0 +1,1035 @@ +Workers support in WebView2 +=== + +# Background +Currently, WebView2 lacks comprehensive APIs for developers to fully utilize workers, leading to increased load on the main thread, offloading to native, or forking their web app for WebView2 scenarios. To address this, the WebView2 team is introducing support for worker scenarios. This enhancement allows WebView2 users to interact with Web Workers from native apps, bypassing the JavaScript thread to boost app performance and responsiveness, or to run tasks in the background for offline support, push notifications, background sync, content updates, and more. As a part of the work, the WebView2 team is adding support for [Dedicated Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API), [Shared Workers](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker), and [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). While there are various types of web workers, our initial focus is on these three, with plans to broaden our support for other workers in the future. + +**What is Web Worker?** +[Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) allow web content to execute scripts in background threads, enabling tasks to run independently of the user interface and facilitating communication between threads using message passing. Web Workers can also make network requests using fetch() or XMLHttpRequest APIs. Few examples of workers are + +- **Dedicated Worker**: Dedicated Workers are a type of Web Worker that operates independently in the background of a web page, enabling parallel execution of tasks without blocking the main UI thread. They are created by specific web pages and communicate with them via message passing, making them ideal for offloading CPU-intensive operations and improving overall performance and responsiveness of web applications. + +- **Shared Worker**: Shared Workers are a type of Web Worker that can be accessed by multiple scripts running in different windows, IFrames, or other contexts, as long as they are within the same domain as the worker. Unlike Dedicated Workers, which are tied to a specific web page, Shared Workers require communication via an active port, making them slightly more complex to implement but enabling collaboration and shared resources across different parts of a web application. + +- **Service Worker**: Service Workers serve as intermediary agents between web applications, the browser, and the network, functioning as proxy servers. Primarily, they facilitate the development of seamless offline experiences by caching resources and enabling web apps to continue functioning without an internet connection. Additionally, Service Workers intercept network requests, enabling customized responses based on network availability, and can update server-side assets. Moreover, they grant access to push notifications and background sync APIs, enhancing the functionality and interactivity of web applications. + +# Description + +We propose the introduction of APIs that enable the host application to oversee workers. These APIs lay the groundwork for the development of additional APIs, facilitating direct interaction between the host application and the workers, and support background operations for service workers. + +**DedicatedWorkerCreated**: This event, associated with CoreWebView2, is triggered when a web page initiates a dedicated worker. It grants access to the CoreWebView2DedicatedWorker object, which contains information such as the script URL and name. Additionally, it provides a 'destroy' event that is fired just before this object is due for destruction. + +**ServiceWorkerRegistered**: This event, originating from the CoreWebView2ServiceWorkerManager assicoated with CoreWebView2Profile is triggered when a service worker is successfully registered within the context of a WebView2 application for the profile. This event provides access to a CoreWebView2ServiceWorkerRegistration object, which encapsulates information about the registered service worker, such as its script URL and scope. Additionally, it enables subscription to the service worker's lifecycle events, including updates and unregistration. + +**GetServiceWorkerRegistrations**: The GetServiceWorkerRegistrations method, part of the CoreWebViewServiceWorkerManager class, is used to retrieve all service worker registrations within the context of a WebView2 application for the profile. This method gives a collection of CoreWebView2ServiceWorkerRegistration objects, each encapsulating information about a registered service worker, such as its script URL and scope. + +**GetServiceWorkerRegistration**: The GetServiceWorkerRegistration method, part of the CoreWebViewServiceWorkerManager class, is used to retrieve a specific service worker registration within the context of a WebView2 application for the profile. This asynchronous method takes a scope as an argument and returns a CoreWebView2ServiceWorkerRegistration object that encapsulates information about the registered service worker with the given scope, such as its script URL. This method is useful for accessing details of a specific service worker based on its scope. + +**SharedWorkerCreated**: This event, originating from the CoreWebView2SharedWorkerManager assicoated with CoreWebView2Profile, is triggered when a shared worker is successfully created within the context of a WebView2 application for the profile. It grants access to the CoreWebView2SharedWorker object, which contains information such as the script URL and name. Additionally, it provides a 'destroy' event that is fired just before this object is due for destruction. + +**GetSharedWorkers**: The GetSharedWorkers method, part of the CoreWebViewSharedWorkerManager class, is used to retrieve all shared workers created within the context of a WebView2 application for the profile. This method gives a collection of CoreWebView2SharedWorkers objects. + +# Examples +## Dedicated Worker +## Monitoring the Creation/Destruction of Dedicated Workers. +The following example demonstrates how to subscribe to the event that is triggered when a web page creates a dedicated worker. This event provides a CoreWebView2 dedicated worker object, enabling the host application to interact with it. + +## .NET/WinRT +```c# + void DedicatedWorkerCreatedExecuted(object target, ExecutedRoutedEventArgs e) + { + webView.CoreWebView2.DedicatedWorkerCreated += (sender, args) => + { + CoreWebView2DedicatedWorker dedicatedWorker = args.Worker; + if(dedicatedWorker != null) + { + var stringUrl = dedicatedWorker.ScriptUrl; + MessageBox.Show("Dedicated is created at " + stringUrl , "Dedicated Worker Message"); + + dedicatedWorker.WorkerDestroyed += (sender, args) => + { + /*Cleanup on worker destruction*/ + MessageBox.Show("Dedicated is destroyed" , "Dedicated Worker Message"); + }; + } + }; + } +``` +## Win32 C++ +```cpp + ScenarioDedicatedWorker::ScenarioDedicatedWorker(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) + { + m_webView2_25 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(m_webView2_25); + + CHECK_FAILURE(m_webView2_25->add_DedicatedWorkerCreated( + Microsoft::WRL::Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2DedicatedWorkerCreatedEventArgs* args) + { + wil::com_ptr dedicatedWorker; + + CHECK_FAILURE(args->get_Worker(&dedicatedWorker)); + + wil::com_ptr worker = + dedicatedWorker.try_query(); + + if(worker) { + wil::unique_cotaskmem_string scriptUrl; + CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + + m_appWindow->AsyncMessageBox(scriptUrl.get(), L"Dedicated worker is created"); + + // Subscribe to worker destroyed event + CHECK_FAILURE(worker->add_Destroyed( + Callback( + [this](ICoreWebView2Worker* sender, IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + return S_OK; + }) + .Get(), + nullptr)); + } + + return S_OK; + }) + .Get(), + &m_dedicatedWorkerCreatedToken)); + } +``` + +## Service Worker +## Monitoring the Registration/Destruction of Service Workers + +The following example demonstrates how to subscribe to the event that is triggered when a web page registers a service worker. This event provides a CoreWebView2 service worker registration object, enabling the host application to interact with the service workers. + +## .NET/WinRT +```c# + CoreWebView2ServiceWorkerManager ServiceWorkerManager_; + void ServiceWorkerRegisteredExecuted(object target, ExecutedRoutedEventArgs e) + { + if (ServiceWorkerManager_ != null) + { + ServiceWorkerManager_ = WebViewProfile.ServiceWorkerManager; + } + ServiceWorkerManager_.ServiceWorkerRegistered += async (sender, args) => + { + CoreWebView2ServiceWorkerRegistration serviceWorkerRegistration = args.ServiceWorkerRegistration; + if(serviceWorkerRegistration != null) + { + serviceWorkerRegistration.WorkerDestroyed += (sender, args) => + { + /*Cleanup on worker destruction*/ + MessageBox.Show("Service worker registration object is destroyed" , "Service Worker Registration Message"); + }; + + MessageBox.Show("Service worker is registered for " + serviceWorkerRegistration.Scope, "Service Worker Registration Message"); + + CoreWebView2ServiceWorker serviceWorker = await serviceWorkerRegistration.GetServiceWorkerAsync(); + if (serviceWorker != null) + { + serviceWorker.WorkerDestroyed += (sender, args) => + { + /*Cleanup on worker destruction*/ + MessageBox.Show("Service worker object is destroyed" , "Service Worker Message"); + }; + MessageBox.Show("Service worker is created.", "Service Worker Message"); + } + else + { + MessageBox.Show("No active service available.", "Service Worker Message"); + } + } + }; + } +``` +## Win32 C++ +```cpp + void ScenarioServiceWorkerManager::CreateServiceWorkerManager() + { + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webViewprofile2 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webViewprofile2); + CHECK_FAILURE(webViewprofile2->get_ServiceWorkerManager(&m_serviceWorkerManager)); + } + + void ScenarioServiceWorkerManager::SetupEventsOnWebview() + { + CHECK_FAILURE(m_serviceWorkerManager->add_ServiceWorkerRegistered( + Microsoft::WRL::Callback( + [this]( + ICoreWebView2ServiceWorkerManager* sender, + ICoreWebView2ServiceWorkerRegisteredEventArgs* args) + { + wil::com_ptr + serviceWorkerRegistration; + CHECK_FAILURE(args->get_ServiceWorkerRegistration(&serviceWorkerRegistration)); + + if(serviceWorkerRegistration) + { + // Subscribe to worker registration destroyed event + CHECK_FAILURE(serviceWorkerRegistration->add_Destroyed( + Callback( + [this]( + ICoreWebView2ServiceWorkerRegistration* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker registration destruction*/ + return S_OK; + }) + .Get(), + nullptr)); + + wil::unique_cotaskmem_string scope; + CHECK_FAILURE(serviceWorkerRegistration->get_Scope(&scope)); + + CHECK_FAILURE(serviceWorkerRegistration->GetServiceWorker( + Callback( + [this, &scope]( + HRESULT error, + ICoreWebView2ServiceWorker* serviceWorker) -> HRESULT + { + wil::com_ptr worker; + wil::unique_cotaskmem_string scriptUrl; + std::wstringstream message; + if (serviceWorker != nullptr) + { + if (SUCCEEDED( + serviceWorker->QueryInterface(IID_PPV_ARGS(&worker)))) + { + // Subscribe to worker destroyed event + CHECK_FAILURE(worker->add_Destroyed( + Callback< + ICoreWebView2WorkerDestroyedEventHandler>( + [this]( + ICoreWebView2Worker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + return S_OK; + }) + .Get(), + nullptr)); + + CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + } + message << L"ScriptUrl: " << scriptUrl.get(); + } + else + { + message << L"No active service worker is available."; + } + + m_appWindow->AsyncMessageBox(message.str(), L"Service worker"); + + return S_OK; + }) + .Get())); + + m_appWindow->AsyncMessageBox(scope.get(), L"Registered service worker for: "); + } + + return S_OK; + }) + .Get(), + &m_serviceWorkerRegisteredToken)); + } +``` + +## Retrieving Service Worker Registrations. +The following example demonstrates how to fetch and display information about all the service worker registrations associated with the WebView2 profile. + +## .NET/WinRT +```c# + private async void GetServiceWorkerRegistrationsExecuted(object target, ExecutedRoutedEventArgs e) + { + try + { + if (ServiceWorkerManager_ != null) + { + ServiceWorkerManager_ = WebViewProfile.ServiceWorkerManager; + } + IReadOnlyList registrationList = await ServiceWorkerManager_.GetServiceWorkerRegistrationsAsync(); + int registrationCount = registrationList.Count; + StringBuilder messageBuilder = new StringBuilder(); + messageBuilder.AppendLine($"No of service workers registered: {registrationCount}"); + + for (int i = 0; i < registrationList.Count(); ++i) + { + var scope = registrationList[i].Scope; + + messageBuilder.AppendLine($"Scope: {scope}"); + }; + + MessageBox.Show(messageBuilder.ToString(), "Service Worker Registrations", MessageBoxButton.OK); + } + catch (NotImplementedException exception) + { + MessageBox.Show(this, "GetServiceWorkerRegistrationsAsync Failed: " + exception.Message, + "Get Service Worker Registrations Info"); + } + } +``` +## Win32 C++ +```cpp + void ScenarioServiceWorkerManager::GetAllServiceWorkerRegistrations() + { + if (!m_serviceWorkerManager) + { + CreateServiceWorkerManager(); + } + CHECK_FAILURE(m_serviceWorkerManager->GetServiceWorkerRegistrations( + Callback( + [this]( + HRESULT error, ICoreWebView2ServiceWorkerRegistrationCollectionView* + workerRegistrationCollection) -> HRESULT + { + UINT32 workersCount = 0; + CHECK_FAILURE(workerRegistrationCollection->get_Count(&workersCount)); + + std::wstringstream message{}; + message << L"No of service workers registered: " << workersCount << std::endl; + + for (UINT32 i = 0; i < workersCount; i++) + { + Microsoft::WRL::ComPtr + serviceWorkerRegistration; + CHECK_FAILURE(workerRegistrationCollection->GetValueAtIndex( + i, &serviceWorkerRegistration)); + + wil::unique_cotaskmem_string scope; + CHECK_FAILURE(serviceWorkerRegistration->get_Scope(&scope)); + + message << L"Scope: " << scope.get(); + } + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Registered service workers"); + + return S_OK; + }) + .Get())); + } +``` + +## Retrieving Service Worker Registration for a Specific Scope. + +The following example demonstrates how to obtain the service worker registration associated with a specific scope. This allows the application to interact with the service worker. + +## .NET/WinRT +```c# + async void GetServiceWorkerRegisteredForScopeExecuted(object target, ExecutedRoutedEventArgs e) + { + var dialog = new TextInputDialog( + title: "Scope of the Service Worker Registration", + description: "Specify a scope to get the service worker", + defaultInput: ""); + if (dialog.ShowDialog() == true) + { + try + { + if (ServiceWorkerManager_ != null) + { + ServiceWorkerManager_ = WebViewProfile.ServiceWorkerManager; + } + CoreWebView2ServiceWorkerRegistration registration = await ServiceWorkerManager_.GetServiceWorkerRegistrationAsync(dialog.Input.Text); + if(registration != null) + { + StringBuilder messageBuilder = new StringBuilder(); + + CoreWebView2ServiceWorker worker = await registration.GetServiceWorkerAsync(); + if(worker != null) + { + messageBuilder.AppendLine($"Service worker for scope '{dialog.Input.Text}' fetched successfully."); + + MessageBox.Show(messageBuilder.ToString(), "Service Worker Registrations", MessageBoxButton.OK); + } else + { + MessageBox.Show("No active service worker for " + dialog.Input.Text, "Service Worker Registrations", MessageBoxButton.OK); + } + } else + { + MessageBox.Show("No service worker registered for " + dialog.Input.Text, "Service Worker Registrations", MessageBoxButton.OK); + } + } + catch (NotImplementedException exception) + { + MessageBox.Show(this, "GetServiceWorkerRegistrationsAsync Failed: " + exception.Message, + "Get Service Workers Info"); + } + } + } +``` +## Win32 C++ +```cpp + void ScenarioServiceWorkerManager::GetServiceWorkerRegistrateredForScope() + { + if (!m_serviceWorkerManager) + { + CreateServiceWorkerManager(); + } + std::wstring scope; + + TextInputDialog dialog( + m_appWindow->GetMainWindow(), L"Service Worker", L"Scope:", + L"Specify a scope to get the service worker", L""); + + if (dialog.confirmed) + { + CHECK_FAILURE(m_serviceWorkerManager->GetServiceWorkerRegistration( + dialog.input.c_str(), + Callback( + [this, &scope]( + HRESULT error, + ICoreWebView2ServiceWorkerRegistration* serviceWorkerRegistration) + -> HRESULT + { + CHECK_FAILURE(serviceWorkerRegistration->GetServiceWorker( + Callback( + [this, &scope]( + HRESULT error, + ICoreWebView2ServiceWorker* serviceWorker) -> HRESULT + { + std::wstringstream message{}; + + if (serviceWorker != nullptr) + { + wil::com_ptr worker; + wil::unique_cotaskmem_string scriptUrl; + if (SUCCEEDED(serviceWorker->QueryInterface( + IID_PPV_ARGS(&worker)))) + { + CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + } + + message << L"ScriptUrl: " << scriptUrl.get(); + message << std::endl; + } + else + { + message << L"No service worker available for the scope: " + << scope; + message << std::endl; + } + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Service Worker"); + + return S_OK; + }) + .Get())); + + return S_OK; + }) + .Get())); + } + } +``` + +## Shared Worker +## Monitoring Shared Worker Creation and Destruction + +The following example demonstrates how to subscribe to the shared worker creation event. This event is triggered when a web page creates a shared worker. It provides the host application with access to the CoreWebView2 shared worker object, enabling interaction with shared workers. + +## .NET/WinRT +```c# + CoreWebView2SharedWorkerManager SharedWorkerManager_; + void SharedWorkerManagerExecuted(object target, ExecutedRoutedEventArgs e) + { + SharedWorkerManager_ = WebViewProfile.SharedWorkerManager; + + if(SharedWorkerManager_ != null) + { + SharedWorkerManager_.SharedWorkerCreated += (sender, args) => + { + CoreWebView2SharedWorker sharedWorker = args.Worker; + if(sharedWorker != null) + { + sharedWorker.WorkerDestroyed += (sender, args) => + { + /*Cleanup on worker destruction*/ + MessageBox.Show("Shared worker is destroyed" , "Shared Worker Message"); + }; + + var stringUrl = sharedWorker.ScriptUrl; + MessageBox.Show("Shared is created at" + stringUrl , "Shared Worker Message"); + } + }; + } + } +``` +## Win32 C++ +```cpp + void ScenarioSharedWorkerManager::GetSharedWorkerManager() + { + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webViewprofile2 = webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webViewprofile2); + CHECK_FAILURE(webViewprofile2->get_SharedWorkerManager(&m_sharedWorkerManager)); + } + + void ScenarioSharedWorkerManager::SetupEventsOnWebview() + { + CHECK_FAILURE(m_sharedWorkerManager->add_SharedWorkerCreated( + Microsoft::WRL::Callback( + [this]( + ICoreWebView2SharedWorkerManager* sender, + ICoreWebView2SharedWorkerCreatedEventArgs* args) + { + wil::com_ptr sharedWorker; + CHECK_FAILURE(args->get_Worker(&sharedWorker)); + + wil::com_ptr worker = + sharedWorker.try_query(); + if(worker) + { + wil::unique_cotaskmem_string scriptUrl; + CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + + // Subscribe to worker destroyed event + CHECK_FAILURE(worker->add_Destroyed( + Callback( + [this, &scriptUrl]( + ICoreWebView2Worker* sender, IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUrl.get(), L"Shared worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr)); + + m_appWindow->AsyncMessageBox(scriptUrl.get(), L"Shared worker is created"); + } + return S_OK; + }) + .Get(), + &m_sharedWorkerCreatedToken)); + } +``` + +## Retrieving Shared Workers + +The following example demonstrates how to fetch and display information about all the shared workers associated with the WebView2 profile. + +## .NET/WinRT +```c# + private async void GetSharedWorkersExecuted(object target, ExecutedRoutedEventArgs e) + { + try + { + if (SharedWorkerManager_ != null) + { + SharedWorkerManager_ = WebViewProfile.SharedWorkerManager; + } + IReadOnlyList workerList = await SharedWorkerManager_.GetSharedWorkersAsync(); + int workerCount = workerList.Count; + StringBuilder messageBuilder = new StringBuilder(); + messageBuilder.AppendLine($"No of shared workers created: {workerCount}"); + + for (int i = 0; i < workerCount; ++i) + { + var stringUrl = workerList[i].ScriptUrl; + + messageBuilder.AppendLine($"ScriptUrl: {scriptUrl}"); + }; + + MessageBox.Show(messageBuilder.ToString(), "Shared Workers", MessageBoxButton.OK); + } + catch (NotImplementedException exception) + { + MessageBox.Show(this, "GetSharedWorkersAsync Failed: " + exception.Message, + "Get Shared Workers Info"); + } + } +``` +## Win32 C++ +```cpp + void ScenarioSharedWorkerManager::GetAllSharedWorkers() + { + if (!m_sharedWorkerManager) + { + GetSharedWorkerManager(); + } + CHECK_FAILURE(m_sharedWorkerManager->GetSharedWorkers( + Callback( + [this]( + HRESULT error, + ICoreWebView2SharedWorkerCollectionView* workersCollection) -> HRESULT + { + UINT32 workersCount = 0; + CHECK_FAILURE(workersCollection->get_Count(&workersCount)); + + std::wstringstream message{}; + message << L"No of shared workers created: " << workersCount << std::endl; + + for (UINT32 i = 0; i < workersCount; i++) + { + Microsoft::WRL::ComPtr sharedWorker; + CHECK_FAILURE(workersCollection->GetValueAtIndex(i, &sharedWorker)); + + wil::com_ptr worker; + if (SUCCEEDED(sharedWorker->QueryInterface(IID_PPV_ARGS(&worker)))) + { + wil::unique_cotaskmem_string scriptUrl; + CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + + message << L"ScriptUrl: " << scriptUrl.get(); + message << std::endl; + } + } + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Get all shared workers"); + + return S_OK; + }) + .Get())); + } +``` + +# API Details +``` +/// State of the service worker. +[v1_enum] +typedef enum COREWEBVIEW2_SERVICE_WORKER_STATE { + /// The service worker is new and has not been installed yet. + COREWEBVIEW2_SERVICE_WORKER_STATE_NEW, + /// The service worker is installing. + COREWEBVIEW2_SERVICE_WORKER_STATE_INSTALLING, + /// The service worker is installed. The service worker in this state is considered a waiting worker. + COREWEBVIEW2_SERVICE_WORKER_STATE_INSTALLED, + /// The service worker is activating. + COREWEBVIEW2_SERVICE_WORKER_STATE_ACTIVATING, + /// The service worker is activated. The service worker in this state is considered an active worker ready to handle functional events. + COREWEBVIEW2_SERVICE_WORKER_STATE_ACTIVATED, + /// The service worker is redundant. + COREWEBVIEW2_SERVICE_WORKER_STATE_REDUNDANT, +} COREWEBVIEW2_SERVICE_WORKER_STATE; + +[uuid(29b994e5-0ac8-5430-89fa-5b4bb2091d8d), object, pointer_default(unique)] +interface ICoreWebView225 : IUnknown { + /// Subscribe to this event that gets raised when a new dedicated worker is created. + /// + /// A Dedicated Worker is a type of web worker that allow you to run Javascript code in the background without blocking the main thread, making them useful for tasks like heavy computations, data processing, and parallel execution. + /// It is "dedicated" because it is linked to a single parent document and cannot be shared with other scripts. + /// + /// This event is raised when a web application creates a dedicated worker using the + /// `new Worker("/worker.js")` method. See the + /// [Worker](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker) + /// for more information. + HRESULT add_DedicatedWorkerCreated( + [in] ICoreWebView2DedicatedWorkerCreatedEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with `add_DedicatedWorkerCreated`. + HRESULT remove_DedicatedWorkerCreated( + [in] EventRegistrationToken token); +} + +/// Receives `DedicatedWorkerCreated` events. +[uuid(99c76d22-d2de-5b04-b8e5-07b27584da49), object, pointer_default(unique)] +interface ICoreWebView2DedicatedWorkerCreatedEventHandler : IUnknown { + /// Provides the event args for the corresponding event. + HRESULT Invoke( + [in] ICoreWebView2* sender, + [in] ICoreWebView2DedicatedWorkerCreatedEventArgs* args); +} + +/// Event args for the `DedicatedWorkerCreated` event. +[uuid(4a122222-390e-5a65-809c-f043486db602), object, pointer_default(unique)] +interface ICoreWebView2DedicatedWorkerCreatedEventArgs : IUnknown { + /// The dedicated worker that was created. + [propget] HRESULT Worker([out, retval] ICoreWebView2DedicatedWorker** value); +} + +[uuid(ad6921d4-c416-5945-8437-2c97aeb76e6e), object, pointer_default(unique)] +interface ICoreWebView2Profile2 : IUnknown { + /// Get the service worker manager to monitor service worker registrations and interact with the service worker associated with the current profile. + /// + /// The changes would apply to the context of the user profile. That is, other WebViews under the same user profile could be affected. + /// + /// \snippet ScenarioServiceWorkerManager.cpp ServiceWorkerManager + [propget] HRESULT ServiceWorkerManager([out, retval] ICoreWebView2ServiceWorkerManager** value); + + + /// Get the shared worker manager to monitor shared worker creations and interact with the shared worker associated with the current profile. + /// + /// The changes would apply to the context of the user profile. That is, other WebViews under the same user profile could be affected. + /// + /// \snippet ScenarioSharedWorkerManager.cpp SharedWorkerManager + [propget] HRESULT SharedWorkerManager([out, retval] ICoreWebView2SharedWorkerManager** value); +} + +[uuid(4e07e562-8db7-5815-907b-6d89a253a974), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorkerManager : IUnknown { + /// Adds an event handler for the `ServiceWorkerRegistered` event. + /// + /// A ServiceWorker is a specific type of worker that takes a JavaScript file that can control the web-page/site that it is associated with, + /// intercepting and modifying navigation and resource requests, and caching resources in a very granular fashion to give you complete control + /// over how app behaves in certain situations. + /// + /// Service workers essentially act as proxy servers that sit between web applications, the browser, and the network (when available). + /// Unlike Shared Workers, which have their own separate global scope, Service Workers have no DOM access and run in a different context. + /// + /// This event is raised when a web application registers a service worker using the + /// `navigator.serviceWorker.register("/sw.js")` method. See the + /// [Service Worker Registration](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration) + /// for more information. + /// + /// + /// \snippet ScenarioServiceWorkerManager.cpp ServiceWorkerRegistered + HRESULT add_ServiceWorkerRegistered( + [in] ICoreWebView2ServiceWorkerRegisteredEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with `add_ServiceWorkerRegistered`. + HRESULT remove_ServiceWorkerRegistered( + [in] EventRegistrationToken token); + + + /// Gets a list of the service worker registrations under the same profile. + HRESULT GetServiceWorkerRegistrations( + [in] ICoreWebView2GetServiceWorkerRegistrationsCompletedHandler* handler + ); + + /// Gets the service worker registration object associated with the specified scope. If a service worker has been registered + /// for the given scope, it gets the corresponding `CoreWebView2ServiceWorkerRegistration` object. + /// If scope is empty string or null, the completed handler immediately returns `E_POINTER` and with a null pointer. + HRESULT GetServiceWorkerRegistration( + [in] LPCWSTR scope + , [in] ICoreWebView2GetServiceWorkerRegistrationCompletedHandler* handler + ); +} + +/// Receives the result of the `GetServiceWorkerRegistrations` method. +[uuid(3c29552b-7ee2-5904-baf3-a0720e1538a5), object, pointer_default(unique)] +interface ICoreWebView2GetServiceWorkerRegistrationsCompletedHandler : IUnknown { + + /// Provides the result of the corresponding asynchronous method. + HRESULT Invoke([in] HRESULT errorCode, [in] ICoreWebView2ServiceWorkerRegistrationCollectionView* result); +} + +/// Receives the result of the `GetServiceWorkerRegistration` method. +[uuid(e5b37473-5833-5ec1-b57e-ccbbbc099a32), object, pointer_default(unique)] +interface ICoreWebView2GetServiceWorkerRegistrationCompletedHandler : IUnknown { + + /// Provides the result of the corresponding asynchronous method. + HRESULT Invoke([in] HRESULT errorCode, [in] ICoreWebView2ServiceWorkerRegistration* result); +} + +/// Receives `ServiceWorkerRegistered` events. +[uuid(81262ddf-ef6c-5184-8ae0-01fa0a4c86c7), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorkerRegisteredEventHandler : IUnknown { + /// Provides the event args for the corresponding event. + HRESULT Invoke( + [in] ICoreWebView2ServiceWorkerManager* sender, + [in] ICoreWebView2ServiceWorkerRegisteredEventArgs* args); +} + +/// Event args for the `ServiceWorkerRegistered` event. +[uuid(a18bd62a-8246-5d2b-abc5-2bdbbc13767b), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorkerRegisteredEventArgs : IUnknown { + /// A string representing a URL that defines a service worker's registration scope. It is relative to the base URL of the application. + /// By default, the scope value for a service worker registration is set to the directory where the service worker script is located. + /// + /// The caller must free the returned string with `CoTaskMemFree`. See + /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). + [propget] HRESULT Scope([out, retval] LPWSTR* value); + + /// The service worker that was registered. + HRESULT GetServiceWorkerRegistration( + [out, retval] ICoreWebView2ServiceWorkerRegistration** value + ); +} + +/// A collection of ICoreWebView2ServiceWorkerRegistration. +[uuid(9860773f-16e5-5521-9bc2-a6d8e5347d4a), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorkerRegistrationCollectionView : IUnknown { + /// The number of elements contained in the collection. + [propget] HRESULT Count([out, retval] UINT32* value); + + /// Gets the element at the given index. + HRESULT GetValueAtIndex([in] UINT32 index, [out, retval] ICoreWebView2ServiceWorkerRegistration** value); +} + +/// Receives the result of the `GetServiceWorker` method. +[uuid(bd120b47-b859-5f44-9913-0318130ffb69), object, pointer_default(unique)] +interface ICoreWebView2GetServiceWorkerCompletedHandler : IUnknown { + + /// Provides the result of the corresponding asynchronous method. + HRESULT Invoke([in] HRESULT errorCode, [in] ICoreWebView2ServiceWorker* result); +} + +/// Receives `Destroyed` events. +[uuid(9d79117e-4e96-5a53-9933-d7a31d0106ae), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorkerRegistrationDestroyedEventHandler : IUnknown { + /// Provides the event args for the corresponding event. + HRESULT Invoke( + [in] ICoreWebView2ServiceWorkerRegistration* sender, + [in] IUnknown* args); +} + +[uuid(0c0b03bd-ced2-5518-851a-3d3f71fb5c4b), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorkerRegistration : IUnknown { + /// A string representing a URL that defines a service worker's registration scope. It is relative to the base URL of the application. + /// By default, the scope value for a service worker registration is set to the directory where the service worker script is located. + /// + /// The caller must free the returned string with `CoTaskMemFree`. See + /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). + [propget] HRESULT Scope([out, retval] LPWSTR* value); + + /// Add an event handler for the `Destroyed` event that is raised when the worker registration is + /// unregistered using the JS api `registration.unregister()` method or when the `CoreWebView2ServiceWorkerRegistration` + /// object is destroyed. See the + /// [Unregister](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/unregister) + /// for more information. + + HRESULT add_Destroyed( + [in] ICoreWebView2ServiceWorkerRegistrationDestroyedEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with `add_Destroyed`. + HRESULT remove_Destroyed( + [in] EventRegistrationToken token); + + + /// The active service worker that was created. If there is no active service worker, the completed handler immediately returns `S_OK` and with a null pointer. + /// The active service worker is the service worker that controls the pages within the scope of the registration. See the [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker) + /// for more information. + HRESULT GetServiceWorker( + [in] ICoreWebView2GetServiceWorkerCompletedHandler* handler + ); +} + +[uuid(9b897103-d035-551f-892e-3e8f2916d03e), object, pointer_default(unique)] +interface ICoreWebView2SharedWorkerManager : IUnknown { + /// Add an event handler for the `SharedWorkerCreated` event. + /// + /// A SharedWorker is a specific type of worker that can be accessed from several browsing contexts, such as multiple windows, iframes, or even other workers. + /// Unlike Dedicated Workers, which have their own separate global scope, SharedWorkers share a commoglobal scope called SharedWorkerGlobalScope. + /// + /// This event is raised when a web application creates a shared worker using the + /// `new SharedWorker("worker.js")` method. See the + /// [Shared Worker](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker) + /// for more information. + /// + /// \snippet ScenarioSharedWorkerManager.cpp SharedWorkerCreated + HRESULT add_SharedWorkerCreated( + [in] ICoreWebView2SharedWorkerCreatedEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with `add_SharedWorkerCreated`. + HRESULT remove_SharedWorkerCreated( + [in] EventRegistrationToken token); + + /// Gets a list of the shared workers created under the same profile. + HRESULT GetSharedWorkers( + [in] ICoreWebView2GetSharedWorkersCompletedHandler* handler + ); +} + +/// Event args for the `SharedWorkerCreated` event. +[uuid(9f6615b0-08f1-5baa-9c95-a02a1dc56d3f), object, pointer_default(unique)] +interface ICoreWebView2SharedWorkerCreatedEventArgs : IUnknown { + /// The shared worker that was created. + [propget] HRESULT Worker([out, retval] ICoreWebView2SharedWorker** value); +} + +/// Receives the result of the `GetSharedWorkers` method. +[uuid(1f3179ae-15e5-51e4-8583-be0caf85adc7), object, pointer_default(unique)] +interface ICoreWebView2GetSharedWorkersCompletedHandler : IUnknown { + /// Provides the result of the corresponding asynchronous method. + HRESULT Invoke([in] HRESULT errorCode, [in] ICoreWebView2SharedWorkerCollectionView* result); +} + +/// Receives `SharedWorkerCreated` events. +[uuid(79cb8524-b842-551a-8d31-5f824b6955ed), object, pointer_default(unique)] +interface ICoreWebView2SharedWorkerCreatedEventHandler : IUnknown { + /// Provides the event args for the corresponding event. + HRESULT Invoke( + [in] ICoreWebView2SharedWorkerManager* sender, + [in] ICoreWebView2SharedWorkerCreatedEventArgs* args); +} + +/// A collection of ICoreWebView2SharedWorker. +[uuid(f8842b09-0108-5575-a965-3d76fd267050), object, pointer_default(unique)] +interface ICoreWebView2SharedWorkerCollectionView : IUnknown { + /// The number of elements contained in the collection. + [propget] HRESULT Count([out, retval] UINT32* value); + + /// Gets the element at the given index. + HRESULT GetValueAtIndex([in] UINT32 index, [out, retval] ICoreWebView2SharedWorker** value); +} + +[uuid(06cfc21b-56e5-59b1-b7b4-13f197d4539d), object, pointer_default(unique)] +interface ICoreWebView2Worker : IUnknown { + /// A string representing the URL of the script that the worker is executing. + /// + /// The caller must free the returned string with `CoTaskMemFree`. See + /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). + [propget] HRESULT ScriptUrl([out, retval] LPWSTR* value); + + + /// Add an event handler for the `Destroyed` event that is raised when the worker object is destroyed. + /// A worker object is destroyed when the worker script is terminated or when the `CoreWebView2Worker` object is destroyed. + HRESULT add_Destroyed( + [in] ICoreWebView2WorkerDestroyedEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with `add_Destroyed`. + HRESULT remove_Destroyed( + [in] EventRegistrationToken token); +} + +/// Receives `Destroyed` events. +[uuid(3197df3b-4245-5fff-9427-e98118fcf657), object, pointer_default(unique)] +interface ICoreWebView2WorkerDestroyedEventHandler : IUnknown { + /// Provides the event args for the corresponding event. + HRESULT Invoke( + [in] ICoreWebView2Worker* sender, + [in] IUnknown* args); +} + +[uuid(f233edb4-d9b4-5209-9abd-b7f50089464c), object, pointer_default(unique)] +interface ICoreWebView2DedicatedWorker : IUnknown { + /// A string specified when creating a dedicated worker. + /// + /// The caller must free the returned string with `CoTaskMemFree`. See + /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). + [propget] HRESULT Name([out, retval] LPWSTR* value); +} + + +[uuid(de8ed42b-5128-55df-9dd0-ea1d4d706c87), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorker : IUnknown { + /// The state of the service worker. A service worker can be in new, installing, installed, activating, activated, or redundant. + [propget] HRESULT State([out, retval] COREWEBVIEW2_SERVICE_WORKER_STATE* value); +} + +[uuid(876f8390-f9a8-5264-9677-985d8453aeab), object, pointer_default(unique)] +interface ICoreWebView2SharedWorker : IUnknown { + /// A string specified when creating a shared worker. + /// + /// The caller must free the returned string with `CoTaskMemFree`. See + /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). + [propget] HRESULT Name([out, retval] LPWSTR* value); +} +``` + +```c# (but really MIDL3) +runtimeclass CoreWebView2DedicatedWorkerCreatedEventArgs; +runtimeclass CoreWebView2DedicatedWorker; +runtimeclass CoreWebView2ServiceWorkerRegistration; +runtimeclass CoreWebView2ServiceWorkerRegisteredEventArgs; +runtimeclass CoreWebView2ServiceWorkerManager; +runtimeclass CoreWebView2ServiceWorker; +runtimeclass CoreWebView2SharedWorkerManager; +runtimeclass CoreWebView2SharedWorkerCreatedEventArgs; +runtimeclass CoreWebView2SharedWorker; + +namespace Microsoft.Web.WebView2.Core +{ + [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView225")] + { + event Windows.Foundation.TypedEventHandler DedicatedWorkerCreated; + } + + // ... + runtimeclass CoreWebView2DedicatedWorkerCreatedEventArgs + { + CoreWebView2DedicatedWorker Worker { get; }; + } + + runtimeclass CoreWebView2DedicatedWorker + { + String Name { get; }; + + String ScriptUrl { get; }; + + event Windows.Foundation.TypedEventHandler Destroyed; + } + + enum CoreWebView2ServiceWorkerState + { + New = 0, + Installing = 1, + Installed = 2, + Activating = 3, + Activated = 4, + Redundant = 5, + }; + + [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Profile9")] + { + CoreWebView2ServiceWorkerManager ServiceWorkerManager { get; }; + + CoreWebView2SharedWorkerManager SharedWorkerManager { get; }; + } + + runtimeclass CoreWebView2ServiceWorkerManager + { + event Windows.Foundation.TypedEventHandler ServiceWorkerRegistered; + + Windows.Foundation.IAsyncOperation> GetServiceWorkerRegistrationsAsync(); + + Windows.Foundation.IAsyncOperation GetServiceWorkerRegistrationAsync(String Scope); + } + + runtimeclass CoreWebView2ServiceWorkerRegisteredEventArgs + { + CoreWebView2ServiceWorkerRegistration ServiceWorkerRegistration { get; }; + } + + runtimeclass CoreWebView2ServiceWorkerRegistration + { + String Scope { get; }; + + event Windows.Foundation.TypedEventHandler Destroyed; + + Windows.Foundation.IAsyncOperation GetServiceWorkerAsync(); + } + + runtimeclass CoreWebView2ServiceWorker + { + String ScriptUrl { get; }; + + CoreWebView2ServiceWorkerState State { get; }; + + event Windows.Foundation.TypedEventHandler Destroyed; + } + + runtimeclass CoreWebView2SharedWorkerManager + { + event Windows.Foundation.TypedEventHandler SharedWorkerCreated; + + Windows.Foundation.IAsyncOperation> GetSharedWorkersAsync(); + } + + runtimeclass CoreWebView2SharedWorkerCreatedEventArgs + { + CoreWebView2SharedWorker Worker { get; }; + } + + runtimeclass CoreWebView2SharedWorker + { + String Name { get; }; + + String ScriptUrl { get; }; + + event Windows.Foundation.TypedEventHandler Destroyed; + } +} +``` From 13bc4b465c1b65b84d4f86dc137d27b70b67e46f Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Tue, 14 May 2024 07:53:31 -0700 Subject: [PATCH 2/7] added checks --- specs/Workers.md | 218 +++++++++++++++++++++++++---------------------- 1 file changed, 118 insertions(+), 100 deletions(-) diff --git a/specs/Workers.md b/specs/Workers.md index 7037ec040..1a71a6aec 100644 --- a/specs/Workers.md +++ b/specs/Workers.md @@ -2,7 +2,7 @@ Workers support in WebView2 === # Background -Currently, WebView2 lacks comprehensive APIs for developers to fully utilize workers, leading to increased load on the main thread, offloading to native, or forking their web app for WebView2 scenarios. To address this, the WebView2 team is introducing support for worker scenarios. This enhancement allows WebView2 users to interact with Web Workers from native apps, bypassing the JavaScript thread to boost app performance and responsiveness, or to run tasks in the background for offline support, push notifications, background sync, content updates, and more. As a part of the work, the WebView2 team is adding support for [Dedicated Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API), [Shared Workers](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker), and [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). While there are various types of web workers, our initial focus is on these three, with plans to broaden our support for other workers in the future. +Currently, WebView2 lacks comprehensive APIs for developers to fully utilize workers, leading to increased load on the main thread, offloading to native, or forking your web app for WebView2 scenarios. To address this, the WebView2 team is introducing support for worker scenarios. This enhancement allows WebView2 users to interact with Web Workers from native apps, bypassing the JavaScript thread to boost app performance and responsiveness, or to run tasks in the background for offline support, push notifications, background sync, content updates, and more. As a part of the work, the WebView2 team is adding support for [Dedicated Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API), [Shared Workers](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker), and [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). While there are various types of web workers, our initial focus is on these three, with plans to broaden our support for other workers in the future. **What is Web Worker?** [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) allow web content to execute scripts in background threads, enabling tasks to run independently of the user interface and facilitating communication between threads using message passing. Web Workers can also make network requests using fetch() or XMLHttpRequest APIs. Few examples of workers are @@ -19,20 +19,20 @@ We propose the introduction of APIs that enable the host application to oversee **DedicatedWorkerCreated**: This event, associated with CoreWebView2, is triggered when a web page initiates a dedicated worker. It grants access to the CoreWebView2DedicatedWorker object, which contains information such as the script URL and name. Additionally, it provides a 'destroy' event that is fired just before this object is due for destruction. -**ServiceWorkerRegistered**: This event, originating from the CoreWebView2ServiceWorkerManager assicoated with CoreWebView2Profile is triggered when a service worker is successfully registered within the context of a WebView2 application for the profile. This event provides access to a CoreWebView2ServiceWorkerRegistration object, which encapsulates information about the registered service worker, such as its script URL and scope. Additionally, it enables subscription to the service worker's lifecycle events, including updates and unregistration. +**ServiceWorkerRegistered**: This event, originating from the CoreWebView2ServiceWorkerManager associated with CoreWebView2Profile is triggered when a service worker is successfully registered within the context of a WebView2 application for the profile. This event provides access to a CoreWebView2ServiceWorkerRegistration object, which encapsulates information about the registered service worker, such as its script URL and scope. Additionally, it enables subscription to the service worker's lifecycle events, including updates and unregistration. **GetServiceWorkerRegistrations**: The GetServiceWorkerRegistrations method, part of the CoreWebViewServiceWorkerManager class, is used to retrieve all service worker registrations within the context of a WebView2 application for the profile. This method gives a collection of CoreWebView2ServiceWorkerRegistration objects, each encapsulating information about a registered service worker, such as its script URL and scope. **GetServiceWorkerRegistration**: The GetServiceWorkerRegistration method, part of the CoreWebViewServiceWorkerManager class, is used to retrieve a specific service worker registration within the context of a WebView2 application for the profile. This asynchronous method takes a scope as an argument and returns a CoreWebView2ServiceWorkerRegistration object that encapsulates information about the registered service worker with the given scope, such as its script URL. This method is useful for accessing details of a specific service worker based on its scope. -**SharedWorkerCreated**: This event, originating from the CoreWebView2SharedWorkerManager assicoated with CoreWebView2Profile, is triggered when a shared worker is successfully created within the context of a WebView2 application for the profile. It grants access to the CoreWebView2SharedWorker object, which contains information such as the script URL and name. Additionally, it provides a 'destroy' event that is fired just before this object is due for destruction. +**SharedWorkerCreated**: This event, originating from the CoreWebView2SharedWorkerManager associated with CoreWebView2Profile, is triggered when a shared worker is successfully created within the context of a WebView2 application for the profile. It grants access to the CoreWebView2SharedWorker object, which contains information such as the script URL and name. Additionally, it provides a 'destroy' event that is fired just before this object is due for destruction. **GetSharedWorkers**: The GetSharedWorkers method, part of the CoreWebViewSharedWorkerManager class, is used to retrieve all shared workers created within the context of a WebView2 application for the profile. This method gives a collection of CoreWebView2SharedWorkers objects. # Examples ## Dedicated Worker ## Monitoring the Creation/Destruction of Dedicated Workers. -The following example demonstrates how to subscribe to the event that is triggered when a web page creates a dedicated worker. This event provides a CoreWebView2 dedicated worker object, enabling the host application to interact with it. +The following example demonstrates how to subscribe to the event that is triggered when a web page creates a dedicated worker. This event provides a CoreWebView2DedicatedWorker object, enabling the host application to interact with it. ## .NET/WinRT ```c# @@ -43,14 +43,14 @@ The following example demonstrates how to subscribe to the event that is trigger CoreWebView2DedicatedWorker dedicatedWorker = args.Worker; if(dedicatedWorker != null) { - var stringUrl = dedicatedWorker.ScriptUrl; - MessageBox.Show("Dedicated is created at " + stringUrl , "Dedicated Worker Message"); - dedicatedWorker.WorkerDestroyed += (sender, args) => { /*Cleanup on worker destruction*/ MessageBox.Show("Dedicated is destroyed" , "Dedicated Worker Message"); }; + + var scriptUrl = dedicatedWorker.ScriptUrl; + MessageBox.Show("Dedicated is created at " + scriptUrl , "Dedicated Worker Message"); } }; } @@ -73,25 +73,29 @@ The following example demonstrates how to subscribe to the event that is trigger CHECK_FAILURE(args->get_Worker(&dedicatedWorker)); - wil::com_ptr worker = - dedicatedWorker.try_query(); - - if(worker) { - wil::unique_cotaskmem_string scriptUrl; - CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); - - m_appWindow->AsyncMessageBox(scriptUrl.get(), L"Dedicated worker is created"); + if (dedicatedWorker) + { + wil::com_ptr worker = + dedicatedWorker.try_query(); - // Subscribe to worker destroyed event - CHECK_FAILURE(worker->add_Destroyed( - Callback( - [this](ICoreWebView2Worker* sender, IUnknown* args) -> HRESULT - { - /*Cleanup on worker destruction*/ - return S_OK; - }) - .Get(), - nullptr)); + if(worker) + { + // Subscribe to worker destroyed event + CHECK_FAILURE(worker->add_Destroyed( + Callback( + [this](ICoreWebView2Worker* sender, IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + return S_OK; + }) + .Get(), + nullptr)); + + wil::unique_cotaskmem_string scriptUrl; + CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + + m_appWindow->AsyncMessageBox(scriptUrl.get(), L"Dedicated worker is created"); + } } return S_OK; @@ -111,7 +115,7 @@ The following example demonstrates how to subscribe to the event that is trigger CoreWebView2ServiceWorkerManager ServiceWorkerManager_; void ServiceWorkerRegisteredExecuted(object target, ExecutedRoutedEventArgs e) { - if (ServiceWorkerManager_ != null) + if (ServiceWorkerManager_ != nullptr) { ServiceWorkerManager_ = WebViewProfile.ServiceWorkerManager; } @@ -199,7 +203,7 @@ The following example demonstrates how to subscribe to the event that is trigger wil::com_ptr worker; wil::unique_cotaskmem_string scriptUrl; std::wstringstream message; - if (serviceWorker != nullptr) + if (serviceWorker) { if (SUCCEEDED( serviceWorker->QueryInterface(IID_PPV_ARGS(&worker)))) @@ -291,27 +295,30 @@ The following example demonstrates how to fetch and display information about al HRESULT error, ICoreWebView2ServiceWorkerRegistrationCollectionView* workerRegistrationCollection) -> HRESULT { - UINT32 workersCount = 0; - CHECK_FAILURE(workerRegistrationCollection->get_Count(&workersCount)); + if(workerRegistrationCollection) + { + UINT32 workersCount = 0; + CHECK_FAILURE(workerRegistrationCollection->get_Count(&workersCount)); - std::wstringstream message{}; - message << L"No of service workers registered: " << workersCount << std::endl; + std::wstringstream message{}; + message << L"No of service workers registered: " << workersCount << std::endl; - for (UINT32 i = 0; i < workersCount; i++) - { - Microsoft::WRL::ComPtr - serviceWorkerRegistration; - CHECK_FAILURE(workerRegistrationCollection->GetValueAtIndex( - i, &serviceWorkerRegistration)); + for (UINT32 i = 0; i < workersCount; i++) + { + Microsoft::WRL::ComPtr + serviceWorkerRegistration; + CHECK_FAILURE(workerRegistrationCollection->GetValueAtIndex( + i, &serviceWorkerRegistration)); - wil::unique_cotaskmem_string scope; - CHECK_FAILURE(serviceWorkerRegistration->get_Scope(&scope)); + wil::unique_cotaskmem_string scope; + CHECK_FAILURE(serviceWorkerRegistration->get_Scope(&scope)); - message << L"Scope: " << scope.get(); - } + message << L"Scope: " << scope.get(); + } - m_appWindow->AsyncMessageBox( - std::move(message.str()), L"Registered service workers"); + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Registered service workers"); + } return S_OK; }) @@ -391,40 +398,50 @@ The following example demonstrates how to obtain the service worker registration ICoreWebView2ServiceWorkerRegistration* serviceWorkerRegistration) -> HRESULT { - CHECK_FAILURE(serviceWorkerRegistration->GetServiceWorker( - Callback( - [this, &scope]( - HRESULT error, - ICoreWebView2ServiceWorker* serviceWorker) -> HRESULT - { - std::wstringstream message{}; - - if (serviceWorker != nullptr) - { - wil::com_ptr worker; - wil::unique_cotaskmem_string scriptUrl; - if (SUCCEEDED(serviceWorker->QueryInterface( - IID_PPV_ARGS(&worker)))) - { - CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); - } - - message << L"ScriptUrl: " << scriptUrl.get(); - message << std::endl; - } - else - { - message << L"No service worker available for the scope: " - << scope; - message << std::endl; - } - - m_appWindow->AsyncMessageBox( - std::move(message.str()), L"Service Worker"); - - return S_OK; - }) - .Get())); + CHECK_FAILURE(error); + if(serviceWorkerRegistration) + { + CHECK_FAILURE(serviceWorkerRegistration->GetServiceWorker( + Callback( + [this, &scope]( + HRESULT error, + ICoreWebView2ServiceWorker* serviceWorker) -> HRESULT + { + std::wstringstream message{}; + + if (serviceWorker != nullptr) + { + wil::com_ptr worker; + wil::unique_cotaskmem_string scriptUrl; + if (SUCCEEDED(serviceWorker->QueryInterface( + IID_PPV_ARGS(&worker)))) + { + CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + } + + message << L"ScriptUrl: " << scriptUrl.get(); + message << std::endl; + } + else + { + message << L"No service worker available for the scope: " + << scope; + message << std::endl; + } + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Service Worker"); + + return S_OK; + }) + .Get())); + } + else + { + m_appWindow->AsyncMessageBox( + L"No service worker registered for the scope: " + scope, + L"Service Worker"); + } return S_OK; }) @@ -569,31 +586,33 @@ The following example demonstrates how to fetch and display information about al HRESULT error, ICoreWebView2SharedWorkerCollectionView* workersCollection) -> HRESULT { - UINT32 workersCount = 0; - CHECK_FAILURE(workersCollection->get_Count(&workersCount)); + if(workersCollection) + { + UINT32 workersCount = 0; + CHECK_FAILURE(workersCollection->get_Count(&workersCount)); - std::wstringstream message{}; - message << L"No of shared workers created: " << workersCount << std::endl; + std::wstringstream message{}; + message << L"No of shared workers created: " << workersCount << std::endl; - for (UINT32 i = 0; i < workersCount; i++) - { - Microsoft::WRL::ComPtr sharedWorker; - CHECK_FAILURE(workersCollection->GetValueAtIndex(i, &sharedWorker)); - - wil::com_ptr worker; - if (SUCCEEDED(sharedWorker->QueryInterface(IID_PPV_ARGS(&worker)))) - { - wil::unique_cotaskmem_string scriptUrl; - CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); - - message << L"ScriptUrl: " << scriptUrl.get(); - message << std::endl; - } - } - - m_appWindow->AsyncMessageBox( - std::move(message.str()), L"Get all shared workers"); + for (UINT32 i = 0; i < workersCount; i++) + { + Microsoft::WRL::ComPtr sharedWorker; + CHECK_FAILURE(workersCollection->GetValueAtIndex(i, &sharedWorker)); + + wil::com_ptr worker; + if (SUCCEEDED(sharedWorker->QueryInterface(IID_PPV_ARGS(&worker)))) + { + wil::unique_cotaskmem_string scriptUrl; + CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + + message << L"ScriptUrl: " << scriptUrl.get(); + message << std::endl; + } + } + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Get all shared workers"); + } return S_OK; }) .Get())); @@ -882,7 +901,6 @@ interface ICoreWebView2Worker : IUnknown { /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). [propget] HRESULT ScriptUrl([out, retval] LPWSTR* value); - /// Add an event handler for the `Destroyed` event that is raised when the worker object is destroyed. /// A worker object is destroyed when the worker script is terminated or when the `CoreWebView2Worker` object is destroyed. HRESULT add_Destroyed( From 4ed60d92e8268247f57cefba97c181c0ae343eec Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Thu, 23 May 2024 16:41:45 -0700 Subject: [PATCH 3/7] Per feedback - reference dom apis and example of api usage in workers --- specs/Workers.md | 341 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 258 insertions(+), 83 deletions(-) diff --git a/specs/Workers.md b/specs/Workers.md index 1a71a6aec..addbd0450 100644 --- a/specs/Workers.md +++ b/specs/Workers.md @@ -32,10 +32,25 @@ We propose the introduction of APIs that enable the host application to oversee # Examples ## Dedicated Worker ## Monitoring the Creation/Destruction of Dedicated Workers. -The following example demonstrates how to subscribe to the event that is triggered when a web page creates a dedicated worker. This event provides a CoreWebView2DedicatedWorker object, enabling the host application to interact with it. +The following example demonstrates how to subscribe to the event that is triggered when a web page creates a dedicated worker. This event provides a `CoreWebView2DedicatedWorker` object, enabling the host application to interact with it. + +This example also showcases the utilization of the upcoming PostMessage and WorkerMessageReceived APIs. These APIs enable efficient communication between the main thread and a dedicated worker. ## .NET/WinRT ```c# + void PostMessageToWorker(CoreWebView2DedicatedWorker worker) + { + // Inside the worker, an event listener is set up for the 'message' event. When a message is received from the host application, the worker performs a fetch request. The host application also sets up an event listener to receive messages from the worker. These messages could contain fetched data or any error information from the worker's fetch operation. + worker.WorkerMessageReceived += (sender, args) => + { + var message = args.TryGetWebMessageAsString; + // This section of the code is dedicated to handling updates received from the worker. Depending on the nature of these updates, you might choose to perform various actions. For instance, you could modify the user interface to reflect the new data, or you could log the received data for debugging or record-keeping purposes. + }; + + // You can dispatch a message to the worker with the URL you want to fetch data from the host app. + worker.PostMessage("{type: 'FETCH_URL',url: 'https://example.com/data.json'"); + } + void DedicatedWorkerCreatedExecuted(object target, ExecutedRoutedEventArgs e) { webView.CoreWebView2.DedicatedWorkerCreated += (sender, args) => @@ -46,21 +61,44 @@ The following example demonstrates how to subscribe to the event that is trigger dedicatedWorker.WorkerDestroyed += (sender, args) => { /*Cleanup on worker destruction*/ - MessageBox.Show("Dedicated is destroyed" , "Dedicated Worker Message"); }; - var scriptUrl = dedicatedWorker.ScriptUrl; - MessageBox.Show("Dedicated is created at " + scriptUrl , "Dedicated Worker Message"); - } + var scriptUri = dedicatedWorker.ScriptUri; + MessageBox.Show("Dedicated is created at" + scriptUri , "Dedicated Worker Message"); + + // Send a message to the dedicated worker to offload fetch request from the host app. + dedicatedWorker.PostMessage(dialog.Input.Text); + } }; } ``` ## Win32 C++ ```cpp + void PostMessageToWorker(wil::com_ptr worker) + { + // Inside the worker, an event listener is set up for the 'message' event. When a message is received from the host application, the worker performs a fetch request. The host application also sets up an event listener to receive messages from the worker. These messages could contain fetched data or any error information from the worker's fetch operation. + CHECK_FAILURE(worker->add_WorkerMessageReceived( + Callback( + [this](ICoreWebView2Worker* sender, ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string message; + CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); + + // This section of the code is dedicated to handling updates received from the worker. Depending on the nature of these updates, you might choose to perform various actions. For instance, you could modify the user interface to reflect the new data, or you could log the received data for debugging or record-keeping purposes. + + return S_OK; + }) + .Get(), + nullptr)); + + // You can dispatch a message to the worker with the URL you want to fetch data from the host app. + CHECK_FAILURE(worker->PostMessage("{type: 'FETCH_URL',url: 'https://example.com/data.json'")); + } + ScenarioDedicatedWorker::ScenarioDedicatedWorker(AppWindow* appWindow) : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) { - m_webView2_25 = m_webView.try_query(); + m_webView2_25 = m_webView.try_query(); CHECK_FEATURE_RETURN_EMPTY(m_webView2_25); CHECK_FAILURE(m_webView2_25->add_DedicatedWorkerCreated( @@ -91,10 +129,14 @@ The following example demonstrates how to subscribe to the event that is trigger .Get(), nullptr)); - wil::unique_cotaskmem_string scriptUrl; - CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + wil::unique_cotaskmem_string ScriptUri; + CHECK_FAILURE(worker->get_ScriptUri(&ScriptUri)); - m_appWindow->AsyncMessageBox(scriptUrl.get(), L"Dedicated worker is created"); + std::wstring message = L"Dedicated worker is created at" + std::wstring(ScriptUri.get()); + m_appWindow->AsyncMessageBox(message, L"Dedicated worker is created"); + + // Send a message to the dedicated worker to offload fetch request from the host app. + PostMessageToWorker(worker); } } @@ -108,10 +150,24 @@ The following example demonstrates how to subscribe to the event that is trigger ## Service Worker ## Monitoring the Registration/Destruction of Service Workers -The following example demonstrates how to subscribe to the event that is triggered when a web page registers a service worker. This event provides a CoreWebView2 service worker registration object, enabling the host application to interact with the service workers. +The following example demonstrates how to subscribe to the event that is triggered when a web page registers a service worker. This event provides a `CoreWebView2ServiceWorkerRegistration` object, enabling the host application to interact with the service workers via upcoming PostMessage and WorkerMessageReceived APIs. ## .NET/WinRT ```c# + void PostMessageToWorker(CoreWebView2ServiceWorker worker) + { + // The service worker communicates updates back to the host application, such as when resource caching is complete. The host application can listen for the WorkerMessageReceived event to receive these updates from the service worker. + worker.WorkerMessageReceived += (sender, args) => + { + var message = args.TryGetWebMessageAsString; + + // Process the messages received from the worker. Depending on the content of these messages, you might choose to log the data for debugging, update the user interface to reflect changes, or trigger other actions within your application. + }; + + // You can send messages to the service worker using its PostMessage method. The host application is sending a message to the worker to cache certain resources. The message is a JSON string that specifies the type of the message and the payload of the message. + worker.PostMessage("{\"type\": \"CACHE_URLS\", \"payload\": [\"/styles/main.css\", \"/scripts/main.js\", \"/images/logo.png\"]}"); + } + CoreWebView2ServiceWorkerManager ServiceWorkerManager_; void ServiceWorkerRegisteredExecuted(object target, ExecutedRoutedEventArgs e) { @@ -127,7 +183,6 @@ The following example demonstrates how to subscribe to the event that is trigger serviceWorkerRegistration.WorkerDestroyed += (sender, args) => { /*Cleanup on worker destruction*/ - MessageBox.Show("Service worker registration object is destroyed" , "Service Worker Registration Message"); }; MessageBox.Show("Service worker is registered for " + serviceWorkerRegistration.Scope, "Service Worker Registration Message"); @@ -138,9 +193,10 @@ The following example demonstrates how to subscribe to the event that is trigger serviceWorker.WorkerDestroyed += (sender, args) => { /*Cleanup on worker destruction*/ - MessageBox.Show("Service worker object is destroyed" , "Service Worker Message"); }; - MessageBox.Show("Service worker is created.", "Service Worker Message"); + + // Send a list of resources to the service worker to cache. + PostMessageToWorker(serviceWorker); } else { @@ -152,6 +208,28 @@ The following example demonstrates how to subscribe to the event that is trigger ``` ## Win32 C++ ```cpp + + void PostMessageToWorker(wil::com_ptr worker) + { + // The service worker communicates updates back to the host application, such as when resource caching is complete. The host application can listen for the WorkerMessageReceived event to receive these updates from the service worker. + CHECK_FAILURE(worker->add_WorkerMessageReceived( + Callback( + [this](ICoreWebView2Worker* sender, ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string message; + CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); + + // Process the messages received from the worker. Depending on the content of these messages, you might choose to log the data for debugging, update the user interface to reflect changes, or trigger other actions within your application. + + return S_OK; + }) + .Get(), + nullptr)); + + // You can send messages to the service worker using its PostMessage method. The host application is sending a message to the worker to cache certain resources. The message is a JSON string that specifies the type of the message and the payload of the message. + CHECK_FAILURE(worker->PostMessage(L"{\"type\": \"CACHE_URLS\", \"payload\": [\"/styles/main.css\", \"/scripts/main.js\", \"/images/logo.png\"]}")); + } + void ScenarioServiceWorkerManager::CreateServiceWorkerManager() { auto webView2_13 = m_webView.try_query(); @@ -201,7 +279,6 @@ The following example demonstrates how to subscribe to the event that is trigger ICoreWebView2ServiceWorker* serviceWorker) -> HRESULT { wil::com_ptr worker; - wil::unique_cotaskmem_string scriptUrl; std::wstringstream message; if (serviceWorker) { @@ -222,9 +299,10 @@ The following example demonstrates how to subscribe to the event that is trigger .Get(), nullptr)); - CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + // Send a list of resources to the service worker to cache. + PostMessageToWorker(worker); } - message << L"ScriptUrl: " << scriptUrl.get(); + } else { @@ -248,7 +326,7 @@ The following example demonstrates how to subscribe to the event that is trigger ``` ## Retrieving Service Worker Registrations. -The following example demonstrates how to fetch and display information about all the service worker registrations associated with the WebView2 profile. +The following example below illustrates how to retrieve and present details about all service worker registrations linked to the WebView2 profile. This yields a list of `CoreWebView2ServiceWorkerRegistration` objects, enabling the host application to communicate directly with the service workers via post messaging. ## .NET/WinRT ```c# @@ -328,7 +406,7 @@ The following example demonstrates how to fetch and display information about al ## Retrieving Service Worker Registration for a Specific Scope. -The following example demonstrates how to obtain the service worker registration associated with a specific scope. This allows the application to interact with the service worker. +The following example illustrates how to retrieve the `CoreWebView2ServiceWorkerRegistration` associated with a specific scope. This enables the host application to establish a communication channel with the service worker, facilitating the exchange of messages. ## .NET/WinRT ```c# @@ -412,14 +490,14 @@ The following example demonstrates how to obtain the service worker registration if (serviceWorker != nullptr) { wil::com_ptr worker; - wil::unique_cotaskmem_string scriptUrl; + wil::unique_cotaskmem_string ScriptUri; if (SUCCEEDED(serviceWorker->QueryInterface( IID_PPV_ARGS(&worker)))) { - CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + CHECK_FAILURE(worker->get_ScriptUri(&ScriptUri)); } - message << L"ScriptUrl: " << scriptUrl.get(); + message << L"ScriptUri: " << ScriptUri.get(); message << std::endl; } else @@ -453,10 +531,24 @@ The following example demonstrates how to obtain the service worker registration ## Shared Worker ## Monitoring Shared Worker Creation and Destruction -The following example demonstrates how to subscribe to the shared worker creation event. This event is triggered when a web page creates a shared worker. It provides the host application with access to the CoreWebView2 shared worker object, enabling interaction with shared workers. +The following example illustrates how the host application initiates a WebSocket connection when a web page creates a shared worker, utilizing the Worker upcoming PostMessage and WorkerMessageReceived APIs. ## .NET/WinRT ```c# + void PostMessageToWorker(CoreWebView2SharedWorker worker) + { + // The shared worker communicates back to the host application with updates from the WebSocket. The host application can monitor this event to receive these updates from the shared worker. + worker.WorkerMessageReceived += (sender, args) => + { + var message = args.TryGetWebMessageAsString; + + // Record the updates from the WebSocket or modify the user interface according to the requirements of the host application. + }; + + // Initiate the WebSocket connection by sending a message to the shared worker. + worker.PostMessage("{\"type\": \"INITIATE_WEBSOCKET_CONNECTION\", \"payload\": \"wss://example.com\"}"); + } + CoreWebView2SharedWorkerManager SharedWorkerManager_; void SharedWorkerManagerExecuted(object target, ExecutedRoutedEventArgs e) { @@ -472,11 +564,13 @@ The following example demonstrates how to subscribe to the shared worker creatio sharedWorker.WorkerDestroyed += (sender, args) => { /*Cleanup on worker destruction*/ - MessageBox.Show("Shared worker is destroyed" , "Shared Worker Message"); }; - var stringUrl = sharedWorker.ScriptUrl; - MessageBox.Show("Shared is created at" + stringUrl , "Shared Worker Message"); + var scriptUri = sharedWorker.ScriptUri; + MessageBox.Show("Shared is created at" + scriptUri , "Shared Worker Message"); + + // You can utilizes a shared worker to maintain a WebSocket connection, enabling real-time updates through the PostMessage API. The shared worker establishes the WebSocket connection, receives real-time updates, and forwards these updates back to the host application. + PostMessageToWorker(worker); } }; } @@ -484,6 +578,27 @@ The following example demonstrates how to subscribe to the shared worker creatio ``` ## Win32 C++ ```cpp + void PostMessageToWorker(wil::com_ptr worker) + { + // The shared worker communicates back to the host application with updates from the WebSocket. The host application can monitor this event to receive these updates from the shared worker. + CHECK_FAILURE(worker->add_WorkerMessageReceived( + Callback( + [this](ICoreWebView2Worker* sender, ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string message; + CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); + + // Record the updates from the WebSocket or modify the user interface according to the requirements of the host application. + return S_OK; + }) + .Get(), + nullptr)); + + + // Initiate the WebSocket connection by sending a message to the shared worker. + CHECK_FAILURE(worker->PostMessage(L"{\"type\": \"INITIATE_WEBSOCKET_CONNECTION\", \"payload\": \"wss://example.com\"}")); + } + void ScenarioSharedWorkerManager::GetSharedWorkerManager() { auto webView2_13 = m_webView.try_query(); @@ -507,30 +622,39 @@ The following example demonstrates how to subscribe to the shared worker creatio wil::com_ptr sharedWorker; CHECK_FAILURE(args->get_Worker(&sharedWorker)); - wil::com_ptr worker = - sharedWorker.try_query(); - if(worker) - { - wil::unique_cotaskmem_string scriptUrl; - CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); - - // Subscribe to worker destroyed event - CHECK_FAILURE(worker->add_Destroyed( - Callback( - [this, &scriptUrl]( - ICoreWebView2Worker* sender, IUnknown* args) -> HRESULT - { - /*Cleanup on worker destruction*/ - m_appWindow->AsyncMessageBox( - scriptUrl.get(), L"Shared worker is destroyed"); - return S_OK; - }) - .Get(), - nullptr)); + if (sharedWorker) + { + wil::com_ptr worker = + sharedWorker.try_query(); - m_appWindow->AsyncMessageBox(scriptUrl.get(), L"Shared worker is created"); - } - return S_OK; + if (worker) + { + wil::unique_cotaskmem_string ScriptUri; + CHECK_FAILURE(worker->get_ScriptUri(&ScriptUri)); + + // Subscribe to worker destroyed event + worker->add_Destroyed( + Callback( + [this, &ScriptUri]( + ICoreWebView2StagingWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + return S_OK; + }) + .Get(), + nullptr); + + + std::wstring message = L"Shared worker is created at" + std::wstring(ScriptUri.get()); + m_appWindow->AsyncMessageBox(message, L"Shared worker is created"); + + // The host application leverages a shared worker to sustain a WebSocket connection, facilitating real-time updates. The initiation of the WebSocket connection is triggered by a message from the host app to the shared worker via the PostMessage API. The shared worker then establishes the WebSocket connection, receives real-time updates, and relays these updates back to the host application. + PostMessageToWorker(worker); + } + } + + return S_OK; }) .Get(), &m_sharedWorkerCreatedToken)); @@ -539,7 +663,8 @@ The following example demonstrates how to subscribe to the shared worker creatio ## Retrieving Shared Workers -The following example demonstrates how to fetch and display information about all the shared workers associated with the WebView2 profile. +The following example demonstrates how to query `CoreWebView2SharedWorkers` associated with the WebView2 profile for the host +app to interact with workers based on the app needs. Host app can directly talk to shared worker using CoreWebView2SharedWorker. ## .NET/WinRT ```c# @@ -551,6 +676,8 @@ The following example demonstrates how to fetch and display information about al { SharedWorkerManager_ = WebViewProfile.SharedWorkerManager; } + + // Creates an instance of CoreWebView2SharedWorker which can be used to communicate with the worker IReadOnlyList workerList = await SharedWorkerManager_.GetSharedWorkersAsync(); int workerCount = workerList.Count; StringBuilder messageBuilder = new StringBuilder(); @@ -558,9 +685,9 @@ The following example demonstrates how to fetch and display information about al for (int i = 0; i < workerCount; ++i) { - var stringUrl = workerList[i].ScriptUrl; + var stringUrl = workerList[i].ScriptUri; - messageBuilder.AppendLine($"ScriptUrl: {scriptUrl}"); + messageBuilder.AppendLine($"ScriptUri: {ScriptUri}"); }; MessageBox.Show(messageBuilder.ToString(), "Shared Workers", MessageBoxButton.OK); @@ -586,34 +713,34 @@ The following example demonstrates how to fetch and display information about al HRESULT error, ICoreWebView2SharedWorkerCollectionView* workersCollection) -> HRESULT { - if(workersCollection) - { - UINT32 workersCount = 0; - CHECK_FAILURE(workersCollection->get_Count(&workersCount)); + if(workersCollection) + { + UINT32 workersCount = 0; + CHECK_FAILURE(workersCollection->get_Count(&workersCount)); - std::wstringstream message{}; - message << L"No of shared workers created: " << workersCount << std::endl; + std::wstringstream message{}; + message << L"No of shared workers created: " << workersCount << std::endl; - for (UINT32 i = 0; i < workersCount; i++) - { - Microsoft::WRL::ComPtr sharedWorker; - CHECK_FAILURE(workersCollection->GetValueAtIndex(i, &sharedWorker)); + for (UINT32 i = 0; i < workersCount; i++) + { + Microsoft::WRL::ComPtr sharedWorker; + CHECK_FAILURE(workersCollection->GetValueAtIndex(i, &sharedWorker)); - wil::com_ptr worker; - if (SUCCEEDED(sharedWorker->QueryInterface(IID_PPV_ARGS(&worker)))) - { - wil::unique_cotaskmem_string scriptUrl; - CHECK_FAILURE(worker->get_ScriptUrl(&scriptUrl)); + wil::com_ptr worker; + if (SUCCEEDED(sharedWorker->QueryInterface(IID_PPV_ARGS(&worker)))) + { + wil::unique_cotaskmem_string ScriptUri; + CHECK_FAILURE(worker->get_ScriptUri(&ScriptUri)); - message << L"ScriptUrl: " << scriptUrl.get(); - message << std::endl; - } - } + message << L"ScriptUri: " << ScriptUri.get(); + message << std::endl; + } + } - m_appWindow->AsyncMessageBox( - std::move(message.str()), L"Get all shared workers"); - } - return S_OK; + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Get all the shared workers"); + } + return S_OK; }) .Get())); } @@ -639,7 +766,7 @@ typedef enum COREWEBVIEW2_SERVICE_WORKER_STATE { } COREWEBVIEW2_SERVICE_WORKER_STATE; [uuid(29b994e5-0ac8-5430-89fa-5b4bb2091d8d), object, pointer_default(unique)] -interface ICoreWebView225 : IUnknown { +interface ICoreWebView2_25 : IUnknown { /// Subscribe to this event that gets raised when a new dedicated worker is created. /// /// A Dedicated Worker is a type of web worker that allow you to run Javascript code in the background without blocking the main thread, making them useful for tasks like heavy computations, data processing, and parallel execution. @@ -720,13 +847,25 @@ interface ICoreWebView2ServiceWorkerManager : IUnknown { /// Gets a list of the service worker registrations under the same profile. + /// + /// This method returns a list of `CoreWebView2ServiceWorkerRegistration` objects, each representing a service worker registration. + /// + /// This method corresponds to the `getRegistrations` method of the `ServiceWorkerContainer` object in the DOM + /// which returns a Promise that resolves to an array of `ServiceWorkerRegistration` objects. + /// See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/getRegistrations) + /// for more information. HRESULT GetServiceWorkerRegistrations( [in] ICoreWebView2GetServiceWorkerRegistrationsCompletedHandler* handler ); /// Gets the service worker registration object associated with the specified scope. If a service worker has been registered - /// for the given scope, it gets the corresponding `CoreWebView2ServiceWorkerRegistration` object. - /// If scope is empty string or null, the completed handler immediately returns `E_POINTER` and with a null pointer. + /// + /// This corresponds to the `getRegistration` method of the `ServiceWorkerContainer` object in the DOM which + /// returns a Promise that resolves to a `ServiceWorkerRegistration` object. + /// See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/getRegistration) + /// for more information. + /// + /// If scope is empty string or null, the completed handler immediately returns `E_INVALIDARG` and with a null pointer. HRESULT GetServiceWorkerRegistration( [in] LPCWSTR scope , [in] ICoreWebView2GetServiceWorkerRegistrationCompletedHandler* handler @@ -764,6 +903,15 @@ interface ICoreWebView2ServiceWorkerRegisteredEventArgs : IUnknown { /// A string representing a URL that defines a service worker's registration scope. It is relative to the base URL of the application. /// By default, the scope value for a service worker registration is set to the directory where the service worker script is located. /// + /// The `scope` parameter will be a fully qualified URL that includes both the origin (scheme, host, and optionally port) and the path. + /// If the origin and scope includes an internationalized domain name (IDN), it should be represented in punycode format. + /// + /// For example, if the service worker script is located at https://example.com/sw.js, the default scope is https://example.com/, and the service worker controls all pages under https://example.com/ + /// If the scope is set to /app/ when registering the service worker, the scope will be https://example.com/app/. + /// + /// This corresponds to the `scope` property of the `ServiceWorkerRegistration` object in the DOM. + /// For more information, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/scope). + /// /// The caller must free the returned string with `CoTaskMemFree`. See /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). [propget] HRESULT Scope([out, retval] LPWSTR* value); @@ -806,6 +954,15 @@ interface ICoreWebView2ServiceWorkerRegistration : IUnknown { /// A string representing a URL that defines a service worker's registration scope. It is relative to the base URL of the application. /// By default, the scope value for a service worker registration is set to the directory where the service worker script is located. /// + /// The `scope` parameter will be a fully qualified URL that includes both the origin (scheme, host, and optionally port) and the path. + /// If the origin and scope includes an internationalized domain name (IDN), it should be represented in punycode format. + /// + /// For example, if the service worker script is located at https://example.com/sw.js, the default scope is https://example.com/, and the service worker controls all pages under https://example.com/ + /// If the scope is set to /app/ when registering the service worker, the scope will be https://example.com/app/. + /// + /// This corresponds to the `scope` property of the `ServiceWorkerRegistration` object in the DOM. + /// For more information, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/scope). + /// /// The caller must free the returned string with `CoTaskMemFree`. See /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). [propget] HRESULT Scope([out, retval] LPWSTR* value); @@ -828,6 +985,9 @@ interface ICoreWebView2ServiceWorkerRegistration : IUnknown { /// The active service worker that was created. If there is no active service worker, the completed handler immediately returns `S_OK` and with a null pointer. /// The active service worker is the service worker that controls the pages within the scope of the registration. See the [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker) /// for more information. + /// + /// This corresponds to the `active` property of the `ServiceWorkerRegistration` object in the DOM. + /// For more information, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/active). HRESULT GetServiceWorker( [in] ICoreWebView2GetServiceWorkerCompletedHandler* handler ); @@ -895,11 +1055,16 @@ interface ICoreWebView2SharedWorkerCollectionView : IUnknown { [uuid(06cfc21b-56e5-59b1-b7b4-13f197d4539d), object, pointer_default(unique)] interface ICoreWebView2Worker : IUnknown { - /// A string representing the URL of the script that the worker is executing. + /// A string representing the Uri of the script that the worker is executing. + /// + /// This corresponds to the `scriptURL` property of the `Worker` object in the DOM. + /// The `scriptURL` property returns a string representing the URL of the script that the worker is executing. + /// See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Worker/scriptURL) + /// for more information. /// /// The caller must free the returned string with `CoTaskMemFree`. See /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). - [propget] HRESULT ScriptUrl([out, retval] LPWSTR* value); + [propget] HRESULT ScriptUri([out, retval] LPWSTR* value); /// Add an event handler for the `Destroyed` event that is raised when the worker object is destroyed. /// A worker object is destroyed when the worker script is terminated or when the `CoreWebView2Worker` object is destroyed. @@ -925,6 +1090,9 @@ interface ICoreWebView2WorkerDestroyedEventHandler : IUnknown { interface ICoreWebView2DedicatedWorker : IUnknown { /// A string specified when creating a dedicated worker. /// + /// This corresponds to the `options.name` property passed to the `Worker` constructor in the DOM. + /// For more information, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker). + /// /// The caller must free the returned string with `CoTaskMemFree`. See /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). [propget] HRESULT Name([out, retval] LPWSTR* value); @@ -934,6 +1102,10 @@ interface ICoreWebView2DedicatedWorker : IUnknown { [uuid(de8ed42b-5128-55df-9dd0-ea1d4d706c87), object, pointer_default(unique)] interface ICoreWebView2ServiceWorker : IUnknown { /// The state of the service worker. A service worker can be in new, installing, installed, activating, activated, or redundant. + /// + /// This corresponds to the `state` property of the `ServiceWorker` object in the DOM. + /// See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/state) + /// for more information. [propget] HRESULT State([out, retval] COREWEBVIEW2_SERVICE_WORKER_STATE* value); } @@ -941,6 +1113,9 @@ interface ICoreWebView2ServiceWorker : IUnknown { interface ICoreWebView2SharedWorker : IUnknown { /// A string specified when creating a shared worker. /// + /// This corresponds to the `options.name` property passed to the `Worker` constructor in the DOM. + /// For more information, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker). + /// /// The caller must free the returned string with `CoTaskMemFree`. See /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). [propget] HRESULT Name([out, retval] LPWSTR* value); @@ -960,7 +1135,7 @@ runtimeclass CoreWebView2SharedWorker; namespace Microsoft.Web.WebView2.Core { - [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView225")] + [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2_25")] { event Windows.Foundation.TypedEventHandler DedicatedWorkerCreated; } @@ -975,7 +1150,7 @@ namespace Microsoft.Web.WebView2.Core { String Name { get; }; - String ScriptUrl { get; }; + String ScriptUri { get; }; event Windows.Foundation.TypedEventHandler Destroyed; } @@ -1022,7 +1197,7 @@ namespace Microsoft.Web.WebView2.Core runtimeclass CoreWebView2ServiceWorker { - String ScriptUrl { get; }; + String ScriptUri { get; }; CoreWebView2ServiceWorkerState State { get; }; @@ -1045,7 +1220,7 @@ namespace Microsoft.Web.WebView2.Core { String Name { get; }; - String ScriptUrl { get; }; + String ScriptUri { get; }; event Windows.Foundation.TypedEventHandler Destroyed; } From bc81bbf1bb5a673ecd5ee3f467374ee67295e864 Mon Sep 17 00:00:00 2001 From: Monica Chintala <69160047+monica-ch@users.noreply.github.com> Date: Wed, 5 Jun 2024 11:09:33 -0700 Subject: [PATCH 4/7] Update specs/Workers.md Co-authored-by: David Risney --- specs/Workers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/Workers.md b/specs/Workers.md index addbd0450..ca0ee2a59 100644 --- a/specs/Workers.md +++ b/specs/Workers.md @@ -17,7 +17,7 @@ Currently, WebView2 lacks comprehensive APIs for developers to fully utilize wor We propose the introduction of APIs that enable the host application to oversee workers. These APIs lay the groundwork for the development of additional APIs, facilitating direct interaction between the host application and the workers, and support background operations for service workers. -**DedicatedWorkerCreated**: This event, associated with CoreWebView2, is triggered when a web page initiates a dedicated worker. It grants access to the CoreWebView2DedicatedWorker object, which contains information such as the script URL and name. Additionally, it provides a 'destroy' event that is fired just before this object is due for destruction. +**DedicatedWorkerCreated**: This event, associated with CoreWebView2, is raised when a web page initiates a dedicated worker. It grants access to the CoreWebView2DedicatedWorker object, which contains information such as the script URL and name. Additionally, it provides a 'destroy' event that is fired just before this object is due for destruction. **ServiceWorkerRegistered**: This event, originating from the CoreWebView2ServiceWorkerManager associated with CoreWebView2Profile is triggered when a service worker is successfully registered within the context of a WebView2 application for the profile. This event provides access to a CoreWebView2ServiceWorkerRegistration object, which encapsulates information about the registered service worker, such as its script URL and scope. Additionally, it enables subscription to the service worker's lifecycle events, including updates and unregistration. From 28f1039ded29799e4b2e905bfd0cbb89062f686e Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Thu, 6 Jun 2024 12:43:55 -0700 Subject: [PATCH 5/7] address feedback-2 --- specs/Workers.md | 549 +++++++++++++++++++++++++++++++---------------- 1 file changed, 360 insertions(+), 189 deletions(-) diff --git a/specs/Workers.md b/specs/Workers.md index ca0ee2a59..fec470dc4 100644 --- a/specs/Workers.md +++ b/specs/Workers.md @@ -2,52 +2,134 @@ Workers support in WebView2 === # Background -Currently, WebView2 lacks comprehensive APIs for developers to fully utilize workers, leading to increased load on the main thread, offloading to native, or forking your web app for WebView2 scenarios. To address this, the WebView2 team is introducing support for worker scenarios. This enhancement allows WebView2 users to interact with Web Workers from native apps, bypassing the JavaScript thread to boost app performance and responsiveness, or to run tasks in the background for offline support, push notifications, background sync, content updates, and more. As a part of the work, the WebView2 team is adding support for [Dedicated Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API), [Shared Workers](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker), and [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). While there are various types of web workers, our initial focus is on these three, with plans to broaden our support for other workers in the future. - -**What is Web Worker?** -[Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) allow web content to execute scripts in background threads, enabling tasks to run independently of the user interface and facilitating communication between threads using message passing. Web Workers can also make network requests using fetch() or XMLHttpRequest APIs. Few examples of workers are - -- **Dedicated Worker**: Dedicated Workers are a type of Web Worker that operates independently in the background of a web page, enabling parallel execution of tasks without blocking the main UI thread. They are created by specific web pages and communicate with them via message passing, making them ideal for offloading CPU-intensive operations and improving overall performance and responsiveness of web applications. - -- **Shared Worker**: Shared Workers are a type of Web Worker that can be accessed by multiple scripts running in different windows, IFrames, or other contexts, as long as they are within the same domain as the worker. Unlike Dedicated Workers, which are tied to a specific web page, Shared Workers require communication via an active port, making them slightly more complex to implement but enabling collaboration and shared resources across different parts of a web application. - -- **Service Worker**: Service Workers serve as intermediary agents between web applications, the browser, and the network, functioning as proxy servers. Primarily, they facilitate the development of seamless offline experiences by caching resources and enabling web apps to continue functioning without an internet connection. Additionally, Service Workers intercept network requests, enabling customized responses based on network availability, and can update server-side assets. Moreover, they grant access to push notifications and background sync APIs, enhancing the functionality and interactivity of web applications. +Currently, WebView2 lacks comprehensive APIs for developers to fully utilize +workers, leading to increased load on the main thread, offloading to native, or +forking your web app for WebView2 scenarios. To address this, the WebView2 team +is introducing support for worker scenarios. This enhancement allows WebView2 +users to interact with Web Workers from native apps, bypassing the JavaScript +thread to boost app performance and responsiveness, or to run tasks in the +background for offline support, push notifications, background sync, content +updates, and more. As a part of the work, the WebView2 team is adding support +for [Dedicated Workers](https://developer.mozilla.org/docs/Web/API/Web_Workers_API), [Shared Workers](https://developer.mozilla.org/docs/Web/API/SharedWorker), and [Service Workers](https://developer.mozilla.org/docs/Web/API/Service_Worker_API). +While there are various types of web workers, our initial focus is on these three, +with plans to broaden our support for other workers in the future. + +**What is Web Worker?** [Web Workers](https://developer.mozilla.org/docs/Web/API/Web_Workers_API) allow web +content to execute scripts in background threads, enabling tasks to run +independently of the user interface and facilitating communication between +threads using message passing. Web Workers can also make network requests using +fetch() or XMLHttpRequest APIs. Few examples of workers are + +- **Dedicated Worker**: Dedicated Workers are a type of Web Worker that operates + independently in the background of a web page, enabling parallel execution of + tasks without blocking the main UI thread. They are created by specific web + pages and communicate with them via message passing, making them ideal for + offloading CPU-intensive operations and improving overall performance and + responsiveness of web applications. + +- **Shared Worker**: Shared Workers are a type of Web Worker that can be + accessed by multiple scripts running in different windows, IFrames, or other + contexts, as long as they are within the same domain as the worker. Unlike + Dedicated Workers, which are tied to a specific web page, Shared Workers + require communication via an active port, making them slightly more complex to + implement but enabling collaboration and shared resources across different + parts of a web application. + +- **Service Worker**: Service Workers serve as intermediary agents between web + applications, the browser, and the network, functioning as proxy servers. + Primarily, they facilitate the development of seamless offline experiences by + caching resources and enabling web apps to continue functioning without an + internet connection. Additionally, Service Workers intercept network requests, + enabling customized responses based on network availability, and can update + server-side assets. Moreover, they grant access to push notifications and + background sync APIs, enhancing the functionality and interactivity of web + applications. # Description -We propose the introduction of APIs that enable the host application to oversee workers. These APIs lay the groundwork for the development of additional APIs, facilitating direct interaction between the host application and the workers, and support background operations for service workers. - -**DedicatedWorkerCreated**: This event, associated with CoreWebView2, is raised when a web page initiates a dedicated worker. It grants access to the CoreWebView2DedicatedWorker object, which contains information such as the script URL and name. Additionally, it provides a 'destroy' event that is fired just before this object is due for destruction. - -**ServiceWorkerRegistered**: This event, originating from the CoreWebView2ServiceWorkerManager associated with CoreWebView2Profile is triggered when a service worker is successfully registered within the context of a WebView2 application for the profile. This event provides access to a CoreWebView2ServiceWorkerRegistration object, which encapsulates information about the registered service worker, such as its script URL and scope. Additionally, it enables subscription to the service worker's lifecycle events, including updates and unregistration. - -**GetServiceWorkerRegistrations**: The GetServiceWorkerRegistrations method, part of the CoreWebViewServiceWorkerManager class, is used to retrieve all service worker registrations within the context of a WebView2 application for the profile. This method gives a collection of CoreWebView2ServiceWorkerRegistration objects, each encapsulating information about a registered service worker, such as its script URL and scope. - -**GetServiceWorkerRegistration**: The GetServiceWorkerRegistration method, part of the CoreWebViewServiceWorkerManager class, is used to retrieve a specific service worker registration within the context of a WebView2 application for the profile. This asynchronous method takes a scope as an argument and returns a CoreWebView2ServiceWorkerRegistration object that encapsulates information about the registered service worker with the given scope, such as its script URL. This method is useful for accessing details of a specific service worker based on its scope. - -**SharedWorkerCreated**: This event, originating from the CoreWebView2SharedWorkerManager associated with CoreWebView2Profile, is triggered when a shared worker is successfully created within the context of a WebView2 application for the profile. It grants access to the CoreWebView2SharedWorker object, which contains information such as the script URL and name. Additionally, it provides a 'destroy' event that is fired just before this object is due for destruction. - -**GetSharedWorkers**: The GetSharedWorkers method, part of the CoreWebViewSharedWorkerManager class, is used to retrieve all shared workers created within the context of a WebView2 application for the profile. This method gives a collection of CoreWebView2SharedWorkers objects. +We propose the introduction of APIs that enable the host application to oversee +workers. These APIs lay the groundwork for the development of additional APIs, +facilitating direct interaction between the host application and the workers, +and support background operations for service workers. + +**DedicatedWorkerCreated**: This event, associated with CoreWebView2, is raised +when a web page initiates a dedicated worker. It grants access to the +CoreWebView2DedicatedWorker object, which contains information such as the +script URL and name. Additionally, it provides a 'destroy' event that is raised +just before this object is due for destruction. + +**ServiceWorkerRegistered**: This event, originating from the +CoreWebView2ServiceWorkerManager associated with CoreWebView2Profile is raised +when a service worker is successfully registered within the context of a +WebView2 application for the profile. This event provides access to a +CoreWebView2ServiceWorkerRegistration object, which encapsulates information +about the registered service worker, such as its script URL and scope. +Additionally, it enables subscription to the service worker's lifecycle events, +including updates and unregistration. + +**GetServiceWorkerRegistrations**: The GetServiceWorkerRegistrations method, +part of the CoreWebView2ServiceWorkerManager class, is used to retrieve all +service worker registrations within the context of a WebView2 application for +the profile. This method gives a collection of +CoreWebView2ServiceWorkerRegistration objects, each encapsulating information +about a registered service worker, such as its script URL and scope. + +**GetServiceWorkerRegistration**: The GetServiceWorkerRegistration method, part +of the CoreWebView2ServiceWorkerManager class, is used to retrieve a specific +service worker registration within the context of a WebView2 application for the +profile. This asynchronous method takes a scope as an argument and returns a +CoreWebView2ServiceWorkerRegistration object that encapsulates information about +the registered service worker with the given scope, such as its script URL. This +method is useful for accessing details of a specific service worker based on its +scope. + +**SharedWorkerCreated**: This event, originating from the +CoreWebView2SharedWorkerManager associated with CoreWebView2Profile, is raised +when a shared worker is successfully created within the context of a WebView2 +application for the profile. It grants access to the CoreWebView2SharedWorker +object, which contains information such as the script URL and name. +Additionally, it provides a 'destroy' event that is raised just before this +object is due for destruction. + +**GetSharedWorkers**: The GetSharedWorkers method, part of the +CoreWebViewSharedWorkerManager class, is used to retrieve all shared workers +created within the context of a WebView2 application for the profile. This +method gives a collection of CoreWebView2SharedWorkers objects. # Examples ## Dedicated Worker ## Monitoring the Creation/Destruction of Dedicated Workers. -The following example demonstrates how to subscribe to the event that is triggered when a web page creates a dedicated worker. This event provides a `CoreWebView2DedicatedWorker` object, enabling the host application to interact with it. +The following example demonstrates how to subscribe to the event that is raised +when a web page creates a dedicated worker. This event provides a +`CoreWebView2DedicatedWorker` object, enabling the host application to interact +with it. -This example also showcases the utilization of the upcoming PostMessage and WorkerMessageReceived APIs. These APIs enable efficient communication between the main thread and a dedicated worker. +This example also showcases the utilization of the upcoming PostMessage and +WorkerMessageReceived APIs. These APIs enable efficient communication between +the main thread and a dedicated worker. ## .NET/WinRT ```c# void PostMessageToWorker(CoreWebView2DedicatedWorker worker) { - // Inside the worker, an event listener is set up for the 'message' event. When a message is received from the host application, the worker performs a fetch request. The host application also sets up an event listener to receive messages from the worker. These messages could contain fetched data or any error information from the worker's fetch operation. + // Inside the worker, an event listener is set up for the 'message' event. + // When a message is received from the host application, the worker + // performs a fetch request. The host application also sets up an event + // listener to receive messages from the worker. These messages could + // contain fetched data or any error information from the worker's fetch + // operation. worker.WorkerMessageReceived += (sender, args) => { var message = args.TryGetWebMessageAsString; - // This section of the code is dedicated to handling updates received from the worker. Depending on the nature of these updates, you might choose to perform various actions. For instance, you could modify the user interface to reflect the new data, or you could log the received data for debugging or record-keeping purposes. + // This section of the code is dedicated to handling updates received + // from the worker. Depending on the nature of these updates, you + // might choose to perform various actions. For instance, you could + // modify the user interface to reflect the new data, or you could + // log the received data for debugging or record-keeping purposes. }; - // You can dispatch a message to the worker with the URL you want to fetch data from the host app. + // You can dispatch a message to the worker with the URL you want to + // fetch data from the host app. worker.PostMessage("{type: 'FETCH_URL',url: 'https://example.com/data.json'"); } @@ -58,17 +140,17 @@ This example also showcases the utilization of the upcoming PostMessage and Work CoreWebView2DedicatedWorker dedicatedWorker = args.Worker; if(dedicatedWorker != null) { - dedicatedWorker.WorkerDestroyed += (sender, args) => - { - /*Cleanup on worker destruction*/ - }; + dedicatedWorker.WorkerDestroyed += (sender, args) => + { + /*Cleanup on worker destruction*/ + }; - var scriptUri = dedicatedWorker.ScriptUri; - MessageBox.Show("Dedicated is created at" + scriptUri , "Dedicated Worker Message"); + string scriptUri = dedicatedWorker.ScriptUri; + LogMessage("Dedicated Worker has been created with the script located at the " + scriptUri); // Send a message to the dedicated worker to offload fetch request from the host app. - dedicatedWorker.PostMessage(dialog.Input.Text); - } + dedicatedWorker.PostMessage(dedicatedWorker); + } }; } ``` @@ -76,22 +158,34 @@ This example also showcases the utilization of the upcoming PostMessage and Work ```cpp void PostMessageToWorker(wil::com_ptr worker) { - // Inside the worker, an event listener is set up for the 'message' event. When a message is received from the host application, the worker performs a fetch request. The host application also sets up an event listener to receive messages from the worker. These messages could contain fetched data or any error information from the worker's fetch operation. + // Inside the worker, an event listener is set up for the 'message' event. + // When a message is received from the host application, the worker performs + // a fetch request. The host application also sets up an event listener + // to receive messages from the worker. These messages could contain + // fetched data or any error information from the worker's fetch operation. CHECK_FAILURE(worker->add_WorkerMessageReceived( Callback( - [this](ICoreWebView2Worker* sender, ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT + [this](ICoreWebView2Worker* sender, + ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT { wil::unique_cotaskmem_string message; CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); - // This section of the code is dedicated to handling updates received from the worker. Depending on the nature of these updates, you might choose to perform various actions. For instance, you could modify the user interface to reflect the new data, or you could log the received data for debugging or record-keeping purposes. + // This section of the code is dedicated to handling + // updates received from the worker. Depending on the + // nature of these updates, you might choose to perform + // various actions. For instance, you could modify + // the user interface to reflect the new data, or you + // could log the received data for debugging or + // record-keeping purposes. return S_OK; }) .Get(), nullptr)); - // You can dispatch a message to the worker with the URL you want to fetch data from the host app. + // You can dispatch a message to the worker with the URL you want to fetch data from + // the host app. CHECK_FAILURE(worker->PostMessage("{type: 'FETCH_URL',url: 'https://example.com/data.json'")); } @@ -132,11 +226,11 @@ This example also showcases the utilization of the upcoming PostMessage and Work wil::unique_cotaskmem_string ScriptUri; CHECK_FAILURE(worker->get_ScriptUri(&ScriptUri)); - std::wstring message = L"Dedicated worker is created at" + std::wstring(ScriptUri.get()); - m_appWindow->AsyncMessageBox(message, L"Dedicated worker is created"); + LogMessage(L"Dedicated Worker has been created with the script located at the " + std::wstring(ScriptUri.get())); - // Send a message to the dedicated worker to offload fetch request from the host app. - PostMessageToWorker(worker); + // Send a message to the dedicated worker to offload fetch + // request from the host app. + PostMessageToWorker(worker); } } @@ -150,21 +244,34 @@ This example also showcases the utilization of the upcoming PostMessage and Work ## Service Worker ## Monitoring the Registration/Destruction of Service Workers -The following example demonstrates how to subscribe to the event that is triggered when a web page registers a service worker. This event provides a `CoreWebView2ServiceWorkerRegistration` object, enabling the host application to interact with the service workers via upcoming PostMessage and WorkerMessageReceived APIs. +The following example demonstrates how to subscribe to the event that is raised +when a web page registers a service worker. This event provides a +`CoreWebView2ServiceWorkerRegistration` object, enabling the host application to +interact with the service workers via upcoming PostMessage and +WorkerMessageReceived APIs. ## .NET/WinRT ```c# void PostMessageToWorker(CoreWebView2ServiceWorker worker) { - // The service worker communicates updates back to the host application, such as when resource caching is complete. The host application can listen for the WorkerMessageReceived event to receive these updates from the service worker. + // The service worker communicates updates back to the host application, + // such as when resource caching is complete. The host application can + // listen for the WorkerMessageReceived event to receive these updates + // from the service worker. worker.WorkerMessageReceived += (sender, args) => { var message = args.TryGetWebMessageAsString; - // Process the messages received from the worker. Depending on the content of these messages, you might choose to log the data for debugging, update the user interface to reflect changes, or trigger other actions within your application. + // Process the messages received from the worker. Depending on the + // content of these messages, you might choose to log the data for + // debugging, update the user interface to reflect changes, or raise + // other actions within your application. }; - // You can send messages to the service worker using its PostMessage method. The host application is sending a message to the worker to cache certain resources. The message is a JSON string that specifies the type of the message and the payload of the message. + // You can send messages to the service worker using its PostMessage method. + // The host application is sending a message to the worker to cache certain + // resources. The message is a JSON string that specifies the type of the + // message and the payload of the message. worker.PostMessage("{\"type\": \"CACHE_URLS\", \"payload\": [\"/styles/main.css\", \"/scripts/main.js\", \"/images/logo.png\"]}"); } @@ -185,9 +292,11 @@ The following example demonstrates how to subscribe to the event that is trigger /*Cleanup on worker destruction*/ }; - MessageBox.Show("Service worker is registered for " + serviceWorkerRegistration.Scope, "Service Worker Registration Message"); + LogMessage("Service worker has been registered with a scope: " + serviceWorkerRegistration.Scope); + + CoreWebView2ServiceWorker serviceWorker = await + serviceWorkerRegistration.GetActiveServiceWorkerAsync(); - CoreWebView2ServiceWorker serviceWorker = await serviceWorkerRegistration.GetServiceWorkerAsync(); if (serviceWorker != null) { serviceWorker.WorkerDestroyed += (sender, args) => @@ -200,7 +309,7 @@ The following example demonstrates how to subscribe to the event that is trigger } else { - MessageBox.Show("No active service available.", "Service Worker Message"); + LogMessage("No active service worker available."); } } }; @@ -211,22 +320,33 @@ The following example demonstrates how to subscribe to the event that is trigger void PostMessageToWorker(wil::com_ptr worker) { - // The service worker communicates updates back to the host application, such as when resource caching is complete. The host application can listen for the WorkerMessageReceived event to receive these updates from the service worker. + // The service worker communicates updates back to the host application, + // such as when resource caching is complete. The host application can + // listen for the WorkerMessageReceived event to receive these updates + // from the service worker. CHECK_FAILURE(worker->add_WorkerMessageReceived( Callback( - [this](ICoreWebView2Worker* sender, ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT + [this](ICoreWebView2Worker* sender, + ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT { wil::unique_cotaskmem_string message; CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); - // Process the messages received from the worker. Depending on the content of these messages, you might choose to log the data for debugging, update the user interface to reflect changes, or trigger other actions within your application. + // Process the messages received from the worker. + // Depending on the content of these messages, + // you might choose to log the data for debugging, + // update the user interface to reflect changes, + // or raise other actions within your application. return S_OK; }) .Get(), nullptr)); - // You can send messages to the service worker using its PostMessage method. The host application is sending a message to the worker to cache certain resources. The message is a JSON string that specifies the type of the message and the payload of the message. + // You can send messages to the service worker using its PostMessage method. + // The host application is sending a message to the worker to cache certain + // resources. The message is a JSON string that specifies the type of the + // message and the payload of the message. CHECK_FAILURE(worker->PostMessage(L"{\"type\": \"CACHE_URLS\", \"payload\": [\"/styles/main.css\", \"/scripts/main.js\", \"/images/logo.png\"]}")); } @@ -272,8 +392,8 @@ The following example demonstrates how to subscribe to the event that is trigger wil::unique_cotaskmem_string scope; CHECK_FAILURE(serviceWorkerRegistration->get_Scope(&scope)); - CHECK_FAILURE(serviceWorkerRegistration->GetServiceWorker( - Callback( + CHECK_FAILURE(serviceWorkerRegistration->GetActiveServiceWorker( + Callback( [this, &scope]( HRESULT error, ICoreWebView2ServiceWorker* serviceWorker) -> HRESULT @@ -302,20 +422,17 @@ The following example demonstrates how to subscribe to the event that is trigger // Send a list of resources to the service worker to cache. PostMessageToWorker(worker); } - } else { - message << L"No active service worker is available."; + LogMessage(L"No active service worker available"); } - m_appWindow->AsyncMessageBox(message.str(), L"Service worker"); - return S_OK; }) .Get())); - m_appWindow->AsyncMessageBox(scope.get(), L"Registered service worker for: "); + LogMessage(L"Service worker has been registered with a scope: " + std::wstring(scope.get())); } return S_OK; @@ -326,7 +443,11 @@ The following example demonstrates how to subscribe to the event that is trigger ``` ## Retrieving Service Worker Registrations. -The following example below illustrates how to retrieve and present details about all service worker registrations linked to the WebView2 profile. This yields a list of `CoreWebView2ServiceWorkerRegistration` objects, enabling the host application to communicate directly with the service workers via post messaging. +The following example below illustrates how to retrieve and present details +about all service worker registrations linked to the WebView2 profile. This +yields a list of `CoreWebView2ServiceWorkerRegistration` objects, enabling the +host application to communicate directly with the service workers via post +messaging. ## .NET/WinRT ```c# @@ -338,7 +459,9 @@ The following example below illustrates how to retrieve and present details abou { ServiceWorkerManager_ = WebViewProfile.ServiceWorkerManager; } - IReadOnlyList registrationList = await ServiceWorkerManager_.GetServiceWorkerRegistrationsAsync(); + IReadOnlyList registrationList = await + ServiceWorkerManager_.GetServiceWorkerRegistrationsAsync(); + int registrationCount = registrationList.Count; StringBuilder messageBuilder = new StringBuilder(); messageBuilder.AppendLine($"No of service workers registered: {registrationCount}"); @@ -350,12 +473,11 @@ The following example below illustrates how to retrieve and present details abou messageBuilder.AppendLine($"Scope: {scope}"); }; - MessageBox.Show(messageBuilder.ToString(), "Service Worker Registrations", MessageBoxButton.OK); + LogMessage(messageBuilder.ToString()); } catch (NotImplementedException exception) { - MessageBox.Show(this, "GetServiceWorkerRegistrationsAsync Failed: " + exception.Message, - "Get Service Worker Registrations Info"); + LogMessage("GetServiceWorkerRegistrationsAsync failed: " + exception.Message); } } ``` @@ -394,8 +516,7 @@ The following example below illustrates how to retrieve and present details abou message << L"Scope: " << scope.get(); } - m_appWindow->AsyncMessageBox( - std::move(message.str()), L"Registered service workers"); + LogMessage(std::wstring(message.str())); } return S_OK; @@ -406,7 +527,10 @@ The following example below illustrates how to retrieve and present details abou ## Retrieving Service Worker Registration for a Specific Scope. -The following example illustrates how to retrieve the `CoreWebView2ServiceWorkerRegistration` associated with a specific scope. This enables the host application to establish a communication channel with the service worker, facilitating the exchange of messages. +The following example illustrates how to retrieve the +`CoreWebView2ServiceWorkerRegistration` associated with a specific scope. This +enables the host application to establish a communication channel with the +service worker, facilitating the exchange of messages. ## .NET/WinRT ```c# @@ -424,37 +548,35 @@ The following example illustrates how to retrieve the `CoreWebView2ServiceWorker { ServiceWorkerManager_ = WebViewProfile.ServiceWorkerManager; } - CoreWebView2ServiceWorkerRegistration registration = await ServiceWorkerManager_.GetServiceWorkerRegistrationAsync(dialog.Input.Text); + CoreWebView2ServiceWorkerRegistration registration = await + ServiceWorkerManager_.GetServiceWorkerRegistrationAsync(dialog.Input.Text); + if(registration != null) { - StringBuilder messageBuilder = new StringBuilder(); - - CoreWebView2ServiceWorker worker = await registration.GetServiceWorkerAsync(); + CoreWebView2ServiceWorker worker = await registration.GetActiveServiceWorkerAsync(); if(worker != null) { - messageBuilder.AppendLine($"Service worker for scope '{dialog.Input.Text}' fetched successfully."); - - MessageBox.Show(messageBuilder.ToString(), "Service Worker Registrations", MessageBoxButton.OK); + LogMessage("Service worker for scope " + dialog.Input.Text + " fetched successfully"); } else { - MessageBox.Show("No active service worker for " + dialog.Input.Text, "Service Worker Registrations", MessageBoxButton.OK); + LogMessage("No active service worker available"); } } else { - MessageBox.Show("No service worker registered for " + dialog.Input.Text, "Service Worker Registrations", MessageBoxButton.OK); + LogMessage("No service worker registered for " + dialog.Input.Text); } } catch (NotImplementedException exception) { - MessageBox.Show(this, "GetServiceWorkerRegistrationsAsync Failed: " + exception.Message, - "Get Service Workers Info"); + + LogMessage("GetServiceWorkerRegistrationsAsync failed: " + exception.Message); } } } ``` ## Win32 C++ ```cpp - void ScenarioServiceWorkerManager::GetServiceWorkerRegistrateredForScope() + void ScenarioServiceWorkerManager::GetServiceWorkerRegisteredForScope() { if (!m_serviceWorkerManager) { @@ -468,6 +590,11 @@ The following example illustrates how to retrieve the `CoreWebView2ServiceWorker if (dialog.confirmed) { + // The 'scope' is a fully qualified URL that defines the range of URLs + // a service worker can control. For example, if you registered a service + // worker with a 'scope' of '/app/' for an application at https://example.com/, + // you should specify the full qualified URL i.e., https://example.com/app/ + // when calling this method. CHECK_FAILURE(m_serviceWorkerManager->GetServiceWorkerRegistration( dialog.input.c_str(), Callback( @@ -479,14 +606,12 @@ The following example illustrates how to retrieve the `CoreWebView2ServiceWorker CHECK_FAILURE(error); if(serviceWorkerRegistration) { - CHECK_FAILURE(serviceWorkerRegistration->GetServiceWorker( + CHECK_FAILURE(serviceWorkerRegistration->GetActiveServiceWorker( Callback( [this, &scope]( HRESULT error, ICoreWebView2ServiceWorker* serviceWorker) -> HRESULT { - std::wstringstream message{}; - if (serviceWorker != nullptr) { wil::com_ptr worker; @@ -497,28 +622,22 @@ The following example illustrates how to retrieve the `CoreWebView2ServiceWorker CHECK_FAILURE(worker->get_ScriptUri(&ScriptUri)); } - message << L"ScriptUri: " << ScriptUri.get(); - message << std::endl; + LogMessage(L"Service worker for scope " + scope + + L" fetched successfully from the script " + + std::wstring(ScriptUri.get())); } else { - message << L"No service worker available for the scope: " - << scope; - message << std::endl; + LogMessage(L"No service worker available"); } - m_appWindow->AsyncMessageBox( - std::move(message.str()), L"Service Worker"); - return S_OK; }) .Get())); } else { - m_appWindow->AsyncMessageBox( - L"No service worker registered for the scope: " + scope, - L"Service Worker"); + LogMessage(L"No service worker registered for the scope: " + scope); } return S_OK; @@ -531,18 +650,23 @@ The following example illustrates how to retrieve the `CoreWebView2ServiceWorker ## Shared Worker ## Monitoring Shared Worker Creation and Destruction -The following example illustrates how the host application initiates a WebSocket connection when a web page creates a shared worker, utilizing the Worker upcoming PostMessage and WorkerMessageReceived APIs. +The following example illustrates how the host application initiates a WebSocket +connection when a web page creates a shared worker, utilizing the Worker +upcoming PostMessage and WorkerMessageReceived APIs. ## .NET/WinRT ```c# void PostMessageToWorker(CoreWebView2SharedWorker worker) { - // The shared worker communicates back to the host application with updates from the WebSocket. The host application can monitor this event to receive these updates from the shared worker. + // The shared worker communicates back to the host application with updates + // from the WebSocket. The host application can monitor this event to receive + // these updates from the shared worker. worker.WorkerMessageReceived += (sender, args) => { var message = args.TryGetWebMessageAsString; - // Record the updates from the WebSocket or modify the user interface according to the requirements of the host application. + // Record the updates from the WebSocket or modify the user interface + // according to the requirements of the host application. }; // Initiate the WebSocket connection by sending a message to the shared worker. @@ -566,10 +690,12 @@ The following example illustrates how the host application initiates a WebSocket /*Cleanup on worker destruction*/ }; - var scriptUri = sharedWorker.ScriptUri; - MessageBox.Show("Shared is created at" + scriptUri , "Shared Worker Message"); + LogMessage("Shared Worker has been created with the script located at the " + scriptUri); - // You can utilizes a shared worker to maintain a WebSocket connection, enabling real-time updates through the PostMessage API. The shared worker establishes the WebSocket connection, receives real-time updates, and forwards these updates back to the host application. + // You can utilizes a shared worker to maintain a WebSocket + // connection, enabling real-time updates through the PostMessage API. + // The shared worker establishes the WebSocket connection, receives + // real-time updates, and forwards these updates back to the host application. PostMessageToWorker(worker); } }; @@ -580,15 +706,20 @@ The following example illustrates how the host application initiates a WebSocket ```cpp void PostMessageToWorker(wil::com_ptr worker) { - // The shared worker communicates back to the host application with updates from the WebSocket. The host application can monitor this event to receive these updates from the shared worker. + // The shared worker communicates back to the host application with + // updates from the WebSocket. The host application can monitor this + // event to receive these updates from the shared worker. CHECK_FAILURE(worker->add_WorkerMessageReceived( Callback( - [this](ICoreWebView2Worker* sender, ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT + [this](ICoreWebView2Worker* sender, + ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT { wil::unique_cotaskmem_string message; CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); - // Record the updates from the WebSocket or modify the user interface according to the requirements of the host application. + // Record the updates from the WebSocket or + // modify the user interface according to the + // requirements of the host application. return S_OK; }) .Get(), @@ -646,10 +777,15 @@ The following example illustrates how the host application initiates a WebSocket nullptr); - std::wstring message = L"Shared worker is created at" + std::wstring(ScriptUri.get()); - m_appWindow->AsyncMessageBox(message, L"Shared worker is created"); + LogMessage(L"Shared Worker has been created with the script located at the " + std::wstring(ScriptUri.get())); - // The host application leverages a shared worker to sustain a WebSocket connection, facilitating real-time updates. The initiation of the WebSocket connection is triggered by a message from the host app to the shared worker via the PostMessage API. The shared worker then establishes the WebSocket connection, receives real-time updates, and relays these updates back to the host application. + // The host application leverages a shared worker to sustain + // a WebSocket connection, facilitating real-time updates. + // The initiation of the WebSocket connection is raised by a + // message from the host app to the shared worker via the + // PostMessage API. The shared worker then establishes the + // WebSocket connection, receives real-time updates, and + // relays these updates back to the host application. PostMessageToWorker(worker); } } @@ -663,8 +799,10 @@ The following example illustrates how the host application initiates a WebSocket ## Retrieving Shared Workers -The following example demonstrates how to query `CoreWebView2SharedWorkers` associated with the WebView2 profile for the host -app to interact with workers based on the app needs. Host app can directly talk to shared worker using CoreWebView2SharedWorker. +The following example demonstrates how to query `CoreWebView2SharedWorkers` +associated with the WebView2 profile for the host app to interact with workers +based on the app needs. Host app can directly talk to shared worker using +CoreWebView2SharedWorker. ## .NET/WinRT ```c# @@ -677,8 +815,11 @@ app to interact with workers based on the app needs. Host app can directly talk SharedWorkerManager_ = WebViewProfile.SharedWorkerManager; } - // Creates an instance of CoreWebView2SharedWorker which can be used to communicate with the worker - IReadOnlyList workerList = await SharedWorkerManager_.GetSharedWorkersAsync(); + // Creates an instance of CoreWebView2SharedWorker which can be used + // to communicate with the worker + IReadOnlyList workerList = await + SharedWorkerManager_.GetSharedWorkersAsync(); + int workerCount = workerList.Count; StringBuilder messageBuilder = new StringBuilder(); messageBuilder.AppendLine($"No of shared workers created: {workerCount}"); @@ -690,12 +831,11 @@ app to interact with workers based on the app needs. Host app can directly talk messageBuilder.AppendLine($"ScriptUri: {ScriptUri}"); }; - MessageBox.Show(messageBuilder.ToString(), "Shared Workers", MessageBoxButton.OK); + LogMessage(messageBuilder.ToString()); } catch (NotImplementedException exception) { - MessageBox.Show(this, "GetSharedWorkersAsync Failed: " + exception.Message, - "Get Shared Workers Info"); + LogMessage("GetSharedWorkersAsync failed: " + exception.Message); } } ``` @@ -737,8 +877,7 @@ app to interact with workers based on the app needs. Host app can directly talk } } - m_appWindow->AsyncMessageBox( - std::move(message.str()), L"Get all the shared workers"); + LogMessage(L"Shared workers" + std::wstring(message.str())); } return S_OK; }) @@ -749,17 +888,23 @@ app to interact with workers based on the app needs. Host app can directly talk # API Details ``` /// State of the service worker. +/// +/// This corresponds to the `state` property of the `ServiceWorker` object in the DOM. +/// See the [MDN documentation](https://developer.mozilla.org/docs/Web/API/ServiceWorker/state) +/// for more information. [v1_enum] typedef enum COREWEBVIEW2_SERVICE_WORKER_STATE { /// The service worker is new and has not been installed yet. COREWEBVIEW2_SERVICE_WORKER_STATE_NEW, /// The service worker is installing. COREWEBVIEW2_SERVICE_WORKER_STATE_INSTALLING, - /// The service worker is installed. The service worker in this state is considered a waiting worker. + /// The service worker is installed. The service worker in this state is considered + /// a waiting worker. COREWEBVIEW2_SERVICE_WORKER_STATE_INSTALLED, /// The service worker is activating. COREWEBVIEW2_SERVICE_WORKER_STATE_ACTIVATING, - /// The service worker is activated. The service worker in this state is considered an active worker ready to handle functional events. + /// The service worker is activated. The service worker in this state is + /// considered an active worker ready to handle functional events. COREWEBVIEW2_SERVICE_WORKER_STATE_ACTIVATED, /// The service worker is redundant. COREWEBVIEW2_SERVICE_WORKER_STATE_REDUNDANT, @@ -769,12 +914,15 @@ typedef enum COREWEBVIEW2_SERVICE_WORKER_STATE { interface ICoreWebView2_25 : IUnknown { /// Subscribe to this event that gets raised when a new dedicated worker is created. /// - /// A Dedicated Worker is a type of web worker that allow you to run Javascript code in the background without blocking the main thread, making them useful for tasks like heavy computations, data processing, and parallel execution. - /// It is "dedicated" because it is linked to a single parent document and cannot be shared with other scripts. + /// A Dedicated Worker is a type of web worker that allow you to run Javascript + /// code in the background without blocking the main thread, making them useful + /// for tasks like heavy computations, data processing, and parallel execution. + /// It is "dedicated" because it is linked to a single parent document and cannot + /// be shared with other scripts. /// /// This event is raised when a web application creates a dedicated worker using the /// `new Worker("/worker.js")` method. See the - /// [Worker](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker) + /// [Worker](https://developer.mozilla.org/docs/Web/API/Worker/Worker) /// for more information. HRESULT add_DedicatedWorkerCreated( [in] ICoreWebView2DedicatedWorkerCreatedEventHandler* eventHandler, @@ -803,17 +951,21 @@ interface ICoreWebView2DedicatedWorkerCreatedEventArgs : IUnknown { [uuid(ad6921d4-c416-5945-8437-2c97aeb76e6e), object, pointer_default(unique)] interface ICoreWebView2Profile2 : IUnknown { - /// Get the service worker manager to monitor service worker registrations and interact with the service worker associated with the current profile. + /// Get the service worker manager to monitor service worker registrations and + /// interact with the service worker associated with the current profile. /// - /// The changes would apply to the context of the user profile. That is, other WebViews under the same user profile could be affected. + /// The changes would apply to the context of the user profile. That is, + /// other WebViews under the same user profile could be affected. /// /// \snippet ScenarioServiceWorkerManager.cpp ServiceWorkerManager [propget] HRESULT ServiceWorkerManager([out, retval] ICoreWebView2ServiceWorkerManager** value); - /// Get the shared worker manager to monitor shared worker creations and interact with the shared worker associated with the current profile. + /// Get the shared worker manager to monitor shared worker creations and interact + /// with the shared worker associated with the current profile. /// - /// The changes would apply to the context of the user profile. That is, other WebViews under the same user profile could be affected. + /// The changes would apply to the context of the user profile. That is, other + /// WebViews under the same user profile could be affected. /// /// \snippet ScenarioSharedWorkerManager.cpp SharedWorkerManager [propget] HRESULT SharedWorkerManager([out, retval] ICoreWebView2SharedWorkerManager** value); @@ -823,16 +975,20 @@ interface ICoreWebView2Profile2 : IUnknown { interface ICoreWebView2ServiceWorkerManager : IUnknown { /// Adds an event handler for the `ServiceWorkerRegistered` event. /// - /// A ServiceWorker is a specific type of worker that takes a JavaScript file that can control the web-page/site that it is associated with, - /// intercepting and modifying navigation and resource requests, and caching resources in a very granular fashion to give you complete control + /// A ServiceWorker is a specific type of worker that takes a JavaScript file + /// that can control the web-page/site that it is associated with, + /// intercepting and modifying navigation and resource requests, and caching + /// resources in a very granular fashion to give you complete control /// over how app behaves in certain situations. /// - /// Service workers essentially act as proxy servers that sit between web applications, the browser, and the network (when available). - /// Unlike Shared Workers, which have their own separate global scope, Service Workers have no DOM access and run in a different context. + /// Service workers essentially act as proxy servers that sit between web applications, + /// the browser, and the network (when available). + /// Unlike Shared Workers, which have their own separate global scope, Service + ///Workers have no DOM access and run in a different context. /// /// This event is raised when a web application registers a service worker using the /// `navigator.serviceWorker.register("/sw.js")` method. See the - /// [Service Worker Registration](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration) + /// [Service Worker Registration](https://developer.mozilla.org/docs/Web/API/ServiceWorkerRegistration) /// for more information. /// /// @@ -848,24 +1004,35 @@ interface ICoreWebView2ServiceWorkerManager : IUnknown { /// Gets a list of the service worker registrations under the same profile. /// - /// This method returns a list of `CoreWebView2ServiceWorkerRegistration` objects, each representing a service worker registration. + /// This method returns a list of `CoreWebView2ServiceWorkerRegistration` objects, + /// each representing a service worker registration. /// - /// This method corresponds to the `getRegistrations` method of the `ServiceWorkerContainer` object in the DOM - /// which returns a Promise that resolves to an array of `ServiceWorkerRegistration` objects. - /// See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/getRegistrations) - /// for more information. + /// This method corresponds to the `getRegistrations` method of the `ServiceWorkerContainer` + /// object in the DOM which returns a Promise that resolves to an array of + /// `ServiceWorkerRegistration` objects. See the [MDN documentation] + /// (https://developer.mozilla.org/docs/Web/API/ServiceWorkerContainer/getRegistrations) for more information. HRESULT GetServiceWorkerRegistrations( [in] ICoreWebView2GetServiceWorkerRegistrationsCompletedHandler* handler ); - /// Gets the service worker registration object associated with the specified scope. If a service worker has been registered + /// Gets the service worker registration object associated with the specified scope. + /// If a service worker has been registered for the given scope, it gets the + /// corresponding `CoreWebView2ServiceWorkerRegistration` object. /// - /// This corresponds to the `getRegistration` method of the `ServiceWorkerContainer` object in the DOM which - /// returns a Promise that resolves to a `ServiceWorkerRegistration` object. - /// See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/getRegistration) - /// for more information. + /// The `scope` parameter is a fully qualified URL that defines the range of URLs + /// a service worker can control. For example, if you registered a service worker + /// with a `scope` of '/app/' for an application at https://example.com/, you should + /// specify the full qualified URL i.e., https://example.com/app/ when calling this + /// method. If the `scope` was not specified during registration, its default value + /// is the base URL of the application, e.g., https://example.com/. /// - /// If scope is empty string or null, the completed handler immediately returns `E_INVALIDARG` and with a null pointer. + /// This corresponds to the `getRegistration` method of the `ServiceWorkerContainer` + /// object in the DOM which returns a Promise that resolves to a `ServiceWorkerRegistration` + /// object. See the [MDN documentation] + /// (https://developer.mozilla.org/docs/Web/API/ServiceWorkerContainer/getRegistration) for more information. + /// + /// If scope is empty string or null, the completed handler immediately returns + /// `E_INVALIDARG` and with a null pointer. HRESULT GetServiceWorkerRegistration( [in] LPCWSTR scope , [in] ICoreWebView2GetServiceWorkerRegistrationCompletedHandler* handler @@ -900,22 +1067,6 @@ interface ICoreWebView2ServiceWorkerRegisteredEventHandler : IUnknown { /// Event args for the `ServiceWorkerRegistered` event. [uuid(a18bd62a-8246-5d2b-abc5-2bdbbc13767b), object, pointer_default(unique)] interface ICoreWebView2ServiceWorkerRegisteredEventArgs : IUnknown { - /// A string representing a URL that defines a service worker's registration scope. It is relative to the base URL of the application. - /// By default, the scope value for a service worker registration is set to the directory where the service worker script is located. - /// - /// The `scope` parameter will be a fully qualified URL that includes both the origin (scheme, host, and optionally port) and the path. - /// If the origin and scope includes an internationalized domain name (IDN), it should be represented in punycode format. - /// - /// For example, if the service worker script is located at https://example.com/sw.js, the default scope is https://example.com/, and the service worker controls all pages under https://example.com/ - /// If the scope is set to /app/ when registering the service worker, the scope will be https://example.com/app/. - /// - /// This corresponds to the `scope` property of the `ServiceWorkerRegistration` object in the DOM. - /// For more information, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/scope). - /// - /// The caller must free the returned string with `CoTaskMemFree`. See - /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). - [propget] HRESULT Scope([out, retval] LPWSTR* value); - /// The service worker that was registered. HRESULT GetServiceWorkerRegistration( [out, retval] ICoreWebView2ServiceWorkerRegistration** value @@ -951,26 +1102,35 @@ interface ICoreWebView2ServiceWorkerRegistrationDestroyedEventHandler : IUnknown [uuid(0c0b03bd-ced2-5518-851a-3d3f71fb5c4b), object, pointer_default(unique)] interface ICoreWebView2ServiceWorkerRegistration : IUnknown { - /// A string representing a URL that defines a service worker's registration scope. It is relative to the base URL of the application. - /// By default, the scope value for a service worker registration is set to the directory where the service worker script is located. + /// The `scope` parameter is a fully qualified URL that defines the range of URLs + /// a service worker can control. + /// + /// By default, the `scope` is the directory where the service worker script resides. + /// For example, if the script is at https://example.com/sw.js, the default scope is + /// https://example.com/, and the service worker can control all pages under this URL. /// - /// The `scope` parameter will be a fully qualified URL that includes both the origin (scheme, host, and optionally port) and the path. - /// If the origin and scope includes an internationalized domain name (IDN), it should be represented in punycode format. + /// During the registration of the service worker, the `scope` is set relative to the + /// application's base URL. For example, if you register a service worker with a scope + /// of /app/ for an application at https://example.com/, the scope is relative to the + /// base URL during registration. /// - /// For example, if the service worker script is located at https://example.com/sw.js, the default scope is https://example.com/, and the service worker controls all pages under https://example.com/ - /// If the scope is set to /app/ when registering the service worker, the scope will be https://example.com/app/. + /// After the service worker is registered, the `scope` is stored and returned as a + /// fully qualified URL, such as https://example.com/app/. This URL includes the origin + /// (scheme, host, and optionally port) and the path. If the origin or scope includes + /// an internationalized domain name (IDN), it should be represented in punycode format. /// - /// This corresponds to the `scope` property of the `ServiceWorkerRegistration` object in the DOM. - /// For more information, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/scope). + /// This corresponds to the `scope` property of the `ServiceWorkerRegistration` + /// object in the DOM. For more information, see the [MDN documentation] + /// (https://developer.mozilla.org/docs/Web/API/ServiceWorkerRegistration/scope). /// /// The caller must free the returned string with `CoTaskMemFree`. See /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). [propget] HRESULT Scope([out, retval] LPWSTR* value); /// Add an event handler for the `Destroyed` event that is raised when the worker registration is - /// unregistered using the JS api `registration.unregister()` method or when the `CoreWebView2ServiceWorkerRegistration` - /// object is destroyed. See the - /// [Unregister](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/unregister) + /// unregistered using the JS api `registration.unregister()` method or when the + /// `CoreWebView2ServiceWorkerRegistration` object is destroyed. See the + /// [Unregister](https://developer.mozilla.org/docs/Web/API/ServiceWorkerRegistration/unregister) /// for more information. HRESULT add_Destroyed( @@ -982,14 +1142,17 @@ interface ICoreWebView2ServiceWorkerRegistration : IUnknown { [in] EventRegistrationToken token); - /// The active service worker that was created. If there is no active service worker, the completed handler immediately returns `S_OK` and with a null pointer. - /// The active service worker is the service worker that controls the pages within the scope of the registration. See the [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker) - /// for more information. + /// The active service worker that was created. If there is no active service worker, + /// the completed handler immediately returns `S_OK` and with a null pointer. + /// The active service worker is the service worker that controls the pages within + /// the scope of the registration. See the [Service Worker] + /// (https://developer.mozilla.org/docs/Web/API/ServiceWorker) for more information. /// /// This corresponds to the `active` property of the `ServiceWorkerRegistration` object in the DOM. - /// For more information, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/active). - HRESULT GetServiceWorker( - [in] ICoreWebView2GetServiceWorkerCompletedHandler* handler + /// For more information, see the [MDN documentation] + /// (https://developer.mozilla.org/docs/Web/API/ServiceWorkerRegistration/active). + HRESULT GetActiveServiceWorker( + [in] ICoreWebView2GetActiveServiceWorkerCompletedHandler* handler ); } @@ -997,12 +1160,14 @@ interface ICoreWebView2ServiceWorkerRegistration : IUnknown { interface ICoreWebView2SharedWorkerManager : IUnknown { /// Add an event handler for the `SharedWorkerCreated` event. /// - /// A SharedWorker is a specific type of worker that can be accessed from several browsing contexts, such as multiple windows, iframes, or even other workers. - /// Unlike Dedicated Workers, which have their own separate global scope, SharedWorkers share a commoglobal scope called SharedWorkerGlobalScope. + /// A SharedWorker is a specific type of worker that can be accessed from several + /// browsing contexts, such as multiple windows, iframes, or even other workers. + /// Unlike Dedicated Workers, which have their own separate global scope, SharedWorkers + /// share a common global scope called SharedWorkerGlobalScope. /// /// This event is raised when a web application creates a shared worker using the /// `new SharedWorker("worker.js")` method. See the - /// [Shared Worker](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker) + /// [Shared Worker](https://developer.mozilla.org/docs/Web/API/SharedWorker) /// for more information. /// /// \snippet ScenarioSharedWorkerManager.cpp SharedWorkerCreated @@ -1058,16 +1223,18 @@ interface ICoreWebView2Worker : IUnknown { /// A string representing the Uri of the script that the worker is executing. /// /// This corresponds to the `scriptURL` property of the `Worker` object in the DOM. - /// The `scriptURL` property returns a string representing the URL of the script that the worker is executing. - /// See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Worker/scriptURL) - /// for more information. + /// The `scriptURL` property returns a string representing the URL of the script that the + /// worker is executing. See the [MDN documentation] + /// (https://developer.mozilla.org/docs/Web/API/Worker/scriptURL) for more information. /// /// The caller must free the returned string with `CoTaskMemFree`. See /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). [propget] HRESULT ScriptUri([out, retval] LPWSTR* value); - /// Add an event handler for the `Destroyed` event that is raised when the worker object is destroyed. - /// A worker object is destroyed when the worker script is terminated or when the `CoreWebView2Worker` object is destroyed. + /// Add an event handler for the `Destroyed` event that is raised when the + /// worker object is destroyed. + /// A worker object is destroyed when the worker script is terminated or when + /// the `CoreWebView2Worker` object is destroyed. HRESULT add_Destroyed( [in] ICoreWebView2WorkerDestroyedEventHandler* eventHandler, [out] EventRegistrationToken* token); @@ -1088,10 +1255,12 @@ interface ICoreWebView2WorkerDestroyedEventHandler : IUnknown { [uuid(f233edb4-d9b4-5209-9abd-b7f50089464c), object, pointer_default(unique)] interface ICoreWebView2DedicatedWorker : IUnknown { - /// A string specified when creating a dedicated worker. + /// A string specified when creating a dedicated worker. If it is not provided during + /// creation, the `Name` property will default to an empty string. /// /// This corresponds to the `options.name` property passed to the `Worker` constructor in the DOM. - /// For more information, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker). + /// For more information, see the [MDN documentation] + /// (https://developer.mozilla.org/docs/Web/API/Worker/Worker). /// /// The caller must free the returned string with `CoTaskMemFree`. See /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). @@ -1101,10 +1270,11 @@ interface ICoreWebView2DedicatedWorker : IUnknown { [uuid(de8ed42b-5128-55df-9dd0-ea1d4d706c87), object, pointer_default(unique)] interface ICoreWebView2ServiceWorker : IUnknown { - /// The state of the service worker. A service worker can be in new, installing, installed, activating, activated, or redundant. + /// The state of the service worker. A service worker can be in new, installing, + /// installed, activating, activated, or redundant. /// /// This corresponds to the `state` property of the `ServiceWorker` object in the DOM. - /// See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/state) + /// See the [MDN documentation](https://developer.mozilla.org/docs/Web/API/ServiceWorker/state) /// for more information. [propget] HRESULT State([out, retval] COREWEBVIEW2_SERVICE_WORKER_STATE* value); } @@ -1114,7 +1284,8 @@ interface ICoreWebView2SharedWorker : IUnknown { /// A string specified when creating a shared worker. /// /// This corresponds to the `options.name` property passed to the `Worker` constructor in the DOM. - /// For more information, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker). + /// For more information, see the [MDN documentation] + /// (https://developer.mozilla.org/docs/Web/API/Worker/Worker). /// /// The caller must free the returned string with `CoTaskMemFree`. See /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). @@ -1192,7 +1363,7 @@ namespace Microsoft.Web.WebView2.Core event Windows.Foundation.TypedEventHandler Destroyed; - Windows.Foundation.IAsyncOperation GetServiceWorkerAsync(); + Windows.Foundation.IAsyncOperation GetActiveServiceWorkerAsync(); } runtimeclass CoreWebView2ServiceWorker From 9dcc11011d650517a9449af5aa8f8fccd8794943 Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Fri, 21 Jun 2024 09:18:39 -0700 Subject: [PATCH 6/7] remove state and add activated event --- specs/Workers.md | 562 +++++++++++++++++++++++------------------------ 1 file changed, 276 insertions(+), 286 deletions(-) diff --git a/specs/Workers.md b/specs/Workers.md index fec470dc4..87225578e 100644 --- a/specs/Workers.md +++ b/specs/Workers.md @@ -55,7 +55,7 @@ and support background operations for service workers. **DedicatedWorkerCreated**: This event, associated with CoreWebView2, is raised when a web page initiates a dedicated worker. It grants access to the CoreWebView2DedicatedWorker object, which contains information such as the -script URL and name. Additionally, it provides a 'destroy' event that is raised +script uri and name. Additionally, it provides a 'destroy' event that is raised just before this object is due for destruction. **ServiceWorkerRegistered**: This event, originating from the @@ -63,7 +63,7 @@ CoreWebView2ServiceWorkerManager associated with CoreWebView2Profile is raised when a service worker is successfully registered within the context of a WebView2 application for the profile. This event provides access to a CoreWebView2ServiceWorkerRegistration object, which encapsulates information -about the registered service worker, such as its script URL and scope. +about the registered service worker, such as its script uri and scope uri. Additionally, it enables subscription to the service worker's lifecycle events, including updates and unregistration. @@ -72,22 +72,22 @@ part of the CoreWebView2ServiceWorkerManager class, is used to retrieve all service worker registrations within the context of a WebView2 application for the profile. This method gives a collection of CoreWebView2ServiceWorkerRegistration objects, each encapsulating information -about a registered service worker, such as its script URL and scope. +about a registered service worker, such as its script uri and scope uri. **GetServiceWorkerRegistration**: The GetServiceWorkerRegistration method, part of the CoreWebView2ServiceWorkerManager class, is used to retrieve a specific service worker registration within the context of a WebView2 application for the -profile. This asynchronous method takes a scope as an argument and returns a +profile. This asynchronous method takes a scope uri as an argument and returns a CoreWebView2ServiceWorkerRegistration object that encapsulates information about -the registered service worker with the given scope, such as its script URL. This +the registered service worker with the given scope uri, such as its script uri. This method is useful for accessing details of a specific service worker based on its -scope. +scope uri. **SharedWorkerCreated**: This event, originating from the CoreWebView2SharedWorkerManager associated with CoreWebView2Profile, is raised when a shared worker is successfully created within the context of a WebView2 application for the profile. It grants access to the CoreWebView2SharedWorker -object, which contains information such as the script URL and name. +object, which contains information such as the script uri and name. Additionally, it provides a 'destroy' event that is raised just before this object is due for destruction. @@ -120,7 +120,7 @@ the main thread and a dedicated worker. // operation. worker.WorkerMessageReceived += (sender, args) => { - var message = args.TryGetWebMessageAsString; + var message = args.TryGetWorkerMessageAsString; // This section of the code is dedicated to handling updates received // from the worker. Depending on the nature of these updates, you // might choose to perform various actions. For instance, you could @@ -156,7 +156,7 @@ the main thread and a dedicated worker. ``` ## Win32 C++ ```cpp - void PostMessageToWorker(wil::com_ptr worker) + void PostMessageToWorker(wil::com_ptr worker) { // Inside the worker, an event listener is set up for the 'message' event. // When a message is received from the host application, the worker performs @@ -164,12 +164,12 @@ the main thread and a dedicated worker. // to receive messages from the worker. These messages could contain // fetched data or any error information from the worker's fetch operation. CHECK_FAILURE(worker->add_WorkerMessageReceived( - Callback( - [this](ICoreWebView2Worker* sender, - ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT + Callback( + [this](ICoreWebView2DedicatedWorker* sender, + ICoreWebView2DedicatedWorkerMessageReceivedEventArgs* args) -> HRESULT { wil::unique_cotaskmem_string message; - CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); + CHECK_FAILURE(args->TryGetWorkerMessageAsString(&message)); // This section of the code is dedicated to handling // updates received from the worker. Depending on the @@ -202,20 +202,14 @@ the main thread and a dedicated worker. ICoreWebView2DedicatedWorkerCreatedEventArgs* args) { wil::com_ptr dedicatedWorker; - CHECK_FAILURE(args->get_Worker(&dedicatedWorker)); if (dedicatedWorker) - { - wil::com_ptr worker = - dedicatedWorker.try_query(); - - if(worker) - { + { // Subscribe to worker destroyed event - CHECK_FAILURE(worker->add_Destroyed( - Callback( - [this](ICoreWebView2Worker* sender, IUnknown* args) -> HRESULT + CHECK_FAILURE(dedicatedWorker->add_Destroyed( + Callback( + [this](ICoreWebView2DedicatedWorker* sender, IUnknown* args) -> HRESULT { /*Cleanup on worker destruction*/ return S_OK; @@ -230,8 +224,7 @@ the main thread and a dedicated worker. // Send a message to the dedicated worker to offload fetch // request from the host app. - PostMessageToWorker(worker); - } + PostMessageToWorker(dedicatedWorker); } return S_OK; @@ -260,7 +253,7 @@ WorkerMessageReceived APIs. // from the service worker. worker.WorkerMessageReceived += (sender, args) => { - var message = args.TryGetWebMessageAsString; + var message = args.TryGetWorkerMessageAsString; // Process the messages received from the worker. Depending on the // content of these messages, you might choose to log the data for @@ -292,24 +285,19 @@ WorkerMessageReceived APIs. /*Cleanup on worker destruction*/ }; - LogMessage("Service worker has been registered with a scope: " + serviceWorkerRegistration.Scope); - - CoreWebView2ServiceWorker serviceWorker = await - serviceWorkerRegistration.GetActiveServiceWorkerAsync(); + LogMessage("Service worker has been registered with a scope: " + serviceWorkerRegistration.ScopeUri); - if (serviceWorker != null) + serviceWorkerRegistration.ServiceWorkerActivated += async (sender, args) => { + CoreWebView2ServiceWorker serviceWorker = args.ActiveServiceWorker; serviceWorker.WorkerDestroyed += (sender, args) => { - /*Cleanup on worker destruction*/ + /*Cleanup on worker destruction*/ }; - // Send a list of resources to the service worker to cache. + // Send a list of resources to the service worker to cache. PostMessageToWorker(serviceWorker); - } - else - { - LogMessage("No active service worker available."); + } } }; @@ -318,19 +306,19 @@ WorkerMessageReceived APIs. ## Win32 C++ ```cpp - void PostMessageToWorker(wil::com_ptr worker) + void PostMessageToWorker(wil::com_ptr worker) { // The service worker communicates updates back to the host application, // such as when resource caching is complete. The host application can // listen for the WorkerMessageReceived event to receive these updates // from the service worker. CHECK_FAILURE(worker->add_WorkerMessageReceived( - Callback( - [this](ICoreWebView2Worker* sender, - ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT + Callback( + [this](ICoreWebView2ServiceWorker* sender, + ICoreWebView2ServiceWorkerMessageReceivedEventArgs* args) -> HRESULT { wil::unique_cotaskmem_string message; - CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); + CHECK_FAILURE(args->TryGetWorkerMessageAsString(&message)); // Process the messages received from the worker. // Depending on the content of these messages, @@ -389,50 +377,43 @@ WorkerMessageReceived APIs. .Get(), nullptr)); - wil::unique_cotaskmem_string scope; - CHECK_FAILURE(serviceWorkerRegistration->get_Scope(&scope)); + wil::unique_cotaskmem_string scopeUri; + CHECK_FAILURE(serviceWorkerRegistration->get_ScopeUri(&scopeUri)); - CHECK_FAILURE(serviceWorkerRegistration->GetActiveServiceWorker( - Callback( - [this, &scope]( - HRESULT error, - ICoreWebView2ServiceWorker* serviceWorker) -> HRESULT - { - wil::com_ptr worker; - std::wstringstream message; - if (serviceWorker) - { - if (SUCCEEDED( - serviceWorker->QueryInterface(IID_PPV_ARGS(&worker)))) - { - // Subscribe to worker destroyed event - CHECK_FAILURE(worker->add_Destroyed( - Callback< - ICoreWebView2WorkerDestroyedEventHandler>( - [this]( - ICoreWebView2Worker* sender, - IUnknown* args) -> HRESULT - { - /*Cleanup on worker destruction*/ - return S_OK; - }) - .Get(), - nullptr)); - - // Send a list of resources to the service worker to cache. - PostMessageToWorker(worker); - } - } - else - { - LogMessage(L"No active service worker available"); - } - - return S_OK; - }) - .Get())); + CHECK_FAILURE(serviceWorkerRegistration->add_ServiceWorkerActivated( + Callback( + [this]( + ICoreWebView2ServiceWorkerRegistration* sender, + ICoreWebView2ServiceWorkerActivatedEventArgs* args) -> HRESULT + { + wil::com_ptr serviceWorker; + CHECK_FAILURE(args->get_ActiveServiceWorker(&serviceWorker)); + + std::wstringstream message; + + // Subscribe to worker destroyed event + CHECK_FAILURE(serviceWorker->add_Destroyed( + Callback< + ICoreWebView2ServiceWorkerDestroyedEventHandler>( + [this]( + ICoreWebView2ServiceWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + return S_OK; + }) + .Get(), + nullptr)); + + // Send a list of resources to the service worker to cache. + PostMessageToWorker(serviceWorker); - LogMessage(L"Service worker has been registered with a scope: " + std::wstring(scope.get())); + return S_OK; + }) + .Get(), + nullptr)); + + LogMessage(L"Service worker has been registered with a scope: " + std::wstring(scopeUri.get())); } return S_OK; @@ -468,9 +449,9 @@ messaging. for (int i = 0; i < registrationList.Count(); ++i) { - var scope = registrationList[i].Scope; + var scopeUri = registrationList[i].ScopeUri; - messageBuilder.AppendLine($"Scope: {scope}"); + messageBuilder.AppendLine($"Scope: {scopeUri}"); }; LogMessage(messageBuilder.ToString()); @@ -510,10 +491,10 @@ messaging. CHECK_FAILURE(workerRegistrationCollection->GetValueAtIndex( i, &serviceWorkerRegistration)); - wil::unique_cotaskmem_string scope; - CHECK_FAILURE(serviceWorkerRegistration->get_Scope(&scope)); + wil::unique_cotaskmem_string scopeUri; + CHECK_FAILURE(serviceWorkerRegistration->get_ScopeUri(&scopeUri)); - message << L"Scope: " << scope.get(); + message << L"Scope: " << scopeUri.get(); } LogMessage(std::wstring(message.str())); @@ -538,7 +519,7 @@ service worker, facilitating the exchange of messages. { var dialog = new TextInputDialog( title: "Scope of the Service Worker Registration", - description: "Specify a scope to get the service worker", + description: "Specify a scope uri to get the service worker", defaultInput: ""); if (dialog.ShowDialog() == true) { @@ -553,7 +534,7 @@ service worker, facilitating the exchange of messages. if(registration != null) { - CoreWebView2ServiceWorker worker = await registration.GetActiveServiceWorkerAsync(); + CoreWebView2ServiceWorker worker = registration.ActiveServiceWorker; if(worker != null) { LogMessage("Service worker for scope " + dialog.Input.Text + " fetched successfully"); @@ -582,23 +563,23 @@ service worker, facilitating the exchange of messages. { CreateServiceWorkerManager(); } - std::wstring scope; + std::wstring scopeUri; TextInputDialog dialog( m_appWindow->GetMainWindow(), L"Service Worker", L"Scope:", - L"Specify a scope to get the service worker", L""); + L"Specify a scope uri to get the service worker", L""); if (dialog.confirmed) { - // The 'scope' is a fully qualified URL that defines the range of URLs + // The 'ScopeUri' is a fully qualified URI that defines the range of URLs // a service worker can control. For example, if you registered a service // worker with a 'scope' of '/app/' for an application at https://example.com/, - // you should specify the full qualified URL i.e., https://example.com/app/ + // you should specify the full qualified URI i.e., https://example.com/app/ // when calling this method. CHECK_FAILURE(m_serviceWorkerManager->GetServiceWorkerRegistration( dialog.input.c_str(), Callback( - [this, &scope]( + [this, &scopeUri]( HRESULT error, ICoreWebView2ServiceWorkerRegistration* serviceWorkerRegistration) -> HRESULT @@ -606,38 +587,24 @@ service worker, facilitating the exchange of messages. CHECK_FAILURE(error); if(serviceWorkerRegistration) { - CHECK_FAILURE(serviceWorkerRegistration->GetActiveServiceWorker( - Callback( - [this, &scope]( - HRESULT error, - ICoreWebView2ServiceWorker* serviceWorker) -> HRESULT - { - if (serviceWorker != nullptr) - { - wil::com_ptr worker; - wil::unique_cotaskmem_string ScriptUri; - if (SUCCEEDED(serviceWorker->QueryInterface( - IID_PPV_ARGS(&worker)))) - { - CHECK_FAILURE(worker->get_ScriptUri(&ScriptUri)); - } - - LogMessage(L"Service worker for scope " + scope + - L" fetched successfully from the script " - + std::wstring(ScriptUri.get())); - } - else - { - LogMessage(L"No service worker available"); - } - - return S_OK; - }) - .Get())); - } + wil::com_ptr serviceWorker; + CHECK_FAILURE(serviceWorkerRegistration->get_ActiveServiceWorker(&serviceWorker)); + if (serviceWorker != nullptr) + { + wil::unique_cotaskmem_string ScriptUri; + CHECK_FAILURE(serviceWorker->get_ScriptUri(&ScriptUri)); + + LogMessage(L"Service worker for scope " + scopeUri + + L" fetched successfully from the script " + + std::wstring(ScriptUri.get())); + } + else + { + LogMessage(L"No service worker available"); + } else { - LogMessage(L"No service worker registered for the scope: " + scope); + LogMessage(L"No service worker registered for the scope: " + scopeUri); } return S_OK; @@ -663,7 +630,7 @@ upcoming PostMessage and WorkerMessageReceived APIs. // these updates from the shared worker. worker.WorkerMessageReceived += (sender, args) => { - var message = args.TryGetWebMessageAsString; + var message = args.TryGetWorkerMessageAsString; // Record the updates from the WebSocket or modify the user interface // according to the requirements of the host application. @@ -696,7 +663,7 @@ upcoming PostMessage and WorkerMessageReceived APIs. // connection, enabling real-time updates through the PostMessage API. // The shared worker establishes the WebSocket connection, receives // real-time updates, and forwards these updates back to the host application. - PostMessageToWorker(worker); + PostMessageToWorker(sharedWorker); } }; } @@ -704,18 +671,18 @@ upcoming PostMessage and WorkerMessageReceived APIs. ``` ## Win32 C++ ```cpp - void PostMessageToWorker(wil::com_ptr worker) + void PostMessageToWorker(wil::com_ptr worker) { // The shared worker communicates back to the host application with // updates from the WebSocket. The host application can monitor this // event to receive these updates from the shared worker. CHECK_FAILURE(worker->add_WorkerMessageReceived( - Callback( - [this](ICoreWebView2Worker* sender, - ICoreWebView2WorkerMessageReceivedEventArgs* args) -> HRESULT + Callback( + [this](ICoreWebView2SharedWorker* sender, + ICoreWebView2SharedWorkerMessageReceivedEventArgs* args) -> HRESULT { wil::unique_cotaskmem_string message; - CHECK_FAILURE(args->TryGetWebMessageAsString(&message)); + CHECK_FAILURE(args->TryGetWorkerMessageAsString(&message)); // Record the updates from the WebSocket or // modify the user interface according to the @@ -755,39 +722,33 @@ upcoming PostMessage and WorkerMessageReceived APIs. if (sharedWorker) { - wil::com_ptr worker = - sharedWorker.try_query(); - - if (worker) - { - wil::unique_cotaskmem_string ScriptUri; - CHECK_FAILURE(worker->get_ScriptUri(&ScriptUri)); - - // Subscribe to worker destroyed event - worker->add_Destroyed( - Callback( - [this, &ScriptUri]( - ICoreWebView2StagingWorker* sender, - IUnknown* args) -> HRESULT - { - /*Cleanup on worker destruction*/ - return S_OK; - }) - .Get(), - nullptr); + wil::unique_cotaskmem_string ScriptUri; + CHECK_FAILURE(sharedWorker->get_ScriptUri(&ScriptUri)); + + // Subscribe to worker destroyed event + sharedWorker->add_Destroyed( + Callback( + [this, &ScriptUri]( + ICoreWebView2SharedWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + return S_OK; + }) + .Get(), + nullptr); - LogMessage(L"Shared Worker has been created with the script located at the " + std::wstring(ScriptUri.get())); + LogMessage(L"Shared Worker has been created with the script located at the " + std::wstring(ScriptUri.get())); - // The host application leverages a shared worker to sustain - // a WebSocket connection, facilitating real-time updates. - // The initiation of the WebSocket connection is raised by a - // message from the host app to the shared worker via the - // PostMessage API. The shared worker then establishes the - // WebSocket connection, receives real-time updates, and - // relays these updates back to the host application. - PostMessageToWorker(worker); - } + // The host application leverages a shared worker to sustain + // a WebSocket connection, facilitating real-time updates. + // The initiation of the WebSocket connection is raised by a + // message from the host app to the shared worker via the + // PostMessage API. The shared worker then establishes the + // WebSocket connection, receives real-time updates, and + // relays these updates back to the host application. + PostMessageToWorker(sharedWorker); } return S_OK; @@ -826,7 +787,7 @@ CoreWebView2SharedWorker. for (int i = 0; i < workerCount; ++i) { - var stringUrl = workerList[i].ScriptUri; + var stringUri = workerList[i].ScriptUri; messageBuilder.AppendLine($"ScriptUri: {ScriptUri}"); }; @@ -866,11 +827,10 @@ CoreWebView2SharedWorker. Microsoft::WRL::ComPtr sharedWorker; CHECK_FAILURE(workersCollection->GetValueAtIndex(i, &sharedWorker)); - wil::com_ptr worker; - if (SUCCEEDED(sharedWorker->QueryInterface(IID_PPV_ARGS(&worker)))) + if (sharedWorker) { wil::unique_cotaskmem_string ScriptUri; - CHECK_FAILURE(worker->get_ScriptUri(&ScriptUri)); + CHECK_FAILURE(sharedWorker->get_ScriptUri(&ScriptUri)); message << L"ScriptUri: " << ScriptUri.get(); message << std::endl; @@ -887,29 +847,6 @@ CoreWebView2SharedWorker. # API Details ``` -/// State of the service worker. -/// -/// This corresponds to the `state` property of the `ServiceWorker` object in the DOM. -/// See the [MDN documentation](https://developer.mozilla.org/docs/Web/API/ServiceWorker/state) -/// for more information. -[v1_enum] -typedef enum COREWEBVIEW2_SERVICE_WORKER_STATE { - /// The service worker is new and has not been installed yet. - COREWEBVIEW2_SERVICE_WORKER_STATE_NEW, - /// The service worker is installing. - COREWEBVIEW2_SERVICE_WORKER_STATE_INSTALLING, - /// The service worker is installed. The service worker in this state is considered - /// a waiting worker. - COREWEBVIEW2_SERVICE_WORKER_STATE_INSTALLED, - /// The service worker is activating. - COREWEBVIEW2_SERVICE_WORKER_STATE_ACTIVATING, - /// The service worker is activated. The service worker in this state is - /// considered an active worker ready to handle functional events. - COREWEBVIEW2_SERVICE_WORKER_STATE_ACTIVATED, - /// The service worker is redundant. - COREWEBVIEW2_SERVICE_WORKER_STATE_REDUNDANT, -} COREWEBVIEW2_SERVICE_WORKER_STATE; - [uuid(29b994e5-0ac8-5430-89fa-5b4bb2091d8d), object, pointer_default(unique)] interface ICoreWebView2_25 : IUnknown { /// Subscribe to this event that gets raised when a new dedicated worker is created. @@ -949,6 +886,43 @@ interface ICoreWebView2DedicatedWorkerCreatedEventArgs : IUnknown { [propget] HRESULT Worker([out, retval] ICoreWebView2DedicatedWorker** value); } +/// Receives `Destroyed` events. +[uuid(d3066b89-9039-5ffc-b594-f936773d5bc5), object, pointer_default(unique)] +interface ICoreWebView2DedicatedWorkerDestroyedEventHandler : IUnknown { + /// Provides the event args for the corresponding event. + HRESULT Invoke( + [in] ICoreWebView2DedicatedWorker* sender, + [in] IUnknown* args); +} + +[uuid(f233edb4-d9b4-5209-9abd-b7f50089464c), object, pointer_default(unique)] +interface ICoreWebView2DedicatedWorker : IUnknown { + /// A string representing the Uri of the script that the worker is executing. + /// + /// This corresponds to the `scriptURL` property of the `Worker` object in the DOM. + /// The `scriptURL` property returns a string representing the URL of the script that the + /// worker is executing. See the [MDN documentation] + /// (https://developer.mozilla.org/docs/Web/API/Worker/scriptURL) for more information. + /// + /// The caller must free the returned string with `CoTaskMemFree`. See + /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). + [propget] HRESULT ScriptUri([out, retval] LPWSTR* value); + + /// Add an event handler for the `Destroyed` event that is raised when the + /// worker object is destroyed. + /// + /// A worker object is destroyed when the worker script is terminated or when + /// the `CoreWebView2DedicatedWorker` object is destroyed. + HRESULT add_Destroyed( + [in] ICoreWebView2DedicatedWorkerDestroyedEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with `add_Destroyed`. + HRESULT remove_Destroyed( + [in] EventRegistrationToken token); +} + + [uuid(ad6921d4-c416-5945-8437-2c97aeb76e6e), object, pointer_default(unique)] interface ICoreWebView2Profile2 : IUnknown { /// Get the service worker manager to monitor service worker registrations and @@ -1019,22 +993,22 @@ interface ICoreWebView2ServiceWorkerManager : IUnknown { /// If a service worker has been registered for the given scope, it gets the /// corresponding `CoreWebView2ServiceWorkerRegistration` object. /// - /// The `scope` parameter is a fully qualified URL that defines the range of URLs + /// The `scopeUri` parameter is a fully qualified URI that defines the range of URIs /// a service worker can control. For example, if you registered a service worker /// with a `scope` of '/app/' for an application at https://example.com/, you should - /// specify the full qualified URL i.e., https://example.com/app/ when calling this - /// method. If the `scope` was not specified during registration, its default value - /// is the base URL of the application, e.g., https://example.com/. + /// specify the full qualified URI i.e., https://example.com/app/ when calling this + /// method. If the scope was not specified during registration, its default value + /// is the base URI of the application, e.g., https://example.com/. /// /// This corresponds to the `getRegistration` method of the `ServiceWorkerContainer` /// object in the DOM which returns a Promise that resolves to a `ServiceWorkerRegistration` /// object. See the [MDN documentation] /// (https://developer.mozilla.org/docs/Web/API/ServiceWorkerContainer/getRegistration) for more information. /// - /// If scope is empty string or null, the completed handler immediately returns + /// If scopeUri is empty string or null, the completed handler immediately returns /// `E_INVALIDARG` and with a null pointer. HRESULT GetServiceWorkerRegistration( - [in] LPCWSTR scope + [in] LPCWSTR scopeUri , [in] ICoreWebView2GetServiceWorkerRegistrationCompletedHandler* handler ); } @@ -1083,14 +1057,6 @@ interface ICoreWebView2ServiceWorkerRegistrationCollectionView : IUnknown { HRESULT GetValueAtIndex([in] UINT32 index, [out, retval] ICoreWebView2ServiceWorkerRegistration** value); } -/// Receives the result of the `GetServiceWorker` method. -[uuid(bd120b47-b859-5f44-9913-0318130ffb69), object, pointer_default(unique)] -interface ICoreWebView2GetServiceWorkerCompletedHandler : IUnknown { - - /// Provides the result of the corresponding asynchronous method. - HRESULT Invoke([in] HRESULT errorCode, [in] ICoreWebView2ServiceWorker* result); -} - /// Receives `Destroyed` events. [uuid(9d79117e-4e96-5a53-9933-d7a31d0106ae), object, pointer_default(unique)] interface ICoreWebView2ServiceWorkerRegistrationDestroyedEventHandler : IUnknown { @@ -1102,20 +1068,20 @@ interface ICoreWebView2ServiceWorkerRegistrationDestroyedEventHandler : IUnknown [uuid(0c0b03bd-ced2-5518-851a-3d3f71fb5c4b), object, pointer_default(unique)] interface ICoreWebView2ServiceWorkerRegistration : IUnknown { - /// The `scope` parameter is a fully qualified URL that defines the range of URLs + /// The `scopeUri` parameter is a fully qualified URL that defines the range of URLs /// a service worker can control. /// - /// By default, the `scope` is the directory where the service worker script resides. - /// For example, if the script is at https://example.com/sw.js, the default scope is - /// https://example.com/, and the service worker can control all pages under this URL. + /// By default, the `scopeUri` is the directory where the service worker script resides. + /// For example, if the script is at https://example.com/app/sw.js, the default scopeUri is + /// https://example.com/app/, and the service worker can control all pages under this URI. /// - /// During the registration of the service worker, the `scope` is set relative to the - /// application's base URL. For example, if you register a service worker with a scope + /// During the registration of the service worker, the scope is set relative to the + /// application's base URI. For example, if you register a service worker with a scope /// of /app/ for an application at https://example.com/, the scope is relative to the - /// base URL during registration. + /// base URI during registration. /// /// After the service worker is registered, the `scope` is stored and returned as a - /// fully qualified URL, such as https://example.com/app/. This URL includes the origin + /// fully qualified URI, such as https://example.com/app/. This URI includes the origin /// (scheme, host, and optionally port) and the path. If the origin or scope includes /// an internationalized domain name (IDN), it should be represented in punycode format. /// @@ -1125,7 +1091,26 @@ interface ICoreWebView2ServiceWorkerRegistration : IUnknown { /// /// The caller must free the returned string with `CoTaskMemFree`. See /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). - [propget] HRESULT Scope([out, retval] LPWSTR* value); + [propget] HRESULT ScopeUri([out, retval] LPWSTR* value); + + /// Adds an event handler for the `ServiceWorkerActivated` event. + /// This event is raised when a service worker is activated. A service worker is + /// activated when its script has been successfully registered and it is ready to + /// control the pages within the scope of the registration. + /// This event is also raised when an updated version of a service worker reaches the active state. + /// In such a case, the existing CoreWebView2ServiceWorker object is destroyed, and this event is + /// raised with a new CoreWebView2ServiceWorker object representing the updated service worker. + /// The active service worker is the one that receives fetch and message events for the pages it controls. + /// See the [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/active) + /// documentation for more information. + /// + HRESULT add_ServiceWorkerActivated( + [in] ICoreWebView2ServiceWorkerActivatedEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with `add_ServiceWorkerActivated`. + HRESULT remove_ServiceWorkerActivated( + [in] EventRegistrationToken token); /// Add an event handler for the `Destroyed` event that is raised when the worker registration is /// unregistered using the JS api `registration.unregister()` method or when the @@ -1143,7 +1128,7 @@ interface ICoreWebView2ServiceWorkerRegistration : IUnknown { /// The active service worker that was created. If there is no active service worker, - /// the completed handler immediately returns `S_OK` and with a null pointer. + /// it returns a null pointer. /// The active service worker is the service worker that controls the pages within /// the scope of the registration. See the [Service Worker] /// (https://developer.mozilla.org/docs/Web/API/ServiceWorker) for more information. @@ -1151,9 +1136,59 @@ interface ICoreWebView2ServiceWorkerRegistration : IUnknown { /// This corresponds to the `active` property of the `ServiceWorkerRegistration` object in the DOM. /// For more information, see the [MDN documentation] /// (https://developer.mozilla.org/docs/Web/API/ServiceWorkerRegistration/active). - HRESULT GetActiveServiceWorker( - [in] ICoreWebView2GetActiveServiceWorkerCompletedHandler* handler - ); + [propget] HRESULT ActiveServiceWorker([out, retval] ICoreWebView2ServiceWorker** value); +} + +/// Receives `ServiceWorkerActivated` events. +[uuid(0f383156-1a08-52d4-81b0-a626484aac40), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorkerActivatedEventHandler : IUnknown { + /// Provides the event args for the corresponding event. + HRESULT Invoke( + [in] ICoreWebView2ServiceWorkerRegistration* sender, + [in] ICoreWebView2ServiceWorkerActivatedEventArgs* args); +} + +/// Event args for the `ServiceWorkerActivated` event. +[uuid(5685c4b6-a514-58b2-9721-b61ef4ccd9d8), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorkerActivatedEventArgs : IUnknown { + /// The service worker that was activated. + [propget] HRESULT ActiveServiceWorker([out, retval] ICoreWebView2ServiceWorker** value); +} + +/// Receives `Destroyed` events. +[uuid(f514c5e7-27f3-5dd8-aa1c-04e053177edd), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorkerDestroyedEventHandler : IUnknown { + /// Provides the event args for the corresponding event. + HRESULT Invoke( + [in] ICoreWebView2ServiceWorker* sender, + [in] IUnknown* args); +} + +[uuid(de8ed42b-5128-55df-9dd0-ea1d4d706c87), object, pointer_default(unique)] +interface ICoreWebView2ServiceWorker : IUnknown { + /// A string representing the Uri of the script that the worker is executing. + /// + /// This corresponds to the `scriptURL` property of the `Worker` object in the DOM. + /// The `scriptURL` property returns a string representing the URL of the script that the + /// worker is executing. See the [MDN documentation] + /// (https://developer.mozilla.org/docs/Web/API/Worker/scriptURL) for more information. + /// + /// The caller must free the returned string with `CoTaskMemFree`. See + /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). + [propget] HRESULT ScriptUri([out, retval] LPWSTR* value); + + /// Add an event handler for the `Destroyed` event that is raised when the + /// worker object is destroyed. + /// + /// A worker object is destroyed when the worker script is terminated or when + /// the `CoreWebView2ServiceWorker` object is destroyed. + HRESULT add_Destroyed( + [in] ICoreWebView2ServiceWorkerDestroyedEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with `add_Destroyed`. + HRESULT remove_Destroyed( + [in] EventRegistrationToken token); } [uuid(9b897103-d035-551f-892e-3e8f2916d03e), object, pointer_default(unique)] @@ -1218,8 +1253,17 @@ interface ICoreWebView2SharedWorkerCollectionView : IUnknown { HRESULT GetValueAtIndex([in] UINT32 index, [out, retval] ICoreWebView2SharedWorker** value); } -[uuid(06cfc21b-56e5-59b1-b7b4-13f197d4539d), object, pointer_default(unique)] -interface ICoreWebView2Worker : IUnknown { +/// Receives `Destroyed` events. +[uuid(fa58150a-5b67-5069-a82e-5606f9f61a67), object, pointer_default(unique)] +interface ICoreWebView2SharedWorkerDestroyedEventHandler : IUnknown { + /// Provides the event args for the corresponding event. + HRESULT Invoke( + [in] ICoreWebView2SharedWorker* sender, + [in] IUnknown* args); +} + +[uuid(876f8390-f9a8-5264-9677-985d8453aeab), object, pointer_default(unique)] +interface ICoreWebView2SharedWorker : IUnknown { /// A string representing the Uri of the script that the worker is executing. /// /// This corresponds to the `scriptURL` property of the `Worker` object in the DOM. @@ -1233,64 +1277,17 @@ interface ICoreWebView2Worker : IUnknown { /// Add an event handler for the `Destroyed` event that is raised when the /// worker object is destroyed. + /// /// A worker object is destroyed when the worker script is terminated or when - /// the `CoreWebView2Worker` object is destroyed. + /// the `CoreWebView2SharedWorker` object is destroyed. HRESULT add_Destroyed( - [in] ICoreWebView2WorkerDestroyedEventHandler* eventHandler, + [in] ICoreWebView2SharedWorkerDestroyedEventHandler* eventHandler, [out] EventRegistrationToken* token); /// Removes an event handler previously added with `add_Destroyed`. HRESULT remove_Destroyed( [in] EventRegistrationToken token); } - -/// Receives `Destroyed` events. -[uuid(3197df3b-4245-5fff-9427-e98118fcf657), object, pointer_default(unique)] -interface ICoreWebView2WorkerDestroyedEventHandler : IUnknown { - /// Provides the event args for the corresponding event. - HRESULT Invoke( - [in] ICoreWebView2Worker* sender, - [in] IUnknown* args); -} - -[uuid(f233edb4-d9b4-5209-9abd-b7f50089464c), object, pointer_default(unique)] -interface ICoreWebView2DedicatedWorker : IUnknown { - /// A string specified when creating a dedicated worker. If it is not provided during - /// creation, the `Name` property will default to an empty string. - /// - /// This corresponds to the `options.name` property passed to the `Worker` constructor in the DOM. - /// For more information, see the [MDN documentation] - /// (https://developer.mozilla.org/docs/Web/API/Worker/Worker). - /// - /// The caller must free the returned string with `CoTaskMemFree`. See - /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). - [propget] HRESULT Name([out, retval] LPWSTR* value); -} - - -[uuid(de8ed42b-5128-55df-9dd0-ea1d4d706c87), object, pointer_default(unique)] -interface ICoreWebView2ServiceWorker : IUnknown { - /// The state of the service worker. A service worker can be in new, installing, - /// installed, activating, activated, or redundant. - /// - /// This corresponds to the `state` property of the `ServiceWorker` object in the DOM. - /// See the [MDN documentation](https://developer.mozilla.org/docs/Web/API/ServiceWorker/state) - /// for more information. - [propget] HRESULT State([out, retval] COREWEBVIEW2_SERVICE_WORKER_STATE* value); -} - -[uuid(876f8390-f9a8-5264-9677-985d8453aeab), object, pointer_default(unique)] -interface ICoreWebView2SharedWorker : IUnknown { - /// A string specified when creating a shared worker. - /// - /// This corresponds to the `options.name` property passed to the `Worker` constructor in the DOM. - /// For more information, see the [MDN documentation] - /// (https://developer.mozilla.org/docs/Web/API/Worker/Worker). - /// - /// The caller must free the returned string with `CoTaskMemFree`. See - /// [API Conventions](/microsoft-edge/webview2/concepts/win32-api-conventions#strings). - [propget] HRESULT Name([out, retval] LPWSTR* value); -} ``` ```c# (but really MIDL3) @@ -1319,23 +1316,11 @@ namespace Microsoft.Web.WebView2.Core runtimeclass CoreWebView2DedicatedWorker { - String Name { get; }; - String ScriptUri { get; }; event Windows.Foundation.TypedEventHandler Destroyed; } - enum CoreWebView2ServiceWorkerState - { - New = 0, - Installing = 1, - Installed = 2, - Activating = 3, - Activated = 4, - Redundant = 5, - }; - [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Profile9")] { CoreWebView2ServiceWorkerManager ServiceWorkerManager { get; }; @@ -1349,7 +1334,7 @@ namespace Microsoft.Web.WebView2.Core Windows.Foundation.IAsyncOperation> GetServiceWorkerRegistrationsAsync(); - Windows.Foundation.IAsyncOperation GetServiceWorkerRegistrationAsync(String Scope); + Windows.Foundation.IAsyncOperation GetServiceWorkerRegistrationAsync(String ScopeUri); } runtimeclass CoreWebView2ServiceWorkerRegisteredEventArgs @@ -1359,11 +1344,18 @@ namespace Microsoft.Web.WebView2.Core runtimeclass CoreWebView2ServiceWorkerRegistration { - String Scope { get; }; + String ScopeUri { get; }; event Windows.Foundation.TypedEventHandler Destroyed; - Windows.Foundation.IAsyncOperation GetActiveServiceWorkerAsync(); + CoreWebView2ServiceWorker ActiveServiceWorker { get; }; + + event Windows.Foundation.TypedEventHandler ServiceWorkerActivated; + } + + runtime CoreWebView2ServiceWorkerActivatedEventArgs + { + CoreWebView2ServiceWorker ActiveServiceWorker { get; }; } runtimeclass CoreWebView2ServiceWorker @@ -1389,8 +1381,6 @@ namespace Microsoft.Web.WebView2.Core runtimeclass CoreWebView2SharedWorker { - String Name { get; }; - String ScriptUri { get; }; event Windows.Foundation.TypedEventHandler Destroyed; From a6f906f7981ef0b362b3a18721f72dc43c286cc1 Mon Sep 17 00:00:00 2001 From: Monica Chintala Date: Fri, 12 Jul 2024 13:31:39 -0700 Subject: [PATCH 7/7] minor updates to the spec --- specs/Workers.md | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/specs/Workers.md b/specs/Workers.md index 87225578e..2b6ba45bc 100644 --- a/specs/Workers.md +++ b/specs/Workers.md @@ -2,8 +2,9 @@ Workers support in WebView2 === # Background -Currently, WebView2 lacks comprehensive APIs for developers to fully utilize -workers, leading to increased load on the main thread, offloading to native, or +Currently, although workers can be used in web content in WebView2, WebView2 +lacks comprehensive WebView2 APIs for developers to fully utilize workers, +leading to increased load on the main thread, offloading to native, or forking your web app for WebView2 scenarios. To address this, the WebView2 team is introducing support for worker scenarios. This enhancement allows WebView2 users to interact with Web Workers from native apps, bypassing the JavaScript @@ -96,6 +97,18 @@ CoreWebViewSharedWorkerManager class, is used to retrieve all shared workers created within the context of a WebView2 application for the profile. This method gives a collection of CoreWebView2SharedWorkers objects. +# Background +This API specification provides a basic overview, including fundamental concepts +and introduces management APIs for interaction. +Please note that while this specification does not add new APIs, future API +specifications will introduce additional features for workers. + +Stay tuned for updates to this spec and look out for new API specs that will +expand on the capabilities of workers. + +See work in progress Workers API specs + - [API Spec for SW Background Sync](https://github.com/MicrosoftEdge/WebView2Feedback/blob/api-periodic-sync-and-background-sync-draft/specs/PeriodicBackgoundSyncAndBackgroundSync.md) + # Examples ## Dedicated Worker ## Monitoring the Creation/Destruction of Dedicated Workers. @@ -130,7 +143,7 @@ the main thread and a dedicated worker. // You can dispatch a message to the worker with the URL you want to // fetch data from the host app. - worker.PostMessage("{type: 'FETCH_URL',url: 'https://example.com/data.json'"); + worker.PostMessage("{ MyMessage: { type: 'FETCH_URL',url: 'https://example.com/data.json' }"); } void DedicatedWorkerCreatedExecuted(object target, ExecutedRoutedEventArgs e) @@ -149,7 +162,7 @@ the main thread and a dedicated worker. LogMessage("Dedicated Worker has been created with the script located at the " + scriptUri); // Send a message to the dedicated worker to offload fetch request from the host app. - dedicatedWorker.PostMessage(dedicatedWorker); + dedicatedWorker.PostMessageToWorker(dedicatedWorker); } }; } @@ -186,7 +199,7 @@ the main thread and a dedicated worker. // You can dispatch a message to the worker with the URL you want to fetch data from // the host app. - CHECK_FAILURE(worker->PostMessage("{type: 'FETCH_URL',url: 'https://example.com/data.json'")); + CHECK_FAILURE(worker->PostMessage("{ MyMessage: {type: 'FETCH_URL',url: 'https://example.com/data.json' }")); } ScenarioDedicatedWorker::ScenarioDedicatedWorker(AppWindow* appWindow) @@ -265,7 +278,7 @@ WorkerMessageReceived APIs. // The host application is sending a message to the worker to cache certain // resources. The message is a JSON string that specifies the type of the // message and the payload of the message. - worker.PostMessage("{\"type\": \"CACHE_URLS\", \"payload\": [\"/styles/main.css\", \"/scripts/main.js\", \"/images/logo.png\"]}"); + worker.PostMessage("{ MyMessage: { \"type\": \"CACHE_URLS\", \"payload\": [\"/styles/main.css\", \"/scripts/main.js\", \"/images/logo.png\"]} }"); } CoreWebView2ServiceWorkerManager ServiceWorkerManager_; @@ -335,7 +348,7 @@ WorkerMessageReceived APIs. // The host application is sending a message to the worker to cache certain // resources. The message is a JSON string that specifies the type of the // message and the payload of the message. - CHECK_FAILURE(worker->PostMessage(L"{\"type\": \"CACHE_URLS\", \"payload\": [\"/styles/main.css\", \"/scripts/main.js\", \"/images/logo.png\"]}")); + CHECK_FAILURE(worker->PostMessage(L"{ MyMessage: {\"type\": \"CACHE_URLS\", \"payload\": [\"/styles/main.css\", \"/scripts/main.js\", \"/images/logo.png\"]} }")); } void ScenarioServiceWorkerManager::CreateServiceWorkerManager() @@ -637,7 +650,7 @@ upcoming PostMessage and WorkerMessageReceived APIs. }; // Initiate the WebSocket connection by sending a message to the shared worker. - worker.PostMessage("{\"type\": \"INITIATE_WEBSOCKET_CONNECTION\", \"payload\": \"wss://example.com\"}"); + worker.PostMessage("{ MyMessage: {\"type\": \"INITIATE_WEBSOCKET_CONNECTION\", \"payload\": \"wss://example.com\"} }"); } CoreWebView2SharedWorkerManager SharedWorkerManager_; @@ -694,7 +707,7 @@ upcoming PostMessage and WorkerMessageReceived APIs. // Initiate the WebSocket connection by sending a message to the shared worker. - CHECK_FAILURE(worker->PostMessage(L"{\"type\": \"INITIATE_WEBSOCKET_CONNECTION\", \"payload\": \"wss://example.com\"}")); + CHECK_FAILURE(worker->PostMessage(L"{ MyMessage: {\"type\": \"INITIATE_WEBSOCKET_CONNECTION\", \"payload\": \"wss://example.com\"} }")); } void ScenarioSharedWorkerManager::GetSharedWorkerManager()