react-native-webview-bootpay 13.8.42 → 13.13.4

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.
Files changed (100) hide show
  1. package/README.md +53 -69
  2. package/android/build.gradle +1 -11
  3. package/android/gradle.properties +0 -42
  4. package/android/src/main/AndroidManifest.xml +3 -1
  5. package/android/src/main/AndroidManifestNew.xml +13 -0
  6. package/android/src/main/java/kr/co/bootpay/webview/BPCWebChromeClient.java +54 -10
  7. package/android/src/main/java/kr/co/bootpay/webview/BPCWebView.java +101 -68
  8. package/android/src/main/java/kr/co/bootpay/webview/BPCWebViewClient.java +68 -60
  9. package/android/src/main/java/kr/co/bootpay/webview/BPCWebViewManagerImpl.kt +119 -65
  10. package/android/src/main/java/kr/co/bootpay/webview/BPCWebViewMessagingModule.kt +9 -0
  11. package/android/src/main/java/kr/co/bootpay/webview/BPCWebViewModuleImpl.java +1 -1
  12. package/android/src/main/java/kr/co/bootpay/webview/BootpayUrlHelper.java +4 -12
  13. package/android/src/newarch/{com/reactnativecommunity → kr/co/bootpay}/webview/BPCWebViewManager.java +118 -109
  14. package/android/src/newarch/{com/reactnativecommunity → kr/co/bootpay}/webview/BPCWebViewModule.java +1 -1
  15. package/android/src/{main/java → oldarch}/kr/co/bootpay/webview/BPCWebViewManager.java +63 -58
  16. package/android/src/{main/java → oldarch}/kr/co/bootpay/webview/BPCWebViewModule.java +1 -1
  17. package/apple/BPCWebView.mm +21 -12
  18. package/apple/BPCWebViewImpl.h +11 -1
  19. package/apple/BPCWebViewImpl.m +278 -216
  20. package/apple/BPCWebViewManager.mm +5 -24
  21. package/apple/BPCWebViewModule.h +23 -0
  22. package/apple/BPCWebViewModule.mm +34 -0
  23. package/apple/RCTConvert+WKDataDetectorTypes.h +11 -0
  24. package/apple/RCTConvert+WKDataDetectorTypes.m +27 -0
  25. package/ios/RNCWebView.xcodeproj/project.pbxproj +24 -24
  26. package/ios/RNCWebView.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  27. package/ios/RNCWebView.xcodeproj/project.xcworkspace/xcuserdata/taesupyoon.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  28. package/ios/RNCWebView.xcodeproj/xcuserdata/taesupyoon.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
  29. package/lib/BPCWebViewNativeComponent.d.ts +24 -25
  30. package/lib/BPCWebViewNativeComponent.js +1 -1
  31. package/lib/{NativeBPCWebView.d.ts → NativeBPCWebViewModule.d.ts} +2 -5
  32. package/lib/{NativeBPCWebView.js → NativeBPCWebViewModule.js} +1 -1
  33. package/lib/WebView.android.d.ts +0 -1
  34. package/lib/WebView.android.js +1 -1
  35. package/lib/WebView.d.ts +0 -1
  36. package/lib/WebView.ios.d.ts +0 -1
  37. package/lib/WebView.ios.js +1 -1
  38. package/lib/WebView.js +1 -1
  39. package/lib/WebView.macos.d.ts +0 -1
  40. package/lib/WebView.macos.js +1 -1
  41. package/lib/WebView.styles.d.ts +37 -11
  42. package/lib/WebView.styles.js +1 -1
  43. package/lib/WebView.windows.d.ts +0 -1
  44. package/lib/WebView.windows.js +1 -1
  45. package/lib/WebViewNativeComponent.macos.d.ts +1 -2
  46. package/lib/WebViewNativeComponent.windows.d.ts +1 -2
  47. package/lib/WebViewShared.d.ts +0 -1
  48. package/lib/WebViewShared.js +1 -1
  49. package/lib/WebViewTypes.d.ts +51 -3
  50. package/lib/WebViewTypes.js +1 -1
  51. package/lib/index.d.ts +0 -1
  52. package/macos/RNCWebView.xcodeproj/project.pbxproj +36 -36
  53. package/package.json +13 -12
  54. package/react-native.config.js +1 -5
  55. package/src/BPCWebViewNativeComponent.ts +143 -79
  56. package/src/NativeBPCWebViewModule.ts +13 -0
  57. package/src/WebView.android.tsx +295 -190
  58. package/src/WebView.ios.tsx +253 -186
  59. package/src/WebView.macos.tsx +220 -152
  60. package/src/WebView.styles.ts +9 -12
  61. package/src/WebView.tsx +14 -7
  62. package/src/WebView.windows.tsx +180 -126
  63. package/src/WebViewNativeComponent.macos.ts +4 -5
  64. package/src/WebViewNativeComponent.windows.ts +6 -8
  65. package/src/WebViewShared.tsx +139 -91
  66. package/src/WebViewTypes.ts +80 -35
  67. package/src/__tests__/WebViewShared-test.js +170 -55
  68. package/windows/ReactNativeWebView/ReactNativeWebView.vcxproj +8 -17
  69. package/windows/ReactNativeWebView/ReactPackageProvider.cpp +5 -1
  70. package/windows/ReactNativeWebView/ReactWebView.cpp +73 -6
  71. package/windows/ReactNativeWebView/ReactWebView.h +11 -1
  72. package/windows/ReactNativeWebView/ReactWebView.idl +12 -3
  73. package/windows/ReactNativeWebView/ReactWebView2.cpp +294 -129
  74. package/windows/ReactNativeWebView/ReactWebView2.h +42 -5
  75. package/windows/ReactNativeWebView/ReactWebView2Manager.cpp +60 -34
  76. package/windows/ReactNativeWebView/ReactWebView2Manager.h +4 -4
  77. package/windows/ReactNativeWebView/ReactWebViewHelpers.cpp +70 -0
  78. package/windows/ReactNativeWebView/ReactWebViewHelpers.h +16 -0
  79. package/windows/ReactNativeWebView/ReactWebViewManager.cpp +22 -3
  80. package/windows/ReactNativeWebView/ReactWebViewManager.h +6 -1
  81. package/windows/ReactNativeWebView/pch.h +11 -7
  82. package/windows/ReactNativeWebView.sln +14 -14
  83. package/ios/main.jsbundle +0 -457
  84. package/lib/BPCWebViewNativeComponent.d.ts.map +0 -1
  85. package/lib/NativeBPCWebView.d.ts.map +0 -1
  86. package/lib/WebView.android.d.ts.map +0 -1
  87. package/lib/WebView.d.ts.map +0 -1
  88. package/lib/WebView.ios.d.ts.map +0 -1
  89. package/lib/WebView.macos.d.ts.map +0 -1
  90. package/lib/WebView.styles.d.ts.map +0 -1
  91. package/lib/WebView.windows.d.ts.map +0 -1
  92. package/lib/WebViewNativeComponent.macos.d.ts.map +0 -1
  93. package/lib/WebViewNativeComponent.windows.d.ts.map +0 -1
  94. package/lib/WebViewShared.d.ts.map +0 -1
  95. package/lib/WebViewTypes.d.ts.map +0 -1
  96. package/lib/index.d.ts.map +0 -1
  97. package/react-native-webview-bootpay.podspec +0 -46
  98. package/src/NativeBPCWebView.ts +0 -14
  99. package/windows/ReactNativeWebView/packages.config +0 -5
  100. /package/android/src/main/java/kr/co/bootpay/webview/{BPCWebviewWrapper.kt → BPCWebViewWrapper.kt} +0 -0
@@ -3,95 +3,38 @@
3
3
 
4
4
  #include "pch.h"
5
5
  #include "ReactWebView2.h"
6
+ #include "ReactWebViewHelpers.h"
6
7
 
7
8
  #if HAS_WEBVIEW2
8
9
  #include "JSValueXaml.h"
9
10
  #include "ReactWebView2.g.cpp"
10
11
  #include <winrt/Windows.Foundation.Metadata.h>
12
+ #include <winrt/Windows.System.h>
11
13
  #include <optional>
12
- #include <iostream>
13
- #include <vector>
14
- #include <algorithm>
15
- #include <cctype>
16
14
 
15
+ namespace mux {
16
+ using namespace winrt::Microsoft::UI::Xaml::Controls;
17
+ }
17
18
 
18
19
  namespace winrt {
19
20
  using namespace Microsoft::ReactNative;
20
21
  using namespace Windows::Foundation;
21
- using namespace Windows::UI;
22
- using namespace Windows::UI::Xaml;
23
- using namespace Windows::UI::Xaml::Controls;
24
- using namespace Microsoft::UI::Xaml::Controls;
25
22
  using namespace Microsoft::Web::WebView2::Core;
26
23
  using namespace Windows::Data::Json;
27
24
  using namespace Windows::UI::Popups;
28
- using namespace Windows::UI::Xaml::Input;
29
- using namespace Windows::UI::Xaml::Media;
25
+ using namespace Windows::Web::Http;
30
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;
31
32
  } // namespace winrt
32
33
 
33
34
  namespace winrt::ReactNativeWebView::implementation {
34
- namespace helpers {
35
- std::string trimString(const std::string& str) {
36
- std::string trimmedString = str;
37
-
38
- // Trim from start
39
- trimmedString.erase(0, trimmedString.find_first_not_of(" \t\n\r\f\v"));
40
-
41
- // Trim from end
42
- trimmedString.erase(trimmedString.find_last_not_of(" \t\n\r\f\v") + 1);
43
-
44
- return trimmedString;
45
- }
46
- std::vector<std::string> splitString(
47
- const std::string& str,
48
- const std::string& delim) {
49
- std::vector<std::string> tokens;
50
- auto startPos = 0;
51
- auto endPos = str.find(delim);
52
-
53
- while (endPos != std::string::npos) {
54
- auto token = str.substr(startPos, endPos - startPos);
55
- tokens.push_back(trimString(token));
56
-
57
- startPos = endPos + delim.length();
58
- endPos = str.find(delim, startPos);
59
- }
60
-
61
- auto lastToken = str.substr(startPos);
62
- tokens.push_back(trimString(lastToken));
63
-
64
- return tokens;
65
- }
66
-
67
- std::map<std::string, std::string> parseSetCookieHeader(
68
- const std::string& setCookieHeader) {
69
- std::map<std::string, std::string> cookie;
70
-
71
- // Split the header into individual cookie strings
72
- auto cookieStrings = splitString(setCookieHeader, ";");
73
-
74
- // Extract the cookie name and value from the first string
75
- auto nameValuePair = splitString(cookieStrings[0], "=");
76
- cookie["Name"] = trimString(nameValuePair[0]);
77
- cookie["Value"] = trimString(nameValuePair[1]);
78
-
79
- // Extract the attributes from the remaining strings
80
- for (std::size_t i = 1; i < cookieStrings.size(); ++i) {
81
- auto attributeValuePair = splitString(cookieStrings[i], "=");
82
- auto attributeName = attributeValuePair[0];
83
- auto attributeValue =
84
- attributeValuePair.size() > 1 ? attributeValuePair[1] : "";
85
- cookie[attributeName] = trimString(attributeValue);
86
- }
87
-
88
- return cookie;
89
- }
90
- } // namespace HP
91
-
92
35
 
93
36
  ReactWebView2::ReactWebView2(winrt::IReactContext const& reactContext) : m_reactContext(reactContext) {
94
- m_webView = winrt::WebView2();
37
+ m_webView = mux::WebView2();
95
38
  this->Content(m_webView);
96
39
  RegisterEvents();
97
40
  }
@@ -101,18 +44,18 @@ namespace winrt::ReactNativeWebView::implementation {
101
44
  void ReactWebView2::RegisterEvents() {
102
45
  m_navigationStartingRevoker = m_webView.NavigationStarting(
103
46
  winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
104
- if (auto self = ref.get()) {
105
- self->OnNavigationStarting(sender, args);
106
- }
47
+ if (auto self = ref.get()) {
48
+ self->OnNavigationStarting(sender, args);
49
+ }
107
50
 
108
- });
51
+ });
109
52
 
110
53
  m_navigationCompletedRevoker = m_webView.NavigationCompleted(
111
54
  winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
112
- if (auto self = ref.get()) {
113
- self->OnNavigationCompleted(sender, args);
114
- }
115
- });
55
+ if (auto self = ref.get()) {
56
+ self->OnNavigationCompleted(sender, args);
57
+ }
58
+ });
116
59
 
117
60
  m_CoreWebView2InitializedRevoker = m_webView.CoreWebView2Initialized(
118
61
  winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args){
@@ -122,6 +65,71 @@ namespace winrt::ReactNativeWebView::implementation {
122
65
  });
123
66
  }
124
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
+
125
133
  bool ReactWebView2::Is17763OrHigher() {
126
134
  static std::optional<bool> hasUniversalAPIContract_v7;
127
135
 
@@ -131,7 +139,7 @@ namespace winrt::ReactNativeWebView::implementation {
131
139
  return hasUniversalAPIContract_v7.value();
132
140
  }
133
141
 
134
- void ReactWebView2::WriteWebViewNavigationEventArg(winrt::WebView2 const& sender, winrt::IJSValueWriter const& eventDataWriter) {
142
+ void ReactWebView2::WriteWebViewNavigationEventArg(mux::WebView2 const& sender, winrt::IJSValueWriter const& eventDataWriter) {
135
143
  auto tag = this->GetValue(winrt::FrameworkElement::TagProperty()).as<winrt::IPropertyValue>().GetInt64();
136
144
  WriteProperty(eventDataWriter, L"canGoBack", sender.CanGoBack());
137
145
  WriteProperty(eventDataWriter, L"canGoForward", sender.CanGoForward());
@@ -144,7 +152,7 @@ namespace winrt::ReactNativeWebView::implementation {
144
152
  }
145
153
  }
146
154
 
147
- void ReactWebView2::OnNavigationStarting(winrt::WebView2 const& webView, winrt::CoreWebView2NavigationStartingEventArgs const& /* args */) {
155
+ void ReactWebView2::OnNavigationStarting(mux::WebView2 const& webView, winrt::CoreWebView2NavigationStartingEventArgs const& /* args */) {
148
156
  m_reactContext.DispatchEvent(
149
157
  *this,
150
158
  L"topLoadingStart",
@@ -156,7 +164,12 @@ namespace winrt::ReactNativeWebView::implementation {
156
164
 
157
165
 
158
166
  if (m_messagingEnabled) {
159
- m_messageToken = webView.WebMessageReceived([this](auto const& /* sender */, winrt::CoreWebView2WebMessageReceivedEventArgs const& messageArgs)
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)
160
173
  {
161
174
  try {
162
175
  auto message = messageArgs.TryGetWebMessageAsString();
@@ -174,7 +187,7 @@ namespace winrt::ReactNativeWebView::implementation {
174
187
  HandleMessageFromJS(message);
175
188
  }
176
189
 
177
- void ReactWebView2::OnNavigationCompleted(winrt::WebView2 const& webView, winrt::CoreWebView2NavigationCompletedEventArgs const& /* args */) {
190
+ void ReactWebView2::OnNavigationCompleted(mux::WebView2 const& webView, winrt::CoreWebView2NavigationCompletedEventArgs const& /* args */) {
178
191
  m_reactContext.DispatchEvent(
179
192
  *this,
180
193
  L"topLoadingFinish",
@@ -186,52 +199,140 @@ namespace winrt::ReactNativeWebView::implementation {
186
199
 
187
200
  if (m_messagingEnabled) {
188
201
  winrt::hstring message = LR"(window.alert = function (msg) {window.chrome.webview.postMessage(`{"type":"__alert","message":"${msg}"}`)};
189
- window.ReactNativeWebView = {postMessage: function (data) {window.chrome.webview.postMessage(String(data))}};)";
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));};)";
190
205
  webView.ExecuteScriptAsync(message);
191
206
  }
192
207
  }
193
208
 
194
- void ReactWebView2::OnCoreWebView2Initialized(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::UI::Xaml::Controls::CoreWebView2InitializedEventArgs const& /* args */) {
209
+ void ReactWebView2::OnCoreWebView2Initialized(mux::WebView2 const& sender, mux::CoreWebView2InitializedEventArgs const& /* args */) {
195
210
  assert(sender.CoreWebView2());
196
211
 
212
+ RegisterCoreWebView2Events();
213
+
197
214
  if (m_navigateToHtml != L"") {
198
215
  m_webView.NavigateToString(m_navigateToHtml);
199
216
  m_navigateToHtml = L"";
200
217
  }
201
- else if (m_navigationWithHeaders.has_value()) {
202
- auto headers = m_navigationWithHeaders.value().second;
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
+ }
203
225
 
204
- auto stream = InMemoryRandomAccessStream();
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
+ }
205
238
 
206
- // construct headers string
207
- winrt::hstring headers_str;
208
- for (auto const& header : headers) {
209
- if (header.Key() == L"cookie" || header.Key() == L"Cookie") {
210
- WriteCookiesToWebView2(header.Value());
211
- }
212
- else {
213
- headers_str = headers_str + header.Key() + L": " +
214
- header.Value() + L"\r\n";
215
- }
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
+ }
216
257
 
217
- }
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
+ }
218
272
 
219
- auto request =
220
- m_webView.CoreWebView2().Environment().CreateWebResourceRequest(
221
- m_navigationWithHeaders.value().first,
222
- L"GET",
223
- stream,
224
- headers_str
225
- );
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
+ }
226
302
 
227
- m_webView.CoreWebView2().NavigateWithWebResourceRequest(request);
228
- m_navigationWithHeaders.reset();
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
+ }
229
329
  }
230
330
  }
231
331
 
232
332
  void ReactWebView2::HandleMessageFromJS(winrt::hstring const& message) {
233
333
  winrt::JsonObject jsonObject;
234
- if (winrt::JsonObject::TryParse(message, jsonObject)) {
334
+ if (winrt::JsonObject::TryParse(message, jsonObject) && jsonObject.HasKey(L"type"))
335
+ {
235
336
  if (auto v = jsonObject.Lookup(L"type"); v && v.ValueType() == JsonValueType::String) {
236
337
  auto type = v.GetString();
237
338
  if (type == L"__alert") {
@@ -248,23 +349,47 @@ namespace winrt::ReactNativeWebView::implementation {
248
349
  L"topMessage",
249
350
  [&](winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter) noexcept {
250
351
  eventDataWriter.WriteObjectBegin();
251
- {
252
- WriteProperty(eventDataWriter, L"data", message);
253
- }
352
+ WriteProperty(eventDataWriter, L"data", message);
254
353
  eventDataWriter.WriteObjectEnd();
255
354
  });
256
355
  }
257
356
 
258
- void ReactWebView2::MessagingEnabled(bool enabled) noexcept {
357
+ void ReactWebView2::MessagingEnabled(bool enabled) noexcept{
259
358
  m_messagingEnabled = enabled;
260
359
  }
261
360
 
262
- bool ReactWebView2::MessagingEnabled() const noexcept {
361
+ bool ReactWebView2::MessagingEnabled() const noexcept{
263
362
  return m_messagingEnabled;
264
363
  }
265
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
+ }
266
391
 
267
- void ReactWebView2::NavigateToHtml(winrt::hstring html) {
392
+ void ReactWebView2::NavigateToHtml(winrt::hstring const& html) {
268
393
  if (m_webView.CoreWebView2()) {
269
394
  m_webView.NavigateToString(html);
270
395
  }
@@ -274,33 +399,73 @@ namespace winrt::ReactNativeWebView::implementation {
274
399
  }
275
400
  }
276
401
 
277
- void ReactWebView2::NavigateWithHeaders(winrt::hstring uri, IMapView<winrt::hstring, winrt::hstring> headers) {
278
- m_navigationWithHeaders = std::make_pair(uri, headers);
279
- m_webView.EnsureCoreWebView2Async();
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
+ }
280
418
  }
281
419
 
282
- void ReactWebView2::WriteCookiesToWebView2(winrt::hstring cookies) {
420
+ void ReactWebView2::WriteCookiesToWebView2(std::string const& cookies) {
283
421
  // Persisting cookies passed from JS
284
422
  // Cookies are separated by ;, and adheres to the Set-Cookie HTTP header format of RFC-6265.
285
423
 
286
- auto cm = m_webView.CoreWebView2().CookieManager();
287
- auto cookies_list =
288
- helpers::splitString(winrt::to_string(cookies), ";,");
289
- for (const auto& cookie_str : cookies_list) {
290
- auto cookieData = helpers::parseSetCookieHeader(helpers::trimString(cookie_str));
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));
291
428
 
292
429
  if (!cookieData.count("Name") || !cookieData.count("Value")) {
293
430
  continue;
294
431
  }
295
- auto cookie = cm.CreateCookie(
432
+
433
+ auto cookie = cookieManager.CreateCookie(
296
434
  winrt::to_hstring(cookieData["Name"]),
297
435
  winrt::to_hstring(cookieData["Value"]),
298
- cookieData.count("Domain")
299
- ? winrt::to_hstring(cookieData["Domain"])
300
- : L"",
301
- cookieData.count("Path")
302
- ? winrt::to_hstring(cookieData["Path"]) : L"");
303
- cm.AddOrUpdateCookie(cookie);
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
+ }
304
469
  }
305
470
  }
306
471
  } // namespace winrt::ReactNativeWebView::implementation
@@ -4,7 +4,6 @@
4
4
  #pragma once
5
5
 
6
6
  #if HAS_WEBVIEW2
7
-
8
7
  #include "winrt/Microsoft.ReactNative.h"
9
8
  #include "NativeModules.h"
10
9
  #include "ReactWebView2.g.h"
@@ -20,14 +19,23 @@ namespace winrt::ReactNativeWebView::implementation {
20
19
  ReactWebView2(Microsoft::ReactNative::IReactContext const& reactContext);
21
20
  void MessagingEnabled(bool enabled) noexcept;
22
21
  bool MessagingEnabled() const noexcept;
23
- void NavigateToHtml(winrt::hstring html);
24
- void NavigateWithHeaders(winrt::hstring uri, IMapView<winrt::hstring, winrt::hstring> headers);
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);
25
30
  ~ReactWebView2();
26
31
 
27
32
  private:
28
33
  winrt::hstring m_navigateToHtml = L"";
29
- std::optional<std::pair<winrt::hstring, IMapView<winrt::hstring, winrt::hstring>>> m_navigationWithHeaders;
34
+ winrt::Microsoft::ReactNative::JSValueObject m_request{};
30
35
  bool m_messagingEnabled{ true };
36
+ bool m_linkHandlingEnabled{ true };
37
+ winrt::hstring m_injectedJavascript = L"";
38
+
31
39
 
32
40
  winrt::Microsoft::UI::Xaml::Controls::WebView2 m_webView{ nullptr };
33
41
  Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
@@ -35,15 +43,44 @@ namespace winrt::ReactNativeWebView::implementation {
35
43
  winrt::Microsoft::UI::Xaml::Controls::WebView2::NavigationStarting_revoker m_navigationStartingRevoker{};
36
44
  winrt::Microsoft::UI::Xaml::Controls::WebView2::NavigationCompleted_revoker m_navigationCompletedRevoker{};
37
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{};
38
54
  void HandleMessageFromJS(winrt::hstring const& message);
39
55
  void RegisterEvents();
40
- void WriteCookiesToWebView2(winrt::hstring cookies);
56
+ void RegisterCoreWebView2Events();
41
57
  void WriteWebViewNavigationEventArg(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter);
42
58
  void OnNavigationStarting(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::Web::WebView2::Core::CoreWebView2NavigationStartingEventArgs const& args);
43
59
  void OnNavigationCompleted(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::Web::WebView2::Core::CoreWebView2NavigationCompletedEventArgs const& args);
44
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
+
45
80
  void OnMessagePosted(hstring const& message);
46
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);
47
84
  };
48
85
  } // namespace winrt::ReactNativeWebView2::implementation
49
86