@javascriptcommon/react-native-webview 13.12.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +82 -0
- package/android/build.gradle +110 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +15 -0
- package/android/src/main/AndroidManifestNew.xml +13 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCBasicAuthCredential.java +11 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java +372 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java +450 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +328 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewConfig.java +11 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java +14 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt +720 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMessagingModule.kt +19 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModuleImpl.java +554 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java +56 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewWrapper.kt +39 -0
- package/android/src/main/java/com/reactnativecommunity/webview/URLUtil.java +179 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopCustomMenuSelectionEvent.kt +24 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopHttpErrorEvent.kt +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingErrorEvent.kt +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingFinishEvent.kt +24 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingProgressEvent.kt +24 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingStartEvent.kt +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopMessageEvent.kt +24 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopNewWindowEvent.kt +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopRenderProcessGoneEvent.kt +26 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopShouldStartLoadWithRequestEvent.kt +29 -0
- package/android/src/main/res/xml/file_provider_paths.xml +6 -0
- package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java +553 -0
- package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewModule.java +63 -0
- package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java +328 -0
- package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewModule.java +59 -0
- package/apple/RCTConvert+WKDataDetectorTypes.h +11 -0
- package/apple/RCTConvert+WKDataDetectorTypes.m +27 -0
- package/apple/RNCWKProcessPoolManager.h +15 -0
- package/apple/RNCWKProcessPoolManager.m +36 -0
- package/apple/RNCWebView.h +35 -0
- package/apple/RNCWebView.mm +546 -0
- package/apple/RNCWebViewDecisionManager.h +20 -0
- package/apple/RNCWebViewDecisionManager.m +47 -0
- package/apple/RNCWebViewImpl.h +161 -0
- package/apple/RNCWebViewImpl.m +1979 -0
- package/apple/RNCWebViewManager.h +9 -0
- package/apple/RNCWebViewManager.mm +215 -0
- package/apple/RNCWebViewModule.h +23 -0
- package/apple/RNCWebViewModule.mm +34 -0
- package/index.d.ts +65 -0
- package/index.js +4 -0
- package/ios/RNCWebView.xcodeproj/project.pbxproj +273 -0
- package/lib/NativeRNCWebViewModule.d.ts +10 -0
- package/lib/NativeRNCWebViewModule.js +1 -0
- package/lib/RNCWebViewNativeComponent.d.ts +242 -0
- package/lib/RNCWebViewNativeComponent.js +1 -0
- package/lib/WebView.android.d.ts +6 -0
- package/lib/WebView.android.js +1 -0
- package/lib/WebView.d.ts +6 -0
- package/lib/WebView.ios.d.ts +6 -0
- package/lib/WebView.ios.js +1 -0
- package/lib/WebView.js +1 -0
- package/lib/WebView.macos.d.ts +6 -0
- package/lib/WebView.macos.js +1 -0
- package/lib/WebView.styles.d.ts +38 -0
- package/lib/WebView.styles.js +1 -0
- package/lib/WebView.windows.d.ts +17 -0
- package/lib/WebView.windows.js +1 -0
- package/lib/WebViewNativeComponent.macos.d.ts +3 -0
- package/lib/WebViewNativeComponent.macos.js +1 -0
- package/lib/WebViewNativeComponent.windows.d.ts +3 -0
- package/lib/WebViewNativeComponent.windows.js +1 -0
- package/lib/WebViewShared.d.ts +38 -0
- package/lib/WebViewShared.js +1 -0
- package/lib/WebViewTypes.d.ts +1093 -0
- package/lib/WebViewTypes.js +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +1 -0
- package/macos/RNCWebView.xcodeproj/project.pbxproj +363 -0
- package/package.json +101 -0
- package/react-native-webview.podspec +46 -0
- package/react-native.config.js +44 -0
- package/src/NativeRNCWebViewModule.ts +15 -0
- package/src/RNCWebViewNativeComponent.ts +342 -0
- package/src/WebView.android.tsx +317 -0
- package/src/WebView.ios.tsx +299 -0
- package/src/WebView.macos.tsx +245 -0
- package/src/WebView.styles.ts +41 -0
- package/src/WebView.tsx +25 -0
- package/src/WebView.windows.tsx +210 -0
- package/src/WebViewNativeComponent.macos.ts +7 -0
- package/src/WebViewNativeComponent.windows.ts +8 -0
- package/src/WebViewShared.tsx +283 -0
- package/src/WebViewTypes.ts +1332 -0
- package/src/__tests__/WebViewShared-test.js +323 -0
- package/src/__tests__/__snapshots__/WebViewShared-test.js.snap +8 -0
- package/src/index.ts +4 -0
- package/windows/ExperimentalFeatures.props +11 -0
- package/windows/ReactNativeWebView/PropertySheet.props +16 -0
- package/windows/ReactNativeWebView/ReactNativeWebView.def +3 -0
- package/windows/ReactNativeWebView/ReactNativeWebView.filters +33 -0
- package/windows/ReactNativeWebView/ReactNativeWebView.vcxproj +189 -0
- package/windows/ReactNativeWebView/ReactPackageProvider.cpp +26 -0
- package/windows/ReactNativeWebView/ReactPackageProvider.h +20 -0
- package/windows/ReactNativeWebView/ReactPackageProvider.idl +7 -0
- package/windows/ReactNativeWebView/ReactWebView.cpp +242 -0
- package/windows/ReactNativeWebView/ReactWebView.h +56 -0
- package/windows/ReactNativeWebView/ReactWebView.idl +31 -0
- package/windows/ReactNativeWebView/ReactWebView2.cpp +473 -0
- package/windows/ReactNativeWebView/ReactWebView2.h +91 -0
- package/windows/ReactNativeWebView/ReactWebView2Manager.cpp +205 -0
- package/windows/ReactNativeWebView/ReactWebView2Manager.h +57 -0
- package/windows/ReactNativeWebView/ReactWebViewHelpers.cpp +70 -0
- package/windows/ReactNativeWebView/ReactWebViewHelpers.h +16 -0
- package/windows/ReactNativeWebView/ReactWebViewManager.cpp +224 -0
- package/windows/ReactNativeWebView/ReactWebViewManager.h +58 -0
- package/windows/ReactNativeWebView/WebBridge.cpp +19 -0
- package/windows/ReactNativeWebView/WebBridge.h +24 -0
- package/windows/ReactNativeWebView/WebBridge.idl +11 -0
- package/windows/ReactNativeWebView/pch.cpp +1 -0
- package/windows/ReactNativeWebView/pch.h +37 -0
- package/windows/ReactNativeWebView.sln +185 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
#include "pch.h"
|
|
5
|
+
#include "ReactWebView2.h"
|
|
6
|
+
#include "ReactWebViewHelpers.h"
|
|
7
|
+
|
|
8
|
+
#if HAS_WEBVIEW2
|
|
9
|
+
#include "JSValueXaml.h"
|
|
10
|
+
#include "ReactWebView2.g.cpp"
|
|
11
|
+
#include <winrt/Windows.Foundation.Metadata.h>
|
|
12
|
+
#include <winrt/Windows.System.h>
|
|
13
|
+
#include <optional>
|
|
14
|
+
|
|
15
|
+
namespace mux {
|
|
16
|
+
using namespace winrt::Microsoft::UI::Xaml::Controls;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
namespace winrt {
|
|
20
|
+
using namespace Microsoft::ReactNative;
|
|
21
|
+
using namespace Windows::Foundation;
|
|
22
|
+
using namespace Microsoft::Web::WebView2::Core;
|
|
23
|
+
using namespace Windows::Data::Json;
|
|
24
|
+
using namespace Windows::UI::Popups;
|
|
25
|
+
using namespace Windows::Web::Http;
|
|
26
|
+
using namespace Windows::Storage::Streams;
|
|
27
|
+
using namespace Windows::Security::Cryptography;
|
|
28
|
+
using namespace xaml;
|
|
29
|
+
using namespace xaml::Controls;
|
|
30
|
+
using namespace xaml::Input;
|
|
31
|
+
using namespace xaml::Media;
|
|
32
|
+
} // namespace winrt
|
|
33
|
+
|
|
34
|
+
namespace winrt::ReactNativeWebView::implementation {
|
|
35
|
+
|
|
36
|
+
ReactWebView2::ReactWebView2(winrt::IReactContext const& reactContext) : m_reactContext(reactContext) {
|
|
37
|
+
m_webView = mux::WebView2();
|
|
38
|
+
this->Content(m_webView);
|
|
39
|
+
RegisterEvents();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
ReactWebView2::~ReactWebView2() {}
|
|
43
|
+
|
|
44
|
+
void ReactWebView2::RegisterEvents() {
|
|
45
|
+
m_navigationStartingRevoker = m_webView.NavigationStarting(
|
|
46
|
+
winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
|
|
47
|
+
if (auto self = ref.get()) {
|
|
48
|
+
self->OnNavigationStarting(sender, args);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
m_navigationCompletedRevoker = m_webView.NavigationCompleted(
|
|
54
|
+
winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
|
|
55
|
+
if (auto self = ref.get()) {
|
|
56
|
+
self->OnNavigationCompleted(sender, args);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
m_CoreWebView2InitializedRevoker = m_webView.CoreWebView2Initialized(
|
|
61
|
+
winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args){
|
|
62
|
+
if (auto self = ref.get()) {
|
|
63
|
+
self->OnCoreWebView2Initialized(sender, args);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void ReactWebView2::RegisterCoreWebView2Events()
|
|
69
|
+
{
|
|
70
|
+
// We need to wait for the CoreWebView component to be initialized before registering its event listeners
|
|
71
|
+
assert(m_webView.CoreWebView2());
|
|
72
|
+
m_webResourceRequestedRevoker = m_webView.CoreWebView2().WebResourceRequested(
|
|
73
|
+
winrt::auto_revoke,
|
|
74
|
+
[ref = get_weak()](auto const& sender, auto const& args)
|
|
75
|
+
{
|
|
76
|
+
if (auto self = ref.get())
|
|
77
|
+
{
|
|
78
|
+
self->OnCoreWebView2ResourceRequseted(sender, args);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
m_CoreWebView2DOMContentLoadedRevoker = m_webView.CoreWebView2().DOMContentLoaded(
|
|
83
|
+
winrt::auto_revoke,
|
|
84
|
+
[ref = get_weak()](auto const& sender, auto const& args)
|
|
85
|
+
{
|
|
86
|
+
if (auto self = ref.get())
|
|
87
|
+
{
|
|
88
|
+
self->OnCoreWebView2DOMContentLoaded(sender, args);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
m_frameNavigationStartingRevoker = m_webView.CoreWebView2().FrameNavigationStarting(
|
|
93
|
+
winrt::auto_revoke,
|
|
94
|
+
[ref = get_weak()](auto const& sender, auto const& args)
|
|
95
|
+
{
|
|
96
|
+
if (auto self = ref.get())
|
|
97
|
+
{
|
|
98
|
+
self->OnCoreWebView2FrameNavigationStarted(sender, args);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
m_frameNavigationCompletedRevoker = m_webView.CoreWebView2().FrameNavigationCompleted(
|
|
103
|
+
winrt::auto_revoke,
|
|
104
|
+
[ref = get_weak()](auto const& sender, auto const& args)
|
|
105
|
+
{
|
|
106
|
+
if (auto self = ref.get())
|
|
107
|
+
{
|
|
108
|
+
self->OnCoreWebView2FrameNavigationCompleted(sender, args);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
m_sourceChangedRevoker = m_webView.CoreWebView2().SourceChanged(
|
|
113
|
+
winrt::auto_revoke,
|
|
114
|
+
[ref = get_weak()](auto const& sender, auto const& args)
|
|
115
|
+
{
|
|
116
|
+
if (auto self = ref.get())
|
|
117
|
+
{
|
|
118
|
+
self->OnCoreWebView2SourceChanged(sender, args);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
m_newWindowRequestedRevoker = m_webView.CoreWebView2().NewWindowRequested(
|
|
123
|
+
winrt::auto_revoke,
|
|
124
|
+
[ref = get_weak()](auto const& sender, auto const& args)
|
|
125
|
+
{
|
|
126
|
+
if (auto self = ref.get())
|
|
127
|
+
{
|
|
128
|
+
self->OnCoreWebView2NewWindowRequested(sender, args);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
bool ReactWebView2::Is17763OrHigher() {
|
|
134
|
+
static std::optional<bool> hasUniversalAPIContract_v7;
|
|
135
|
+
|
|
136
|
+
if (!hasUniversalAPIContract_v7.has_value()) {
|
|
137
|
+
hasUniversalAPIContract_v7 = winrt::Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 7);
|
|
138
|
+
}
|
|
139
|
+
return hasUniversalAPIContract_v7.value();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
void ReactWebView2::WriteWebViewNavigationEventArg(mux::WebView2 const& sender, winrt::IJSValueWriter const& eventDataWriter) {
|
|
143
|
+
auto tag = this->GetValue(winrt::FrameworkElement::TagProperty()).as<winrt::IPropertyValue>().GetInt64();
|
|
144
|
+
WriteProperty(eventDataWriter, L"canGoBack", sender.CanGoBack());
|
|
145
|
+
WriteProperty(eventDataWriter, L"canGoForward", sender.CanGoForward());
|
|
146
|
+
if (Is17763OrHigher()) {
|
|
147
|
+
WriteProperty(eventDataWriter, L"loading", !sender.IsLoaded());
|
|
148
|
+
}
|
|
149
|
+
WriteProperty(eventDataWriter, L"target", tag);
|
|
150
|
+
if (auto uri = sender.Source()) {
|
|
151
|
+
WriteProperty(eventDataWriter, L"url", uri.AbsoluteCanonicalUri());
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
void ReactWebView2::OnNavigationStarting(mux::WebView2 const& webView, winrt::CoreWebView2NavigationStartingEventArgs const& /* args */) {
|
|
156
|
+
m_reactContext.DispatchEvent(
|
|
157
|
+
*this,
|
|
158
|
+
L"topLoadingStart",
|
|
159
|
+
[&](winrt::IJSValueWriter const& eventDataWriter) noexcept {
|
|
160
|
+
eventDataWriter.WriteObjectBegin();
|
|
161
|
+
WriteWebViewNavigationEventArg(webView, eventDataWriter);
|
|
162
|
+
eventDataWriter.WriteObjectEnd();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
if (m_messagingEnabled) {
|
|
167
|
+
if (m_messageToken)
|
|
168
|
+
{
|
|
169
|
+
// In case the webview has a new navigation, we need to clean up the old WebMessageReceived handler
|
|
170
|
+
webView.WebMessageReceived(m_messageToken);
|
|
171
|
+
}
|
|
172
|
+
m_messageToken = webView.WebMessageReceived([this](auto const& /* sender */ , winrt::CoreWebView2WebMessageReceivedEventArgs const& messageArgs)
|
|
173
|
+
{
|
|
174
|
+
try {
|
|
175
|
+
auto message = messageArgs.TryGetWebMessageAsString();
|
|
176
|
+
this->OnMessagePosted(message);
|
|
177
|
+
}
|
|
178
|
+
catch (...) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
void ReactWebView2::OnMessagePosted(hstring const& message)
|
|
186
|
+
{
|
|
187
|
+
HandleMessageFromJS(message);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
void ReactWebView2::OnNavigationCompleted(mux::WebView2 const& webView, winrt::CoreWebView2NavigationCompletedEventArgs const& /* args */) {
|
|
191
|
+
m_reactContext.DispatchEvent(
|
|
192
|
+
*this,
|
|
193
|
+
L"topLoadingFinish",
|
|
194
|
+
[&](winrt::IJSValueWriter const& eventDataWriter) noexcept {
|
|
195
|
+
eventDataWriter.WriteObjectBegin();
|
|
196
|
+
WriteWebViewNavigationEventArg(webView, eventDataWriter);
|
|
197
|
+
eventDataWriter.WriteObjectEnd();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
if (m_messagingEnabled) {
|
|
201
|
+
winrt::hstring message = LR"(window.alert = function (msg) {window.chrome.webview.postMessage(`{"type":"__alert","message":"${msg}"}`)};
|
|
202
|
+
window.ReactNativeWebView = {postMessage: function (data) {window.chrome.webview.postMessage(String(data))}};
|
|
203
|
+
const originalPostMessage = globalThis.postMessage;
|
|
204
|
+
globalThis.postMessage = function (data) { originalPostMessage(data); globalThis.ReactNativeWebView.postMessage(typeof data == 'string' ? data : JSON.stringify(data));};)";
|
|
205
|
+
webView.ExecuteScriptAsync(message);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
void ReactWebView2::OnCoreWebView2Initialized(mux::WebView2 const& sender, mux::CoreWebView2InitializedEventArgs const& /* args */) {
|
|
210
|
+
assert(sender.CoreWebView2());
|
|
211
|
+
|
|
212
|
+
RegisterCoreWebView2Events();
|
|
213
|
+
|
|
214
|
+
if (m_navigateToHtml != L"") {
|
|
215
|
+
m_webView.NavigateToString(m_navigateToHtml);
|
|
216
|
+
m_navigateToHtml = L"";
|
|
217
|
+
}
|
|
218
|
+
if (!m_request.empty())
|
|
219
|
+
{
|
|
220
|
+
auto uriString = winrt::to_hstring(m_request.at("uri").AsString());
|
|
221
|
+
sender.CoreWebView2().AddWebResourceRequestedFilter(
|
|
222
|
+
uriString, winrt::CoreWebView2WebResourceContext::All);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
void ReactWebView2::OnCoreWebView2ResourceRequseted(
|
|
227
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& sender,
|
|
228
|
+
winrt::CoreWebView2WebResourceRequestedEventArgs const& args)
|
|
229
|
+
{
|
|
230
|
+
assert(sender);
|
|
231
|
+
if (!m_request.empty()) {
|
|
232
|
+
auto uriString = winrt::to_hstring(m_request.at("uri").AsString());
|
|
233
|
+
if (args.Request().Uri() == uriString) {
|
|
234
|
+
SetupRequest(m_request, args.Request());
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
void ReactWebView2::OnCoreWebView2DOMContentLoaded(
|
|
240
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& sender,
|
|
241
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2DOMContentLoadedEventArgs const& /* args */)
|
|
242
|
+
{
|
|
243
|
+
m_reactContext.DispatchEvent(
|
|
244
|
+
*this,
|
|
245
|
+
L"topDOMContentLoaded",
|
|
246
|
+
[&](winrt::IJSValueWriter const& eventDataWriter) noexcept
|
|
247
|
+
{
|
|
248
|
+
eventDataWriter.WriteObjectBegin();
|
|
249
|
+
WriteWebViewNavigationEventArg(m_webView, eventDataWriter);
|
|
250
|
+
eventDataWriter.WriteObjectEnd();
|
|
251
|
+
});
|
|
252
|
+
if (!m_injectedJavascript.empty())
|
|
253
|
+
{
|
|
254
|
+
sender.ExecuteScriptAsync(m_injectedJavascript);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
void ReactWebView2::OnCoreWebView2FrameNavigationStarted(
|
|
259
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& /* sender */,
|
|
260
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2NavigationStartingEventArgs const& /* args */)
|
|
261
|
+
{
|
|
262
|
+
m_reactContext.DispatchEvent(
|
|
263
|
+
*this,
|
|
264
|
+
L"topFrameNavigationStart",
|
|
265
|
+
[&](winrt::IJSValueWriter const& eventDataWriter) noexcept
|
|
266
|
+
{
|
|
267
|
+
eventDataWriter.WriteObjectBegin();
|
|
268
|
+
WriteWebViewNavigationEventArg(m_webView, eventDataWriter);
|
|
269
|
+
eventDataWriter.WriteObjectEnd();
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
void ReactWebView2::OnCoreWebView2FrameNavigationCompleted(
|
|
274
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& /* sender */,
|
|
275
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2NavigationCompletedEventArgs const& /* args */)
|
|
276
|
+
{
|
|
277
|
+
m_reactContext.DispatchEvent(
|
|
278
|
+
*this,
|
|
279
|
+
L"topFrameNavigationFinish",
|
|
280
|
+
[&](winrt::IJSValueWriter const& eventDataWriter) noexcept
|
|
281
|
+
{
|
|
282
|
+
eventDataWriter.WriteObjectBegin();
|
|
283
|
+
WriteWebViewNavigationEventArg(m_webView, eventDataWriter);
|
|
284
|
+
eventDataWriter.WriteObjectEnd();
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
void ReactWebView2::OnCoreWebView2SourceChanged(
|
|
289
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& /* sender */,
|
|
290
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2SourceChangedEventArgs const& /* args */)
|
|
291
|
+
{
|
|
292
|
+
m_reactContext.DispatchEvent(
|
|
293
|
+
*this,
|
|
294
|
+
L"topSourceChanged",
|
|
295
|
+
[&](winrt::IJSValueWriter const& eventDataWriter) noexcept
|
|
296
|
+
{
|
|
297
|
+
eventDataWriter.WriteObjectBegin();
|
|
298
|
+
WriteWebViewNavigationEventArg(m_webView, eventDataWriter);
|
|
299
|
+
eventDataWriter.WriteObjectEnd();
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
void ReactWebView2::OnCoreWebView2NewWindowRequested(
|
|
304
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& sender,
|
|
305
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2NewWindowRequestedEventArgs const& args)
|
|
306
|
+
{
|
|
307
|
+
if (m_linkHandlingEnabled) {
|
|
308
|
+
m_reactContext.DispatchEvent(
|
|
309
|
+
*this,
|
|
310
|
+
L"topOpenWindow",
|
|
311
|
+
[&](winrt::IJSValueWriter const& eventDataWriter) noexcept
|
|
312
|
+
{
|
|
313
|
+
eventDataWriter.WriteObjectBegin();
|
|
314
|
+
WriteProperty(eventDataWriter, L"targetUrl", args.Uri());
|
|
315
|
+
eventDataWriter.WriteObjectEnd();
|
|
316
|
+
});
|
|
317
|
+
args.Handled(true);
|
|
318
|
+
} else {
|
|
319
|
+
try
|
|
320
|
+
{
|
|
321
|
+
winrt::Windows::Foundation::Uri uri(args.Uri());
|
|
322
|
+
winrt::Windows::System::Launcher::LaunchUriAsync(uri);
|
|
323
|
+
args.Handled(true);
|
|
324
|
+
}
|
|
325
|
+
catch (winrt::hresult_error& e)
|
|
326
|
+
{
|
|
327
|
+
// Do Nothing
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
void ReactWebView2::HandleMessageFromJS(winrt::hstring const& message) {
|
|
333
|
+
winrt::JsonObject jsonObject;
|
|
334
|
+
if (winrt::JsonObject::TryParse(message, jsonObject) && jsonObject.HasKey(L"type"))
|
|
335
|
+
{
|
|
336
|
+
if (auto v = jsonObject.Lookup(L"type"); v && v.ValueType() == JsonValueType::String) {
|
|
337
|
+
auto type = v.GetString();
|
|
338
|
+
if (type == L"__alert") {
|
|
339
|
+
auto dialog = winrt::MessageDialog(jsonObject.GetNamedString(L"message"));
|
|
340
|
+
dialog.Commands().Append(winrt::UICommand(L"OK"));
|
|
341
|
+
dialog.ShowAsync();
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
m_reactContext.DispatchEvent(
|
|
348
|
+
*this,
|
|
349
|
+
L"topMessage",
|
|
350
|
+
[&](winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter) noexcept {
|
|
351
|
+
eventDataWriter.WriteObjectBegin();
|
|
352
|
+
WriteProperty(eventDataWriter, L"data", message);
|
|
353
|
+
eventDataWriter.WriteObjectEnd();
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
void ReactWebView2::MessagingEnabled(bool enabled) noexcept{
|
|
358
|
+
m_messagingEnabled = enabled;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
bool ReactWebView2::MessagingEnabled() const noexcept{
|
|
362
|
+
return m_messagingEnabled;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
void ReactWebView2::LinkHandlingEnabled(bool enabled) noexcept {
|
|
366
|
+
m_linkHandlingEnabled = enabled;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
bool ReactWebView2::LinkHandlingEnabled() const noexcept {
|
|
370
|
+
return m_linkHandlingEnabled;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
void ReactWebView2::WebResourceRequestSource(Microsoft::ReactNative::JSValueObject const& source) noexcept
|
|
374
|
+
{
|
|
375
|
+
m_request = std::move(source.Copy());
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
JSValueObject ReactWebView2::WebResourceRequestSource() const noexcept
|
|
379
|
+
{
|
|
380
|
+
return m_request.Copy();
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
void ReactWebView2::InjectedJavascript(winrt::hstring const& injectedJavascript) noexcept {
|
|
384
|
+
m_injectedJavascript = injectedJavascript;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
winrt::hstring ReactWebView2::InjectedJavascript() const noexcept
|
|
388
|
+
{
|
|
389
|
+
return m_injectedJavascript;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
void ReactWebView2::NavigateToHtml(winrt::hstring const& html) {
|
|
393
|
+
if (m_webView.CoreWebView2()) {
|
|
394
|
+
m_webView.NavigateToString(html);
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
m_webView.EnsureCoreWebView2Async();
|
|
398
|
+
m_navigateToHtml = html;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
winrt::fire_and_forget ReactWebView2::NavigateWithWebResourceRequest(Microsoft::ReactNative::IJSValueReader const& source)
|
|
403
|
+
{
|
|
404
|
+
m_request = JSValueObject::ReadFrom(source);
|
|
405
|
+
co_await m_webView.EnsureCoreWebView2Async();
|
|
406
|
+
assert(m_webView.CoreWebView2());
|
|
407
|
+
if (m_webView.CoreWebView2())
|
|
408
|
+
{
|
|
409
|
+
auto uri = winrt::Uri(winrt::to_hstring(m_request.at("uri").AsString()));
|
|
410
|
+
auto method = (m_request.find("method") != m_request.end()) ? m_request.at("method").AsString() : "GET";
|
|
411
|
+
auto webResourceRequest = m_webView.CoreWebView2().Environment().CreateWebResourceRequest(
|
|
412
|
+
uri.ToString(), winrt::to_hstring(method), nullptr, L"");
|
|
413
|
+
|
|
414
|
+
SetupRequest(m_request.Copy(), webResourceRequest);
|
|
415
|
+
|
|
416
|
+
m_webView.CoreWebView2().NavigateWithWebResourceRequest(webResourceRequest);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
void ReactWebView2::WriteCookiesToWebView2(std::string const& cookies) {
|
|
421
|
+
// Persisting cookies passed from JS
|
|
422
|
+
// Cookies are separated by ;, and adheres to the Set-Cookie HTTP header format of RFC-6265.
|
|
423
|
+
|
|
424
|
+
auto cookieManager = m_webView.CoreWebView2().CookieManager();
|
|
425
|
+
auto cookiesList = ReactWebViewHelpers::SplitString(cookies, ";,");
|
|
426
|
+
for (const auto& cookie_str : cookiesList) {
|
|
427
|
+
auto cookieData = ReactWebViewHelpers::ParseSetCookieHeader(ReactWebViewHelpers::TrimString(cookie_str));
|
|
428
|
+
|
|
429
|
+
if (!cookieData.count("Name") || !cookieData.count("Value")) {
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
auto cookie = cookieManager.CreateCookie(
|
|
434
|
+
winrt::to_hstring(cookieData["Name"]),
|
|
435
|
+
winrt::to_hstring(cookieData["Value"]),
|
|
436
|
+
cookieData.count("Domain") ? winrt::to_hstring(cookieData["Domain"]) : L"",
|
|
437
|
+
cookieData.count("Path") ? winrt::to_hstring(cookieData["Path"]) : L"");
|
|
438
|
+
cookieManager.AddOrUpdateCookie(cookie);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
void ReactWebView2::SetupRequest(Microsoft::ReactNative::JSValueObject const& srcMap, winrt::Microsoft::Web::WebView2::Core::CoreWebView2WebResourceRequest const& request) {
|
|
443
|
+
bool hasHeaders = srcMap.find("headers") != srcMap.end();
|
|
444
|
+
auto method = srcMap.find("method") != srcMap.end() ? srcMap.at("method").AsString() : "GET";
|
|
445
|
+
request.Method(winrt::to_hstring(method));
|
|
446
|
+
if (method == "POST")
|
|
447
|
+
{
|
|
448
|
+
auto formBody = srcMap.at("body").AsString();
|
|
449
|
+
winrt::InMemoryRandomAccessStream formContent;
|
|
450
|
+
winrt::IBuffer buffer{winrt::CryptographicBuffer::ConvertStringToBinary(
|
|
451
|
+
winrt::to_hstring(formBody), winrt::BinaryStringEncoding::Utf8)};
|
|
452
|
+
formContent.ReadAsync(buffer, buffer.Length(), InputStreamOptions::None);
|
|
453
|
+
request.Content(formContent);
|
|
454
|
+
}
|
|
455
|
+
if (hasHeaders)
|
|
456
|
+
{
|
|
457
|
+
for (auto const& header : srcMap.at("headers").AsObject())
|
|
458
|
+
{
|
|
459
|
+
auto const& headerKey = header.first;
|
|
460
|
+
auto const& headerValue = header.second;
|
|
461
|
+
if (headerValue.IsNull())
|
|
462
|
+
continue;
|
|
463
|
+
if (headerKey == "Cookie") {
|
|
464
|
+
WriteCookiesToWebView2(headerValue.AsString());
|
|
465
|
+
} else {
|
|
466
|
+
request.Headers().SetHeader(winrt::to_hstring(headerKey), winrt::to_hstring(headerValue.AsString()));
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
} // namespace winrt::ReactNativeWebView::implementation
|
|
472
|
+
|
|
473
|
+
#endif // HAS_WEBVIEW2
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#if HAS_WEBVIEW2
|
|
7
|
+
#include "winrt/Microsoft.ReactNative.h"
|
|
8
|
+
#include "NativeModules.h"
|
|
9
|
+
#include "ReactWebView2.g.h"
|
|
10
|
+
|
|
11
|
+
#include "winrt/ReactNativeWebView.h"
|
|
12
|
+
|
|
13
|
+
using namespace winrt::ReactNativeWebView;
|
|
14
|
+
|
|
15
|
+
namespace winrt::ReactNativeWebView::implementation {
|
|
16
|
+
|
|
17
|
+
class ReactWebView2 : public ReactWebView2T<ReactWebView2> {
|
|
18
|
+
public:
|
|
19
|
+
ReactWebView2(Microsoft::ReactNative::IReactContext const& reactContext);
|
|
20
|
+
void MessagingEnabled(bool enabled) noexcept;
|
|
21
|
+
bool MessagingEnabled() const noexcept;
|
|
22
|
+
void LinkHandlingEnabled(bool enabled) noexcept;
|
|
23
|
+
bool LinkHandlingEnabled() const noexcept;
|
|
24
|
+
void WebResourceRequestSource(Microsoft::ReactNative::JSValueObject const& source) noexcept;
|
|
25
|
+
Microsoft::ReactNative::JSValueObject WebResourceRequestSource() const noexcept;
|
|
26
|
+
void InjectedJavascript(winrt::hstring const& injectedJavascript) noexcept;
|
|
27
|
+
winrt::hstring InjectedJavascript() const noexcept;
|
|
28
|
+
void NavigateToHtml(winrt::hstring const& html);
|
|
29
|
+
winrt::fire_and_forget NavigateWithWebResourceRequest(Microsoft::ReactNative::IJSValueReader const& source);
|
|
30
|
+
~ReactWebView2();
|
|
31
|
+
|
|
32
|
+
private:
|
|
33
|
+
winrt::hstring m_navigateToHtml = L"";
|
|
34
|
+
winrt::Microsoft::ReactNative::JSValueObject m_request{};
|
|
35
|
+
bool m_messagingEnabled{ true };
|
|
36
|
+
bool m_linkHandlingEnabled{ true };
|
|
37
|
+
winrt::hstring m_injectedJavascript = L"";
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
winrt::Microsoft::UI::Xaml::Controls::WebView2 m_webView{ nullptr };
|
|
41
|
+
Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
|
|
42
|
+
winrt::event_token m_messageToken;
|
|
43
|
+
winrt::Microsoft::UI::Xaml::Controls::WebView2::NavigationStarting_revoker m_navigationStartingRevoker{};
|
|
44
|
+
winrt::Microsoft::UI::Xaml::Controls::WebView2::NavigationCompleted_revoker m_navigationCompletedRevoker{};
|
|
45
|
+
winrt::Microsoft::UI::Xaml::Controls::WebView2::CoreWebView2Initialized_revoker m_CoreWebView2InitializedRevoker{};
|
|
46
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2::WebResourceRequested_revoker
|
|
47
|
+
m_webResourceRequestedRevoker{};
|
|
48
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2::DOMContentLoaded_revoker
|
|
49
|
+
m_CoreWebView2DOMContentLoadedRevoker{};
|
|
50
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2::FrameNavigationStarting_revoker m_frameNavigationStartingRevoker{};
|
|
51
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2::FrameNavigationCompleted_revoker m_frameNavigationCompletedRevoker{};
|
|
52
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2::SourceChanged_revoker m_sourceChangedRevoker{};
|
|
53
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2::NewWindowRequested_revoker m_newWindowRequestedRevoker{};
|
|
54
|
+
void HandleMessageFromJS(winrt::hstring const& message);
|
|
55
|
+
void RegisterEvents();
|
|
56
|
+
void RegisterCoreWebView2Events();
|
|
57
|
+
void WriteWebViewNavigationEventArg(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter);
|
|
58
|
+
void OnNavigationStarting(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::Web::WebView2::Core::CoreWebView2NavigationStartingEventArgs const& args);
|
|
59
|
+
void OnNavigationCompleted(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::Web::WebView2::Core::CoreWebView2NavigationCompletedEventArgs const& args);
|
|
60
|
+
void OnCoreWebView2Initialized(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::UI::Xaml::Controls::CoreWebView2InitializedEventArgs const& args);
|
|
61
|
+
void OnCoreWebView2ResourceRequseted(
|
|
62
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& sender,
|
|
63
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2WebResourceRequestedEventArgs const& args);
|
|
64
|
+
void OnCoreWebView2DOMContentLoaded(
|
|
65
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& sender,
|
|
66
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2DOMContentLoadedEventArgs const& args);
|
|
67
|
+
void OnCoreWebView2FrameNavigationStarted(
|
|
68
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& sender,
|
|
69
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2NavigationStartingEventArgs const& args);
|
|
70
|
+
void OnCoreWebView2FrameNavigationCompleted(
|
|
71
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& sender,
|
|
72
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2NavigationCompletedEventArgs const& args);
|
|
73
|
+
void OnCoreWebView2SourceChanged(
|
|
74
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& sender,
|
|
75
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2SourceChangedEventArgs const& args);
|
|
76
|
+
void OnCoreWebView2NewWindowRequested(
|
|
77
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2 const& sender,
|
|
78
|
+
winrt::Microsoft::Web::WebView2::Core::CoreWebView2NewWindowRequestedEventArgs const& args);
|
|
79
|
+
|
|
80
|
+
void OnMessagePosted(hstring const& message);
|
|
81
|
+
bool Is17763OrHigher();
|
|
82
|
+
void WriteCookiesToWebView2(std::string const& cookies);
|
|
83
|
+
void SetupRequest(Microsoft::ReactNative::JSValueObject const& srcMap, winrt::Microsoft::Web::WebView2::Core::CoreWebView2WebResourceRequest const& request);
|
|
84
|
+
};
|
|
85
|
+
} // namespace winrt::ReactNativeWebView2::implementation
|
|
86
|
+
|
|
87
|
+
namespace winrt::ReactNativeWebView::factory_implementation {
|
|
88
|
+
struct ReactWebView2 : ReactWebView2T<ReactWebView2, implementation::ReactWebView2> {};
|
|
89
|
+
} // namespace winrt::ReactNativeWebView2::factory_implementation
|
|
90
|
+
|
|
91
|
+
#endif // HAS_WEBVIEW2
|