#include "pch.h" #include "ReactWebViewManager.h" #include "NativeModules.h" namespace winrt { using namespace Microsoft::ReactNative; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; } namespace winrt::ReactNativeWebView::implementation { ReactWebViewManager::ReactWebViewManager() {} // IViewManager winrt::hstring ReactWebViewManager::Name() noexcept { return L"RCTWebView"; } winrt::FrameworkElement ReactWebViewManager::CreateView() noexcept { auto webView = winrt::WebView(); m_webView = winrt::make_weak(webView); RegisterEvents(); return webView; } void ReactWebViewManager::RegisterEvents() { if (auto webView = m_webView.get()) { m_navigationCompletedRevoker = webView.NavigationCompleted( winrt::auto_revoke, [=](auto const& sender, auto const& args) { OnNavigationCompleted(sender, args); }); } } // IViewManagerWithReactContext winrt::IReactContext ReactWebViewManager::ReactContext() noexcept { return m_reactContext; } void ReactWebViewManager::ReactContext(IReactContext reactContext) noexcept { m_reactContext = reactContext; } // IViewManagerWithNativeProperties IMapView ReactWebViewManager::NativeProps() noexcept { auto nativeProps = winrt::single_threaded_map(); nativeProps.Insert(L"source", ViewManagerPropertyType::Map); return nativeProps.GetView(); } void ReactWebViewManager::UpdateProperties( FrameworkElement const& view, IJSValueReader const& propertyMapReader) noexcept { if (auto webView = view.try_as()) { const JSValueObject& propertyMap = JSValue::ReadObjectFrom(propertyMapReader); for (auto const& pair : propertyMap) { auto const& propertyName = pair.first; auto const& propertyValue = pair.second; if (propertyName == "source") { if (!propertyValue.IsNull()) { auto const& srcMap = propertyValue.Object(); auto uriString = srcMap.at("uri").String(); // non-uri sources not yet supported if (uriString.length() == 0) { continue; } bool isPackagerAsset = false; if (srcMap.find("__packager_asset") != srcMap.end()) { isPackagerAsset = srcMap.at("__packager_asset").Boolean(); } if (isPackagerAsset && uriString.find("assets") == 0) { uriString.replace(0, 6, "ms-appx://"); } SetSource(winrt::Uri(to_hstring(uriString))); } } } } } void ReactWebViewManager::SetSource(winrt::Uri const& uri) { if (auto webView = m_webView.get()) { auto tag = webView.GetValue(winrt::FrameworkElement::TagProperty()).as().GetInt64(); m_reactContext.DispatchEvent( webView, L"topLoadingStart", [webView, tag, uri](winrt::IJSValueWriter const& eventDataWriter) noexcept { eventDataWriter.WriteObjectBegin(); { WriteProperty(eventDataWriter, L"canGoBack", webView.CanGoBack()); WriteProperty(eventDataWriter, L"canGoForward", webView.CanGoForward()); WriteProperty(eventDataWriter, L"loading", true); WriteProperty(eventDataWriter, L"target", tag); WriteProperty(eventDataWriter, L"title", webView.DocumentTitle()); WriteProperty(eventDataWriter, L"url", uri.ToString()); } eventDataWriter.WriteObjectEnd(); }); webView.Navigate(uri); } } // IViewManagerWithExportedEventTypeConstants ConstantProvider ReactWebViewManager::ExportedCustomBubblingEventTypeConstants() noexcept { return nullptr; } ConstantProvider ReactWebViewManager::ExportedCustomDirectEventTypeConstants() noexcept { return [](winrt::IJSValueWriter const& constantWriter) { WriteCustomDirectEventTypeConstant(constantWriter, "onLoadingStart"); WriteCustomDirectEventTypeConstant(constantWriter, "onLoad"); WriteCustomDirectEventTypeConstant(constantWriter, "onLoadingFinish"); }; } // IViewManagerWithCommands IMapView ReactWebViewManager::Commands() noexcept { auto commands = winrt::single_threaded_map(); commands.Insert(L"goForward", 0); commands.Insert(L"goBack", 1); commands.Insert(L"reload", 2); return commands.GetView(); } void ReactWebViewManager::DispatchCommand( FrameworkElement const& view, int64_t commandId, winrt::IJSValueReader const& commandArgsReader) noexcept { if (auto webView = view.try_as()) { switch (commandId) { case 0: // goForward webView.GoForward(); break; case 1: // goBack webView.GoBack(); break; case 2: // reload webView.Refresh(); break; } } } void ReactWebViewManager::OnNavigationCompleted(winrt::WebView const& webView, winrt::WebViewNavigationCompletedEventArgs const& args) { m_reactContext.DispatchEvent( webView, L"topLoadingFinish", [webView, args](winrt::IJSValueWriter const& eventDataWriter) noexcept { eventDataWriter.WriteObjectBegin(); { auto tag = webView.GetValue(winrt::FrameworkElement::TagProperty()).as().GetInt64(); WriteProperty(eventDataWriter, L"canGoBack", webView.CanGoBack()); WriteProperty(eventDataWriter, L"canGoForward", webView.CanGoForward()); WriteProperty(eventDataWriter, L"loading", false); WriteProperty(eventDataWriter, L"target", tag); WriteProperty(eventDataWriter, L"title", webView.DocumentTitle()); WriteProperty(eventDataWriter, L"url", args.Uri().ToString()); } eventDataWriter.WriteObjectEnd(); }); } } // namespace winrt::ReactWebView::implementation