Skip to content

Commit

Permalink
feat(windows): Adds support for compiling Windows module for WinAppSDK (
Browse files Browse the repository at this point in the history
#3411)

* Adds support for compiling Windows module for WinAppSDK

Similar to other packages (react-native-svg,
@react-native-picker/picker, etc.), this change adds WinAppSDK support
for apps that compile react-native-windows from source targeting
WinAppSDK.

* Minor fix for WinUI 2 builds for ReactWebView2

---------

Co-authored-by: Thibault Malbranche <thibault@brigad.co>
  • Loading branch information
rozele and Titozzz committed May 7, 2024
1 parent 8bc122d commit d843539
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 47 deletions.
6 changes: 5 additions & 1 deletion windows/ReactNativeWebView/ReactPackageProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@
#endif

#include "ReactWebView2Manager.h"
#ifndef USE_WINUI3
#include "ReactWebViewManager.h"
#endif

using namespace winrt::Microsoft::ReactNative;

namespace winrt::ReactNativeWebView::implementation {

void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept {
#ifndef USE_WINUI3
packageBuilder.AddViewManager(L"ReactWebViewManager", []() { return winrt::make<ReactWebViewManager>(); });
#endif

#if HAS_WEBVIEW2
packageBuilder.AddViewManager(L"ReactWebView2Manager", []() { return winrt::make<ReactWebView2Manager>(); });
#endif
}

} // namespace winrt::ReactNativeWebView::implementation
} // namespace winrt::ReactNativeWebView::implementation
12 changes: 8 additions & 4 deletions windows/ReactNativeWebView/ReactWebView.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#ifndef USE_WINUI3

#include "pch.h"
#include "JSValueXaml.h"
#include "ReactWebView.h"
Expand Down Expand Up @@ -41,7 +43,7 @@ namespace winrt::ReactNativeWebView::implementation {
if (auto self = ref.get()) {
self->OnNavigationStarting(sender, args);
}

});

m_navigationCompletedRevoker = m_webView.NavigationCompleted(
Expand All @@ -60,7 +62,7 @@ namespace winrt::ReactNativeWebView::implementation {

m_domContentLoadedRevoker = m_webView.DOMContentLoaded(
winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
if (auto self = ref.get())
if (auto self = ref.get())
{
self->OnDOMContentLoaded(sender, args);
}
Expand Down Expand Up @@ -167,7 +169,7 @@ namespace winrt::ReactNativeWebView::implementation {
}
}
}

m_reactContext.DispatchEvent(
*this,
L"topMessage",
Expand Down Expand Up @@ -234,4 +236,6 @@ namespace winrt::ReactNativeWebView::implementation {
bool ReactWebView::MessagingEnabled() const noexcept{
return m_messagingEnabled;
}
} // namespace winrt::ReactNativeWebView::implementation
} // namespace winrt::ReactNativeWebView::implementation

#endif // USE_WINUI3
6 changes: 5 additions & 1 deletion windows/ReactNativeWebView/ReactWebView.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#pragma once

#ifndef USE_WINUI3

#include "winrt/Microsoft.ReactNative.h"
#include "NativeModules.h"
#include "ReactWebView.g.h"
Expand Down Expand Up @@ -49,4 +51,6 @@ namespace winrt::ReactNativeWebView::implementation {

namespace winrt::ReactNativeWebView::factory_implementation {
struct ReactWebView : ReactWebViewT<ReactWebView, implementation::ReactWebView> {};
} // namespace winrt::ReactNativeWebView::factory_implementation
} // namespace winrt::ReactNativeWebView::factory_implementation

#endif // USE_WINUI3
8 changes: 6 additions & 2 deletions windows/ReactNativeWebView/ReactWebView.idl
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include <NamespaceRedirect.h>

namespace ReactNativeWebView{
#if !defined(USE_WINUI3)
[default_interface]
runtimeclass ReactWebView : Windows.UI.Xaml.Controls.ContentPresenter{
ReactWebView(Microsoft.ReactNative.IReactContext context);
Expand All @@ -7,15 +10,16 @@ namespace ReactNativeWebView{
void RequestFocus();
void PostMessage(String message);
};
#endif
#if __has_include(<VersionMacros.h>)
#include <VersionMacros.h>
#else
#define RNW_VERSION_AT_LEAST(x,y,z) false
#endif

#if RNW_VERSION_AT_LEAST(0,68,0) && defined(WINUI2_HAS_WEBVIEW2)
#if RNW_VERSION_AT_LEAST(0,68,0) && (defined(WINUI2_HAS_WEBVIEW2) || defined(USE_WINUI3))
[default_interface]
runtimeclass ReactWebView2 : Windows.UI.Xaml.Controls.ContentPresenter{
runtimeclass ReactWebView2 : XAML_NAMESPACE.Controls.ContentPresenter{
ReactWebView2(Microsoft.ReactNative.IReactContext context);
void NavigateToHtml(String html);
void NavigateWithWebResourceRequest(Microsoft.ReactNative.IJSValueReader request);
Expand Down
33 changes: 18 additions & 15 deletions windows/ReactNativeWebView/ReactWebView2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,32 @@
#include "JSValueXaml.h"
#include "ReactWebView2.g.cpp"
#include <winrt/Windows.Foundation.Metadata.h>
#include <winrt/Windows.System.h>
#include <optional>

namespace mux {
using namespace winrt::Microsoft::UI::Xaml::Controls;
}

namespace winrt {
using namespace Microsoft::ReactNative;
using namespace Windows::Foundation;
using namespace Windows::UI;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Microsoft::UI::Xaml::Controls;
using namespace Microsoft::Web::WebView2::Core;
using namespace Windows::Data::Json;
using namespace Windows::UI::Popups;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::Web::Http;
using namespace Windows::Storage::Streams;
using namespace Windows::Security::Cryptography;
using namespace xaml;
using namespace xaml::Controls;
using namespace xaml::Input;
using namespace xaml::Media;
} // namespace winrt

namespace winrt::ReactNativeWebView::implementation {

ReactWebView2::ReactWebView2(winrt::IReactContext const& reactContext) : m_reactContext(reactContext) {
m_webView = winrt::WebView2();
m_webView = mux::WebView2();
this->Content(m_webView);
RegisterEvents();
}
Expand All @@ -44,7 +47,7 @@ namespace winrt::ReactNativeWebView::implementation {
if (auto self = ref.get()) {
self->OnNavigationStarting(sender, args);
}

});

m_navigationCompletedRevoker = m_webView.NavigationCompleted(
Expand All @@ -60,7 +63,7 @@ namespace winrt::ReactNativeWebView::implementation {
self->OnCoreWebView2Initialized(sender, args);
}
});
}
}

void ReactWebView2::RegisterCoreWebView2Events()
{
Expand Down Expand Up @@ -136,7 +139,7 @@ namespace winrt::ReactNativeWebView::implementation {
return hasUniversalAPIContract_v7.value();
}

void ReactWebView2::WriteWebViewNavigationEventArg(winrt::WebView2 const& sender, winrt::IJSValueWriter const& eventDataWriter) {
void ReactWebView2::WriteWebViewNavigationEventArg(mux::WebView2 const& sender, winrt::IJSValueWriter const& eventDataWriter) {
auto tag = this->GetValue(winrt::FrameworkElement::TagProperty()).as<winrt::IPropertyValue>().GetInt64();
WriteProperty(eventDataWriter, L"canGoBack", sender.CanGoBack());
WriteProperty(eventDataWriter, L"canGoForward", sender.CanGoForward());
Expand All @@ -149,7 +152,7 @@ namespace winrt::ReactNativeWebView::implementation {
}
}

void ReactWebView2::OnNavigationStarting(winrt::WebView2 const& webView, winrt::CoreWebView2NavigationStartingEventArgs const& /* args */) {
void ReactWebView2::OnNavigationStarting(mux::WebView2 const& webView, winrt::CoreWebView2NavigationStartingEventArgs const& /* args */) {
m_reactContext.DispatchEvent(
*this,
L"topLoadingStart",
Expand Down Expand Up @@ -184,7 +187,7 @@ namespace winrt::ReactNativeWebView::implementation {
HandleMessageFromJS(message);
}

void ReactWebView2::OnNavigationCompleted(winrt::WebView2 const& webView, winrt::CoreWebView2NavigationCompletedEventArgs const& /* args */) {
void ReactWebView2::OnNavigationCompleted(mux::WebView2 const& webView, winrt::CoreWebView2NavigationCompletedEventArgs const& /* args */) {
m_reactContext.DispatchEvent(
*this,
L"topLoadingFinish",
Expand All @@ -195,15 +198,15 @@ namespace winrt::ReactNativeWebView::implementation {
});

if (m_messagingEnabled) {
winrt::hstring message = LR"(window.alert = function (msg) {window.chrome.webview.postMessage(`{"type":"__alert","message":"${msg}"}`)};
winrt::hstring message = LR"(window.alert = function (msg) {window.chrome.webview.postMessage(`{"type":"__alert","message":"${msg}"}`)};
window.ReactNativeWebView = {postMessage: function (data) {window.chrome.webview.postMessage(String(data))}};
const originalPostMessage = globalThis.postMessage;
globalThis.postMessage = function (data) { originalPostMessage(data); globalThis.ReactNativeWebView.postMessage(typeof data == 'string' ? data : JSON.stringify(data));};)";
webView.ExecuteScriptAsync(message);
}
}

void ReactWebView2::OnCoreWebView2Initialized(winrt::WebView2 const& sender, winrt::CoreWebView2InitializedEventArgs const& /* args */) {
void ReactWebView2::OnCoreWebView2Initialized(mux::WebView2 const& sender, mux::CoreWebView2InitializedEventArgs const& /* args */) {
assert(sender.CoreWebView2());

RegisterCoreWebView2Events();
Expand Down Expand Up @@ -407,7 +410,7 @@ namespace winrt::ReactNativeWebView::implementation {
auto method = (m_request.find("method") != m_request.end()) ? m_request.at("method").AsString() : "GET";
auto webResourceRequest = m_webView.CoreWebView2().Environment().CreateWebResourceRequest(
uri.ToString(), winrt::to_hstring(method), nullptr, L"");

SetupRequest(m_request.Copy(), webResourceRequest);

m_webView.CoreWebView2().NavigateWithWebResourceRequest(webResourceRequest);
Expand Down
22 changes: 12 additions & 10 deletions windows/ReactNativeWebView/ReactWebView2Manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@
#include "ReactWebView2.h"
#include "JSValueXaml.h"

namespace mux {
using namespace winrt::Microsoft::UI::Xaml::Controls;
}

namespace winrt {
using namespace Microsoft::ReactNative;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Input;
using namespace Microsoft::UI::Xaml::Controls;
using namespace Windows::Web::Http;
using namespace Windows::Web::Http::Headers;
using namespace xaml;
using namespace xaml::Controls;
using namespace xaml::Input;
}

namespace winrt::ReactNativeWebView::implementation {
Expand Down Expand Up @@ -57,7 +59,7 @@ namespace winrt::ReactNativeWebView::implementation {
IJSValueReader const& propertyMapReader) noexcept {
auto control = view.as<winrt::ContentPresenter>();
auto content = control.Content();
auto webView = content.as<winrt::WebView2>();
auto webView = content.as<mux::WebView2>();
const JSValueObject& propertyMap = JSValueObject::ReadFrom(propertyMapReader);

for (auto const& pair : propertyMap) {
Expand All @@ -81,7 +83,7 @@ namespace winrt::ReactNativeWebView::implementation {
}
if (isPackagerAsset && uriString.find(fileScheme) == 0) {
auto bundleRootPath = winrt::to_string(ReactNativeHost().InstanceSettings().BundleRootPath());
uriString.replace(0, std::size(fileScheme), bundleRootPath.empty() ? "ms-appx-web:///Bundle/" : bundleRootPath);
uriString.replace(0, std::size(fileScheme), bundleRootPath.empty() ? "ms-appx-web:///Bundle/" : bundleRootPath);
}
if (uriString.find("ms-appdata://") == 0 || uriString.find("ms-appx-web://") == 0) {
reactWebView2.NavigateToHtml(to_hstring(uriString));
Expand Down Expand Up @@ -110,7 +112,7 @@ namespace winrt::ReactNativeWebView::implementation {
auto reactWebView2 = view.as<ReactNativeWebView::ReactWebView2>();
reactWebView2.LinkHandlingEnabled(linkHandlingEnabled);
}
}
}
}

// IViewManagerWithExportedEventTypeConstants
Expand Down Expand Up @@ -153,7 +155,7 @@ namespace winrt::ReactNativeWebView::implementation {
winrt::IJSValueReader const& commandArgsReader) noexcept {
auto control = view.as<winrt::ContentPresenter>();
auto content = control.Content();
auto webView = content.as<winrt::WebView2>();
auto webView = content.as<mux::WebView2>();
auto commandArgs = JSValue::ReadArrayFrom(commandArgsReader);

if (commandId == L"goForward") {
Expand All @@ -179,7 +181,7 @@ namespace winrt::ReactNativeWebView::implementation {
}
else if (commandId == L"requestFocus") {
FocusManager::TryFocusAsync(webView, FocusState::Programmatic);
}
}
else if (commandId == L"clearCache") {
// There is no way to clear the cache in WebView2 because it is shared with Edge.
// The best we can do is clear the cookies, because we cannot access history or local storage.
Expand Down
8 changes: 4 additions & 4 deletions windows/ReactNativeWebView/ReactWebView2Manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include "NativeModules.h"

namespace winrt::ReactNativeWebView::implementation {

class ReactWebView2Manager : public winrt::implements<
ReactWebView2Manager,
winrt::Microsoft::ReactNative::IViewManager,
Expand All @@ -22,7 +22,7 @@ namespace winrt::ReactNativeWebView::implementation {
ReactWebView2Manager();
// IViewManager
winrt::hstring Name() noexcept;
winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;
xaml::FrameworkElement CreateView() noexcept;

// IViewManagerWithReactContext
winrt::Microsoft::ReactNative::IReactContext ReactContext() noexcept;
Expand All @@ -34,7 +34,7 @@ namespace winrt::ReactNativeWebView::implementation {
NativeProps() noexcept;

void UpdateProperties(
winrt::Windows::UI::Xaml::FrameworkElement const& view,
xaml::FrameworkElement const& view,
winrt::Microsoft::ReactNative::IJSValueReader const& propertyMapReader) noexcept;

// IViewManagerWithExportedEventTypeConstants
Expand All @@ -45,7 +45,7 @@ namespace winrt::ReactNativeWebView::implementation {
winrt::Windows::Foundation::Collections::IVectorView<winrt::hstring> Commands() noexcept;

void DispatchCommand(
winrt::Windows::UI::Xaml::FrameworkElement const& view,
xaml::FrameworkElement const& view,
winrt::hstring const& commandId,
winrt::Microsoft::ReactNative::IJSValueReader const& commandArgsReader) noexcept;

Expand Down
11 changes: 9 additions & 2 deletions windows/ReactNativeWebView/ReactWebViewManager.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#ifndef USE_WINUI3

#include "pch.h"
#include "ReactWebViewManager.h"
#include "NativeModules.h"
Expand Down Expand Up @@ -144,7 +149,7 @@ namespace winrt::ReactNativeWebView::implementation {
auto reactWebView = view.as<ReactNativeWebView::ReactWebView>();
reactWebView.MessagingEnabled(messagingEnabled);
}
}
}
}

// IViewManagerWithExportedEventTypeConstants
Expand Down Expand Up @@ -213,4 +218,6 @@ namespace winrt::ReactNativeWebView::implementation {
}
}

} // namespace winrt::ReactWebView::implementation
} // namespace winrt::ReactWebView::implementation

#endif // USE_WINUI3
5 changes: 4 additions & 1 deletion windows/ReactNativeWebView/ReactWebViewManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
// Licensed under the MIT License.

#pragma once

#ifndef USE_WINUI3

#include "winrt/Microsoft.ReactNative.h"
#include "NativeModules.h"
#include "ReactWebView.h"

namespace winrt::ReactNativeWebView::implementation {

class ReactWebViewManager : public winrt::implements<
ReactWebViewManager,
winrt::Microsoft::ReactNative::IViewManager,
Expand Down

0 comments on commit d843539

Please sign in to comment.