No Description

ReactWebView.cpp 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // Licensed under the MIT License.
  3. #include "pch.h"
  4. #include "JSValueXaml.h"
  5. #include "ReactWebView.h"
  6. #include "ReactWebView.g.cpp"
  7. #include "winrt/WebViewBridge.h"
  8. namespace winrt {
  9. using namespace Microsoft::ReactNative;
  10. using namespace Windows::Data::Json;
  11. using namespace Windows::Foundation;
  12. using namespace Windows::UI;
  13. using namespace Windows::UI::Popups;
  14. using namespace Windows::UI::Xaml;
  15. using namespace Windows::UI::Xaml::Controls;
  16. using namespace Windows::UI::Xaml::Input;
  17. using namespace Windows::UI::Xaml::Media;
  18. } // namespace winrt
  19. namespace winrt::ReactNativeWebView::implementation {
  20. ReactWebView::ReactWebView(winrt::IReactContext const& reactContext) : m_reactContext(reactContext) {
  21. #ifdef CHAKRACORE_UWP
  22. m_webView = winrt::WebView(winrt::WebViewExecutionMode::SeparateProcess);
  23. #else
  24. m_webView = winrt::WebView();
  25. #endif
  26. this->Content(m_webView);
  27. RegisterEvents();
  28. }
  29. void ReactWebView::RegisterEvents() {
  30. m_navigationStartingRevoker = m_webView.NavigationStarting(
  31. winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
  32. if (auto self = ref.get()) {
  33. self->OnNavigationStarting(sender, args);
  34. }
  35. });
  36. m_navigationCompletedRevoker = m_webView.NavigationCompleted(
  37. winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
  38. if (auto self = ref.get()) {
  39. self->OnNavigationCompleted(sender, args);
  40. }
  41. });
  42. m_navigationFailedRevoker = m_webView.NavigationFailed(
  43. winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
  44. if (auto self = ref.get()) {
  45. self->OnNavigationFailed(sender, args);
  46. }
  47. });
  48. m_scriptNotifyRevoker = m_webView.ScriptNotify(
  49. winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) {
  50. if (auto self = ref.get()) {
  51. self->OnScriptNotify(sender, args);
  52. }
  53. });
  54. }
  55. void ReactWebView::WriteWebViewNavigationEventArg(winrt::WebView const& sender, winrt::IJSValueWriter const& eventDataWriter) {
  56. auto tag = this->GetValue(winrt::FrameworkElement::TagProperty()).as<winrt::IPropertyValue>().GetInt64();
  57. WriteProperty(eventDataWriter, L"canGoBack", sender.CanGoBack());
  58. WriteProperty(eventDataWriter, L"canGoForward", sender.CanGoForward());
  59. WriteProperty(eventDataWriter, L"loading", !sender.IsLoaded());
  60. WriteProperty(eventDataWriter, L"target", tag);
  61. WriteProperty(eventDataWriter, L"title", sender.DocumentTitle());
  62. if (auto uri = sender.Source()) {
  63. WriteProperty(eventDataWriter, L"url", uri.AbsoluteCanonicalUri());
  64. }
  65. }
  66. void ReactWebView::OnNavigationStarting(winrt::WebView const& webView, winrt::WebViewNavigationStartingEventArgs const& /*args*/) {
  67. m_reactContext.DispatchEvent(
  68. *this,
  69. L"topLoadingStart",
  70. [&](winrt::IJSValueWriter const& eventDataWriter) noexcept {
  71. eventDataWriter.WriteObjectBegin();
  72. WriteWebViewNavigationEventArg(webView, eventDataWriter);
  73. eventDataWriter.WriteObjectEnd();
  74. });
  75. if (m_messagingEnabled) {
  76. auto tag = this->GetValue(winrt::FrameworkElement::TagProperty()).as<winrt::IPropertyValue>().GetInt64();
  77. auto bridge = WebViewBridge::WebBridge(tag);
  78. webView.AddWebAllowedObject(L"__RN_WEBVIEW_JS_BRIDGE", bridge);
  79. }
  80. }
  81. void ReactWebView::OnNavigationCompleted(winrt::WebView const& webView, winrt::WebViewNavigationCompletedEventArgs const& /*args*/) {
  82. m_reactContext.DispatchEvent(
  83. *this,
  84. L"topLoadingFinish",
  85. [&](winrt::IJSValueWriter const& eventDataWriter) noexcept {
  86. eventDataWriter.WriteObjectBegin();
  87. WriteWebViewNavigationEventArg(webView, eventDataWriter);
  88. eventDataWriter.WriteObjectEnd();
  89. });
  90. winrt::hstring windowAlert = L"window.alert = function (msg) {window.external.notify(`{\"type\":\"__alert\",\"message\":\"${msg}\"}`)};";
  91. winrt::hstring postMessage = L"window.ReactNativeWebView = {postMessage: function (data) {window.external.notify(String(data))}};";
  92. webView.InvokeScriptAsync(L"eval", { windowAlert + postMessage });
  93. }
  94. void ReactWebView::OnNavigationFailed(winrt::IInspectable const& /*sender*/, winrt::WebViewNavigationFailedEventArgs const& args) {
  95. m_reactContext.DispatchEvent(
  96. *this,
  97. L"topLoadingError",
  98. [&](winrt::IJSValueWriter const& eventDataWriter) noexcept {
  99. auto httpCode = static_cast<int32_t>(args.WebErrorStatus());
  100. eventDataWriter.WriteObjectBegin();
  101. {
  102. WriteProperty(eventDataWriter, L"code", httpCode);
  103. WriteWebViewNavigationEventArg(m_webView, eventDataWriter);
  104. }
  105. eventDataWriter.WriteObjectEnd();
  106. });
  107. }
  108. void ReactWebView::OnScriptNotify(winrt::IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::Controls::NotifyEventArgs const& args) {
  109. winrt::JsonObject jsonObject;
  110. if (winrt::JsonObject::TryParse(args.Value(), jsonObject) && jsonObject.HasKey(L"type")) {
  111. auto type = jsonObject.GetNamedString(L"type");
  112. if (type == L"__alert") {
  113. auto dialog = winrt::MessageDialog(jsonObject.GetNamedString(L"message"));
  114. dialog.Commands().Append(winrt::UICommand(L"OK"));
  115. dialog.ShowAsync();
  116. return;
  117. }
  118. }
  119. PostMessage(winrt::hstring(args.Value()));
  120. }
  121. void ReactWebView::PostMessage(winrt::hstring const& message) {
  122. m_reactContext.DispatchEvent(
  123. *this,
  124. L"topMessage",
  125. [&](winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter) noexcept {
  126. eventDataWriter.WriteObjectBegin();
  127. {
  128. WriteProperty(eventDataWriter, L"data", message);
  129. }
  130. eventDataWriter.WriteObjectEnd();
  131. });
  132. }
  133. void ReactWebView::SetMessagingEnabled(bool enabled) {
  134. this->m_messagingEnabled = enabled;
  135. }
  136. } // namespace winrt::ReactNativeWebView::implementation