windows: added c++ nlohmann.json dependency, added getCopyBackForwardList implementation

This commit is contained in:
unknown 2024-01-17 01:23:08 +01:00
parent 914316e6d3
commit a8e960c4d0
10 changed files with 221 additions and 16 deletions

View File

@ -783,6 +783,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface
///- Android native WebView ([Official API - WebView.copyBackForwardList](https://developer.android.com/reference/android/webkit/WebView#copyBackForwardList())) ///- Android native WebView ([Official API - WebView.copyBackForwardList](https://developer.android.com/reference/android/webkit/WebView#copyBackForwardList()))
///- iOS ([Official API - WKWebView.backForwardList](https://developer.apple.com/documentation/webkit/wkwebview/1414977-backforwardlist)) ///- iOS ([Official API - WKWebView.backForwardList](https://developer.apple.com/documentation/webkit/wkwebview/1414977-backforwardlist))
///- MacOS ([Official API - WKWebView.backForwardList](https://developer.apple.com/documentation/webkit/wkwebview/1414977-backforwardlist)) ///- MacOS ([Official API - WKWebView.backForwardList](https://developer.apple.com/documentation/webkit/wkwebview/1414977-backforwardlist))
///- Windows
///{@endtemplate} ///{@endtemplate}
Future<WebHistory?> getCopyBackForwardList() { Future<WebHistory?> getCopyBackForwardList() {
throw UnimplementedError( throw UnimplementedError(

View File

@ -6,6 +6,7 @@ cmake_minimum_required(VERSION 3.14)
set(WIL_VERSION "1.0.231216.1") set(WIL_VERSION "1.0.231216.1")
set(WEBVIEW_VERSION "1.0.2210.55") set(WEBVIEW_VERSION "1.0.2210.55")
set(NLOHMANN_JSON "3.11.2")
message(VERBOSE "CMake system version is ${CMAKE_SYSTEM_VERSION} (using SDK ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION})") message(VERBOSE "CMake system version is ${CMAKE_SYSTEM_VERSION} (using SDK ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION})")
@ -31,6 +32,7 @@ add_custom_command(
TARGET ${PROJECT_NAME}_DEPENDENCIES_DOWNLOAD PRE_BUILD TARGET ${PROJECT_NAME}_DEPENDENCIES_DOWNLOAD PRE_BUILD
COMMAND ${NUGET} install Microsoft.Windows.ImplementationLibrary -Version ${WIL_VERSION} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages COMMAND ${NUGET} install Microsoft.Windows.ImplementationLibrary -Version ${WIL_VERSION} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages
COMMAND ${NUGET} install Microsoft.Web.WebView2 -Version ${WEBVIEW_VERSION} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages COMMAND ${NUGET} install Microsoft.Web.WebView2 -Version ${WEBVIEW_VERSION} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages
COMMAND ${NUGET} install nlohmann.json -Version ${NLOHMANN_JSON} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages
DEPENDS ${NUGET} DEPENDS ${NUGET}
) )
@ -54,6 +56,10 @@ list(APPEND PLUGIN_SOURCES
"types/web_resource_request.h" "types/web_resource_request.h"
"types/web_resource_response.cpp" "types/web_resource_response.cpp"
"types/web_resource_response.h" "types/web_resource_response.h"
"types/web_history.cpp"
"types/web_history.h"
"types/web_history_item.cpp"
"types/web_history_item.h"
"custom_platform_view/custom_platform_view.cc" "custom_platform_view/custom_platform_view.cc"
"custom_platform_view/custom_platform_view.h" "custom_platform_view/custom_platform_view.h"
"custom_platform_view/texture_bridge.cc" "custom_platform_view/texture_bridge.cc"
@ -123,6 +129,7 @@ apply_standard_settings(${PLUGIN_NAME})
target_link_libraries(${PLUGIN_NAME} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Web.WebView2/build/native/Microsoft.Web.WebView2.targets) target_link_libraries(${PLUGIN_NAME} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Web.WebView2/build/native/Microsoft.Web.WebView2.targets)
target_link_libraries(${PLUGIN_NAME} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Windows.ImplementationLibrary/build/native/Microsoft.Windows.ImplementationLibrary.targets) target_link_libraries(${PLUGIN_NAME} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Windows.ImplementationLibrary/build/native/Microsoft.Windows.ImplementationLibrary.targets)
target_link_libraries(${PLUGIN_NAME} PRIVATE ${CMAKE_BINARY_DIR}/packages/nlohmann.json/build/native/nlohmann.json.targets)
# Symbols are hidden by default to reduce the chance of accidental conflicts # Symbols are hidden by default to reduce the chance of accidental conflicts
# between plugins. This should not be removed; any symbols that should be # between plugins. This should not be removed; any symbols that should be

View File

@ -1,4 +1,5 @@
#include <cstring> #include <cstring>
#include <nlohmann/json.hpp>
#include <Shlwapi.h> #include <Shlwapi.h>
#include <WebView2EnvironmentOptions.h> #include <WebView2EnvironmentOptions.h>
#include <wil/wrl.h> #include <wil/wrl.h>
@ -21,11 +22,15 @@ namespace flutter_inappwebview_plugin
: plugin(plugin), id(params.id), webViewEnv(std::move(webViewEnv)), webViewController(std::move(webViewController)), webViewCompositionController(std::move(webViewCompositionController)), : plugin(plugin), id(params.id), webViewEnv(std::move(webViewEnv)), webViewController(std::move(webViewController)), webViewCompositionController(std::move(webViewCompositionController)),
settings(params.initialSettings) settings(params.initialSettings)
{ {
this->webViewController->get_CoreWebView2(webView.put()); auto hrWebView2 = this->webViewController->get_CoreWebView2(webView.put());
if (FAILED(hrWebView2)) {
std::cerr << "Cannot create CoreWebView2." << std::endl;
debugLog(getErrorMessage(hrWebView2));
}
if (this->webViewCompositionController) { if (this->webViewCompositionController) {
if (!createSurface(parentWindow, plugin->inAppWebViewManager->compositor())) { if (!createSurface(parentWindow, plugin->inAppWebViewManager->compositor())) {
std::cerr << "Cannot create InAppWebView surface\n"; std::cerr << "Cannot create InAppWebView surface." << std::endl;
} }
registerSurfaceEventHandlers(); registerSurfaceEventHandlers();
} }
@ -37,7 +42,8 @@ namespace flutter_inappwebview_plugin
} }
wil::com_ptr<ICoreWebView2Settings> webView2Settings; wil::com_ptr<ICoreWebView2Settings> webView2Settings;
if (SUCCEEDED(webView->get_Settings(&webView2Settings))) { auto hrWebView2Settings = webView->get_Settings(&webView2Settings);
if (SUCCEEDED(hrWebView2Settings)) {
webView2Settings->put_IsScriptEnabled(settings->javaScriptEnabled); webView2Settings->put_IsScriptEnabled(settings->javaScriptEnabled);
webView2Settings->put_IsZoomControlEnabled(settings->supportZoom); webView2Settings->put_IsZoomControlEnabled(settings->supportZoom);
@ -48,6 +54,9 @@ namespace flutter_inappwebview_plugin
} }
} }
} }
else {
debugLog(getErrorMessage(hrWebView2Settings));
}
registerEventHandlers(); registerEventHandlers();
} }
@ -182,7 +191,7 @@ namespace flutter_inappwebview_plugin
UINT64 navigationId; UINT64 navigationId;
if (SUCCEEDED(args->get_NavigationId(&navigationId))) { if (SUCCEEDED(args->get_NavigationId(&navigationId))) {
navigationActions.insert({ navigationId, navigationAction }); callShouldOverrideUrlLoading_ = navigationActions.insert({ navigationId, navigationAction });
} }
if (callShouldOverrideUrlLoading_ && requestMethod == nullptr) { if (callShouldOverrideUrlLoading_ && requestMethod == nullptr) {
@ -363,16 +372,55 @@ namespace flutter_inappwebview_plugin
webView->Reload(); webView->Reload();
} }
void InAppWebView::goBack() const void InAppWebView::goBack()
{ {
callShouldOverrideUrlLoading_ = false;
webView->GoBack(); webView->GoBack();
} }
void InAppWebView::goForward() const void InAppWebView::goForward()
{ {
callShouldOverrideUrlLoading_ = false;
webView->GoForward(); webView->GoForward();
} }
void InAppWebView::getCopyBackForwardList(const std::function<void(std::unique_ptr<WebHistory>)> completionHandler) const
{
webView->CallDevToolsProtocolMethod(L"Page.getNavigationHistory", L"{}", Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
[completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson)
{
if (errorCode == S_OK) {
auto historyJson = nlohmann::json::parse(wide_to_ansi(returnObjectAsJson));
int64_t currentIndex = historyJson.at("currentIndex").is_number_unsigned() ? historyJson.at("currentIndex").get<int64_t>() : 0;
auto entries = historyJson.at("entries").is_array() ? historyJson.at("entries").get<std::vector<nlohmann::json>>() : std::vector<nlohmann::json>{};
std::vector<std::shared_ptr<WebHistoryItem>> webHistoryItems;
webHistoryItems.reserve(entries.size());
int64_t i = 0;
for (auto const& entry : entries) {
int64_t offset = i - currentIndex;
webHistoryItems.push_back(std::make_shared<WebHistoryItem>(
i,
offset,
entry.at("userTypedURL").is_string() ? entry.at("userTypedURL").get<std::string>() : std::optional<std::string>{},
entry.at("title").is_string() ? entry.at("title").get<std::string>() : std::optional<std::string>{},
entry.at("url").is_string() ? entry.at("url").get<std::string>() : std::optional<std::string>{}
));
i++;
}
completionHandler(std::make_unique<WebHistory>(currentIndex, webHistoryItems));
}
else {
debugLog(getErrorMessage(errorCode));
}
return S_OK;
}
).Get());
}
void InAppWebView::evaluateJavascript(const std::string& source, std::function<void(std::string)> completionHanlder) const void InAppWebView::evaluateJavascript(const std::string& source, std::function<void(std::string)> completionHanlder) const
{ {
webView->ExecuteScript(ansi_to_wide(source).c_str(), webView->ExecuteScript(ansi_to_wide(source).c_str(),

View File

@ -11,6 +11,7 @@
#include "../flutter_inappwebview_windows_plugin.h" #include "../flutter_inappwebview_windows_plugin.h"
#include "../types/navigation_action.h" #include "../types/navigation_action.h"
#include "../types/url_request.h" #include "../types/url_request.h"
#include "../types/web_history.h"
#include "in_app_webview_settings.h" #include "in_app_webview_settings.h"
#include "webview_channel_delegate.h" #include "webview_channel_delegate.h"
@ -130,9 +131,10 @@ namespace flutter_inappwebview_plugin
std::optional<std::string> getTitle() const; std::optional<std::string> getTitle() const;
void loadUrl(const URLRequest& urlRequest) const; void loadUrl(const URLRequest& urlRequest) const;
void reload() const; void reload() const;
void goBack() const; void goBack();
void goForward() const; void goForward();
void evaluateJavascript(const std::string& source, std::function<void(std::string)> completionHanlder) const; void evaluateJavascript(const std::string& source, std::function<void(std::string)> completionHanlder) const;
void getCopyBackForwardList(const std::function<void(std::unique_ptr<WebHistory>)> completionHandler) const;
static bool isSslError(const COREWEBVIEW2_WEB_ERROR_STATUS& webErrorStatus); static bool isSslError(const COREWEBVIEW2_WEB_ERROR_STATUS& webErrorStatus);
private: private:

View File

@ -46,19 +46,19 @@ namespace flutter_inappwebview_plugin
else if (method_call.method_name().compare("loadUrl") == 0) { else if (method_call.method_name().compare("loadUrl") == 0) {
auto urlRequest = std::make_unique<URLRequest>(get_fl_map_value<flutter::EncodableMap>(arguments, "urlRequest")); auto urlRequest = std::make_unique<URLRequest>(get_fl_map_value<flutter::EncodableMap>(arguments, "urlRequest"));
webView->loadUrl(*urlRequest); webView->loadUrl(*urlRequest);
result->Success(make_fl_value(true)); result->Success(true);
} }
else if (method_call.method_name().compare("reload") == 0) { else if (method_call.method_name().compare("reload") == 0) {
webView->reload(); webView->reload();
result->Success(make_fl_value(true)); result->Success(true);
} }
else if (method_call.method_name().compare("goBack") == 0) { else if (method_call.method_name().compare("goBack") == 0) {
webView->goBack(); webView->goBack();
result->Success(make_fl_value(true)); result->Success(true);
} }
else if (method_call.method_name().compare("goForward") == 0) { else if (method_call.method_name().compare("goForward") == 0) {
webView->goForward(); webView->goForward();
result->Success(make_fl_value(true)); result->Success(true);
} }
else if (method_call.method_name().compare("evaluateJavascript") == 0) { else if (method_call.method_name().compare("evaluateJavascript") == 0) {
auto result_ = std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>>(std::move(result)); auto result_ = std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>>(std::move(result));
@ -66,21 +66,28 @@ namespace flutter_inappwebview_plugin
auto source = get_fl_map_value<std::string>(arguments, "source"); auto source = get_fl_map_value<std::string>(arguments, "source");
webView->evaluateJavascript(source, [result_ = std::move(result_)](const std::string& value) webView->evaluateJavascript(source, [result_ = std::move(result_)](const std::string& value)
{ {
result_->Success(make_fl_value(value)); result_->Success(value);
});
}
else if (method_call.method_name().compare("getCopyBackForwardList") == 0) {
auto result_ = std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>>(std::move(result));
webView->getCopyBackForwardList([result_ = std::move(result_)](const std::unique_ptr<WebHistory> value)
{
result_->Success(value->toEncodableMap());
}); });
} }
// for inAppBrowser // for inAppBrowser
else if (webView->inAppBrowser && method_call.method_name().compare("show") == 0) { else if (webView->inAppBrowser && method_call.method_name().compare("show") == 0) {
webView->inAppBrowser->show(); webView->inAppBrowser->show();
result->Success(make_fl_value(true)); result->Success(true);
} }
else if (webView->inAppBrowser && method_call.method_name().compare("hide") == 0) { else if (webView->inAppBrowser && method_call.method_name().compare("hide") == 0) {
webView->inAppBrowser->hide(); webView->inAppBrowser->hide();
result->Success(make_fl_value(true)); result->Success(true);
} }
else if (webView->inAppBrowser && method_call.method_name().compare("close") == 0) { else if (webView->inAppBrowser && method_call.method_name().compare("close") == 0) {
webView->inAppBrowser->close(); webView->inAppBrowser->close();
result->Success(make_fl_value(true)); result->Success(true);
} }
else { else {
result->NotImplemented(); result->NotImplemented();

View File

@ -0,0 +1,22 @@
#include "../utils/util.h"
#include "web_history.h"
namespace flutter_inappwebview_plugin
{
WebHistory::WebHistory(const std::optional<int64_t> currentIndex, const std::optional<std::vector<std::shared_ptr<WebHistoryItem>>>& list)
: currentIndex(currentIndex), list(list)
{}
WebHistory::WebHistory(const flutter::EncodableMap& map)
: currentIndex(get_optional_fl_map_value<int64_t>(map, "currentIndex")),
list(functional_map(get_optional_fl_map_value<flutter::EncodableList>(map, "list"), [](const flutter::EncodableValue& m) { return std::make_shared<WebHistoryItem>(std::get<flutter::EncodableMap>(m)); }))
{}
flutter::EncodableMap WebHistory::toEncodableMap() const
{
return flutter::EncodableMap{
{"currentIndex", make_fl_value(currentIndex)},
{"list", make_fl_value(functional_map(list, [](const std::shared_ptr<WebHistoryItem>& item) { return item->toEncodableMap(); }))}
};
}
}

View File

@ -0,0 +1,26 @@
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_HISTORY_H_
#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_HISTORY_H_
#include <flutter/standard_method_codec.h>
#include <optional>
#include "../utils/flutter.h"
#include "web_history_item.h"
namespace flutter_inappwebview_plugin
{
class WebHistory
{
public:
const std::optional<int64_t> currentIndex;
const std::optional<std::vector<std::shared_ptr<WebHistoryItem>>> list;
WebHistory(const std::optional<int64_t> currentIndex, const std::optional<std::vector<std::shared_ptr<WebHistoryItem>>>& list);
WebHistory(const flutter::EncodableMap& map);
~WebHistory() = default;
flutter::EncodableMap toEncodableMap() const;
};
}
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_HISTORY_H_

View File

@ -0,0 +1,29 @@
#include "web_history_item.h"
namespace flutter_inappwebview_plugin
{
WebHistoryItem::WebHistoryItem(const std::optional<int64_t>& index, const std::optional<int64_t>& offset,
const std::optional<std::string>& originalUrl, const std::optional<std::string>& title,
const std::optional<std::string>& url)
: index(index), offset(offset), originalUrl(originalUrl), title(title), url(url)
{}
WebHistoryItem::WebHistoryItem(const flutter::EncodableMap& map)
: index(get_optional_fl_map_value<int64_t>(map, "index")),
offset(get_optional_fl_map_value<int64_t>(map, "offset")),
originalUrl(get_optional_fl_map_value<std::string>(map, "originalUrl")),
title(get_optional_fl_map_value<std::string>(map, "title")),
url(get_optional_fl_map_value<std::string>(map, "url"))
{}
flutter::EncodableMap WebHistoryItem::toEncodableMap() const
{
return flutter::EncodableMap{
{"index", make_fl_value(index)},
{"offset", make_fl_value(offset)},
{"originalUrl", make_fl_value(originalUrl)},
{"title", make_fl_value(title)},
{"url", make_fl_value(url)}
};
}
}

View File

@ -0,0 +1,30 @@
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_HISTORY_ITEM_H_
#define FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_HISTORY_ITEM_H_
#include <flutter/standard_method_codec.h>
#include <optional>
#include "../utils/flutter.h"
namespace flutter_inappwebview_plugin
{
class WebHistoryItem
{
public:
const std::optional<int64_t> index;
const std::optional<int64_t> offset;
const std::optional<std::string> originalUrl;
const std::optional<std::string> title;
const std::optional<std::string> url;
WebHistoryItem(const std::optional<int64_t>& index, const std::optional<int64_t>& offset,
const std::optional<std::string>& originalUrl, const std::optional<std::string>& title,
const std::optional<std::string>& url);
WebHistoryItem(const flutter::EncodableMap& map);
~WebHistoryItem() = default;
flutter::EncodableMap toEncodableMap() const;
};
}
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_WEB_HISTORY_ITEM_H_

View File

@ -87,6 +87,39 @@ namespace flutter_inappwebview_plugin
auto itr = map.find(key); auto itr = map.find(key);
return itr != map.end() ? itr->second : nullptr; return itr != map.end() ? itr->second : nullptr;
} }
template <typename Iterator, typename Func>
static inline auto functional_map(Iterator begin, Iterator end, Func&& func) ->
std::vector<decltype(func(std::declval<typename Iterator::value_type>()))>
{
using value_type = decltype(func(std::declval<typename Iterator::value_type>()));
std::vector<value_type> out_vector;
out_vector.reserve(std::distance(begin, end));
std::transform(begin, end, std::back_inserter(out_vector),
std::forward<Func>(func));
return out_vector;
}
template <typename T, typename Func>
static inline auto functional_map(const T& iterable, Func&& func) ->
std::vector<decltype(func(std::declval<typename T::value_type>()))>
{
return functional_map(std::begin(iterable), std::end(iterable),
std::forward<Func>(func));
}
template <typename T, typename Func>
static inline auto functional_map(const std::optional<T>& iterable, Func&& func) ->
std::vector<decltype(func(std::declval<typename T::value_type>()))>
{
if (!iterable.has_value()) {
return {};
}
return functional_map(iterable.value(), std::forward<Func>(func));
}
} }
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_ #endif //FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_