windows: added content world support for user scripts and javascript evaluation
This commit is contained in:
parent
b27036e59b
commit
ed6283d3b3
|
@ -64,6 +64,8 @@ list(APPEND PLUGIN_SOURCES
|
|||
"types/web_history.h"
|
||||
"types/web_history_item.cpp"
|
||||
"types/web_history_item.h"
|
||||
"types/content_world.cpp"
|
||||
"types/content_world.h"
|
||||
"types/user_script.cpp"
|
||||
"types/user_script.h"
|
||||
"types/plugin_script.cpp"
|
||||
|
|
|
@ -190,7 +190,7 @@ namespace flutter_inappwebview_plugin
|
|||
void InAppBrowser::didChangeTitle(const std::optional<std::string>& title) const
|
||||
{
|
||||
if (title.has_value()) {
|
||||
SetWindowText(m_hWnd, ansi_to_wide(title.value()).c_str());
|
||||
SetWindowText(m_hWnd, utf8_to_wide(title.value()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace flutter_inappwebview_plugin
|
|||
auto url = get_fl_map_value<std::string>(*arguments, "url");
|
||||
|
||||
int status = static_cast<int>(reinterpret_cast<INT_PTR>(
|
||||
ShellExecute(nullptr, TEXT("open"), ansi_to_wide(url).c_str(),
|
||||
ShellExecute(nullptr, TEXT("open"), utf8_to_wide(url).c_str(),
|
||||
nullptr, nullptr, SW_SHOWNORMAL)));
|
||||
|
||||
// Anything >32 indicates success.
|
||||
|
|
|
@ -133,11 +133,40 @@ namespace flutter_inappwebview_plugin
|
|||
wil::com_ptr<ICoreWebView2Settings2> webView2Settings2;
|
||||
if (succeededOrLog(webView2Settings->QueryInterface(IID_PPV_ARGS(&webView2Settings2)))) {
|
||||
if (!settings->userAgent.empty()) {
|
||||
webView2Settings2->put_UserAgent(ansi_to_wide(settings->userAgent).c_str());
|
||||
webView2Settings2->put_UserAgent(utf8_to_wide(settings->userAgent).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// required to make Runtime events work
|
||||
failedLog(webView->CallDevToolsProtocolMethod(L"Runtime.enable", L"{}", Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
|
||||
[this](HRESULT errorCode, LPCWSTR returnObjectAsJson)
|
||||
{
|
||||
failedLog(errorCode);
|
||||
return S_OK;
|
||||
}
|
||||
).Get()));
|
||||
|
||||
// required to make Page events work and to add User Scripts
|
||||
failedLog(webView->CallDevToolsProtocolMethod(L"Page.enable", L"{}", Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
|
||||
[this](HRESULT errorCode, LPCWSTR returnObjectAsJson)
|
||||
{
|
||||
failedLog(errorCode);
|
||||
return S_OK;
|
||||
}
|
||||
).Get()));
|
||||
|
||||
failedLog(webView->CallDevToolsProtocolMethod(L"Page.getFrameTree", L"{}", Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
|
||||
[this](HRESULT errorCode, LPCWSTR returnObjectAsJson)
|
||||
{
|
||||
if (succeededOrLog(errorCode)) {
|
||||
auto treeJson = nlohmann::json::parse(wide_to_utf8(returnObjectAsJson));
|
||||
pageFrameId_ = treeJson["frameTree"]["frame"]["id"].get<std::string>();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
).Get()));
|
||||
|
||||
userContentController->addPluginScript(std::move(createJavaScriptBridgePluginScript()));
|
||||
|
||||
if (params.initialUserScripts.has_value()) {
|
||||
|
@ -241,7 +270,7 @@ namespace flutter_inappwebview_plugin
|
|||
|
||||
UINT64 navigationId;
|
||||
if (SUCCEEDED(args->get_NavigationId(&navigationId))) {
|
||||
navigationActions.insert({ navigationId, navigationAction });
|
||||
navigationActions_.insert({ navigationId, navigationAction });
|
||||
}
|
||||
|
||||
if (callShouldOverrideUrlLoading_ && requestMethod == nullptr) {
|
||||
|
@ -287,17 +316,14 @@ namespace flutter_inappwebview_plugin
|
|||
{
|
||||
isLoading_ = false;
|
||||
|
||||
if (userContentController) {
|
||||
evaluateJavascript(userContentController->generateWrappedCodeForDocumentEnd(), nullptr);
|
||||
}
|
||||
evaluateJavascript(PLATFORM_READY_JS_SOURCE, nullptr);
|
||||
evaluateJavascript(PLATFORM_READY_JS_SOURCE, ContentWorld::page(), nullptr);
|
||||
|
||||
std::shared_ptr<NavigationAction> navigationAction;
|
||||
UINT64 navigationId;
|
||||
if (SUCCEEDED(args->get_NavigationId(&navigationId))) {
|
||||
navigationAction = map_at_or_null(navigationActions, navigationId);
|
||||
navigationAction = map_at_or_null(navigationActions_, navigationId);
|
||||
if (navigationAction) {
|
||||
navigationActions.erase(navigationId);
|
||||
navigationActions_.erase(navigationId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,7 +364,7 @@ namespace flutter_inappwebview_plugin
|
|||
if (channelDelegate) {
|
||||
wil::unique_cotaskmem_string title;
|
||||
sender->get_DocumentTitle(&title);
|
||||
channelDelegate->onTitleChanged(title.is_valid() ? wide_to_ansi(title.get()) : std::optional<std::string>{});
|
||||
channelDelegate->onTitleChanged(title.is_valid() ? wide_to_utf8(title.get()) : std::optional<std::string>{});
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -379,7 +405,7 @@ namespace flutter_inappwebview_plugin
|
|||
|
||||
wil::unique_cotaskmem_string json;
|
||||
if (succeededOrLog(args->get_WebMessageAsJson(&json))) {
|
||||
auto message = nlohmann::json::parse(wide_to_ansi(json.get()));
|
||||
auto message = nlohmann::json::parse(wide_to_utf8(json.get()));
|
||||
|
||||
if (message.is_object() && message.contains("name") && message.at("name").is_string() && message.contains("body") && message.at("body").is_object()) {
|
||||
auto name = message.at("name").get<std::string>();
|
||||
|
@ -401,7 +427,7 @@ namespace flutter_inappwebview_plugin
|
|||
evaluateJavascript("if (window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "] != null) { \
|
||||
window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "].resolve(" + json + "); \
|
||||
delete window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "]; \
|
||||
}", nullptr);
|
||||
}", ContentWorld::page(), nullptr);
|
||||
};
|
||||
callback->error = [this, callHandlerID](const std::string& error_code, const std::string& error_message, const flutter::EncodableValue* error_details)
|
||||
{
|
||||
|
@ -411,7 +437,7 @@ namespace flutter_inappwebview_plugin
|
|||
evaluateJavascript("if (window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "] != null) { \
|
||||
window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "].reject(new Error('" + replace_all_copy(errorMessage, "\'", "\\'") + "')); \
|
||||
delete window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "]; \
|
||||
}", nullptr);
|
||||
}", ContentWorld::page(), nullptr);
|
||||
};
|
||||
channelDelegate->onCallJsHandler(handlerName, handlerArgs, std::move(callback));
|
||||
}
|
||||
|
@ -421,6 +447,55 @@ namespace flutter_inappwebview_plugin
|
|||
return S_OK;
|
||||
}
|
||||
).Get(), nullptr));
|
||||
|
||||
wil::com_ptr<ICoreWebView2DevToolsProtocolEventReceiver> consoleMessageReceiver;
|
||||
if (succeededOrLog(webView->GetDevToolsProtocolEventReceiver(L"Runtime.consoleAPICalled", &consoleMessageReceiver))) {
|
||||
failedLog(consoleMessageReceiver->add_DevToolsProtocolEventReceived(
|
||||
Callback<ICoreWebView2DevToolsProtocolEventReceivedEventHandler>(
|
||||
[this](
|
||||
ICoreWebView2* sender,
|
||||
ICoreWebView2DevToolsProtocolEventReceivedEventArgs* args) -> HRESULT
|
||||
{
|
||||
|
||||
if (!channelDelegate) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
wil::unique_cotaskmem_string json;
|
||||
if (succeededOrLog(args->get_ParameterObjectAsJson(&json))) {
|
||||
auto consoleMessageJson = nlohmann::json::parse(wide_to_utf8(json.get()));
|
||||
|
||||
auto level = consoleMessageJson.at("type").get<std::string>();
|
||||
int64_t messageLevel = 1;
|
||||
if (string_equals(level, "log")) {
|
||||
messageLevel = 1;
|
||||
}
|
||||
else if (string_equals(level, "debug")) {
|
||||
messageLevel = 0;
|
||||
}
|
||||
else if (string_equals(level, "error")) {
|
||||
messageLevel = 3;
|
||||
}
|
||||
else if (string_equals(level, "info")) {
|
||||
messageLevel = 1;
|
||||
}
|
||||
else if (string_equals(level, "warn")) {
|
||||
messageLevel = 2;
|
||||
}
|
||||
|
||||
auto consoleArgs = consoleMessageJson.at("args").get<std::vector<nlohmann::json>>();
|
||||
auto message = join(functional_map(consoleArgs, [](const nlohmann::json& json) { return json.contains("value") ? json.at("value").dump() : (json.contains("description") ? json.at("description").dump() : json.dump()); }), std::string{ " " });
|
||||
channelDelegate->onConsoleMessage(message, messageLevel);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
})
|
||||
.Get(), nullptr));
|
||||
}
|
||||
|
||||
if (userContentController) {
|
||||
userContentController->registerEventHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
void InAppWebView::registerSurfaceEventHandlers()
|
||||
|
@ -462,13 +537,13 @@ namespace flutter_inappwebview_plugin
|
|||
return;
|
||||
}
|
||||
|
||||
std::wstring url = ansi_to_wide(urlRequest->url.value());
|
||||
std::wstring url = utf8_to_wide(urlRequest->url.value());
|
||||
|
||||
wil::com_ptr<ICoreWebView2Environment2> webViewEnv2;
|
||||
wil::com_ptr<ICoreWebView2_2> webView2;
|
||||
if (SUCCEEDED(webViewEnv->QueryInterface(IID_PPV_ARGS(&webViewEnv2))) && SUCCEEDED(webView->QueryInterface(IID_PPV_ARGS(&webView2)))) {
|
||||
wil::com_ptr<ICoreWebView2WebResourceRequest> webResourceRequest;
|
||||
std::wstring method = urlRequest->method.has_value() ? ansi_to_wide(urlRequest->method.value()) : L"GET";
|
||||
std::wstring method = urlRequest->method.has_value() ? utf8_to_wide(urlRequest->method.value()) : L"GET";
|
||||
|
||||
wil::com_ptr<IStream> postDataStream = nullptr;
|
||||
if (urlRequest->body.has_value()) {
|
||||
|
@ -491,7 +566,7 @@ namespace flutter_inappwebview_plugin
|
|||
if (urlRequest->headers.has_value()) {
|
||||
auto& headers = urlRequest->headers.value();
|
||||
for (auto const& [key, val] : headers) {
|
||||
requestHeaders->SetHeader(ansi_to_wide(key).c_str(), ansi_to_wide(val).c_str());
|
||||
requestHeaders->SetHeader(utf8_to_wide(key).c_str(), utf8_to_wide(val).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -530,7 +605,7 @@ namespace flutter_inappwebview_plugin
|
|||
return;
|
||||
}
|
||||
|
||||
failedLog(webView->NavigateToString(ansi_to_wide(data).c_str()));
|
||||
failedLog(webView->NavigateToString(utf8_to_wide(data).c_str()));
|
||||
}
|
||||
|
||||
void InAppWebView::reload() const
|
||||
|
@ -590,7 +665,7 @@ namespace flutter_inappwebview_plugin
|
|||
if (entryId.has_value()) {
|
||||
auto oldCallShouldOverrideUrlLoading_ = callShouldOverrideUrlLoading_;
|
||||
callShouldOverrideUrlLoading_ = false;
|
||||
if (failedAndLog(webView->CallDevToolsProtocolMethod(L"Page.navigateToHistoryEntry", ansi_to_wide("{\"entryId\": " + std::to_string(entryId.value()) + "}").c_str(), Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
|
||||
if (failedAndLog(webView->CallDevToolsProtocolMethod(L"Page.navigateToHistoryEntry", utf8_to_wide("{\"entryId\": " + std::to_string(entryId.value()) + "}").c_str(), Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
|
||||
[this](HRESULT errorCode, LPCWSTR returnObjectAsJson)
|
||||
{
|
||||
failedLog(errorCode);
|
||||
|
@ -653,7 +728,7 @@ namespace flutter_inappwebview_plugin
|
|||
}
|
||||
|
||||
if (errorCode == S_OK) {
|
||||
auto historyJson = nlohmann::json::parse(wide_to_ansi(returnObjectAsJson));
|
||||
auto historyJson = nlohmann::json::parse(wide_to_utf8(returnObjectAsJson));
|
||||
|
||||
int64_t currentIndex = historyJson.at("currentIndex").is_number_unsigned() ? historyJson.at("currentIndex").get<int64_t>() : 0;
|
||||
std::vector<nlohmann::json> entries = historyJson.at("entries").is_array() ? historyJson.at("entries").get<std::vector<nlohmann::json>>() : std::vector<nlohmann::json>{};
|
||||
|
@ -686,22 +761,44 @@ namespace flutter_inappwebview_plugin
|
|||
).Get()));
|
||||
}
|
||||
|
||||
void InAppWebView::evaluateJavascript(const std::string& source, const std::function<void(std::string)> completionHanlder) const
|
||||
void InAppWebView::evaluateJavascript(const std::string& source, const std::shared_ptr<ContentWorld> contentWorld, const std::function<void(std::string)> completionHandler) const
|
||||
{
|
||||
failedLog(webView->ExecuteScript(ansi_to_wide(source).c_str(),
|
||||
Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
|
||||
[completionHanlder = std::move(completionHanlder)](HRESULT error, PCWSTR result) -> HRESULT
|
||||
{
|
||||
if (error != S_OK) {
|
||||
debugLog(error);
|
||||
}
|
||||
if (!webView || !userContentController) {
|
||||
if (completionHandler) {
|
||||
completionHandler("null");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (completionHanlder) {
|
||||
completionHanlder(wide_to_ansi(result));
|
||||
}
|
||||
userContentController->createContentWorld(contentWorld,
|
||||
[=](const int& contextId)
|
||||
{
|
||||
nlohmann::json parameters = {
|
||||
{"expression", source}
|
||||
};
|
||||
|
||||
return S_OK;
|
||||
}).Get()));
|
||||
if (contextId >= 0) {
|
||||
parameters["contextId"] = contextId;
|
||||
}
|
||||
|
||||
auto hr = webView->CallDevToolsProtocolMethod(L"Runtime.evaluate", utf8_to_wide(parameters.dump()).c_str(), Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
|
||||
[this, completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson)
|
||||
{
|
||||
std::string result = "null";
|
||||
if (succeededOrLog(errorCode)) {
|
||||
result = wide_to_utf8(returnObjectAsJson);
|
||||
}
|
||||
if (completionHandler) {
|
||||
completionHandler(result);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
).Get());
|
||||
|
||||
if (failedAndLog(hr) && completionHandler) {
|
||||
completionHandler("null");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void InAppWebView::addUserScript(const std::shared_ptr<UserScript> userScript) const
|
||||
|
@ -964,10 +1061,10 @@ namespace flutter_inappwebview_plugin
|
|||
return handled; \
|
||||
})(" + std::to_string(horizontal) + ", " + std::to_string(offset) + ", " + std::to_string(lastCursorPos_.x) + ", " + std::to_string(lastCursorPos_.y) + ");";
|
||||
|
||||
webView->ExecuteScript(ansi_to_wide(workaroundScrollJS).c_str(), Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
|
||||
webView->ExecuteScript(utf8_to_wide(workaroundScrollJS).c_str(), Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
|
||||
[this, horizontal, offset](HRESULT error, PCWSTR result) -> HRESULT
|
||||
{
|
||||
if (webViewCompositionController && (error != S_OK || wide_to_ansi(result).compare("false") == 0)) {
|
||||
if (webViewCompositionController && (error != S_OK || wide_to_utf8(result).compare("false") == 0)) {
|
||||
// try to use native mouse wheel handler
|
||||
|
||||
POINT point;
|
||||
|
@ -1057,7 +1154,7 @@ namespace flutter_inappwebview_plugin
|
|||
if (webViewController) {
|
||||
webViewController->Close();
|
||||
}
|
||||
navigationActions.clear();
|
||||
navigationActions_.clear();
|
||||
inAppBrowser = nullptr;
|
||||
plugin = nullptr;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <winrt/base.h>
|
||||
|
||||
#include "../flutter_inappwebview_windows_plugin.h"
|
||||
#include "../types/content_world.h"
|
||||
#include "../types/navigation_action.h"
|
||||
#include "../types/url_request.h"
|
||||
#include "../types/web_history.h"
|
||||
|
@ -87,7 +88,6 @@ namespace flutter_inappwebview_plugin
|
|||
wil::com_ptr<ICoreWebView2CompositionController> webViewCompositionController;
|
||||
wil::com_ptr<ICoreWebView2> webView;
|
||||
std::unique_ptr<WebViewChannelDelegate> channelDelegate;
|
||||
std::map<UINT64, std::shared_ptr<NavigationAction>> navigationActions = {};
|
||||
const std::shared_ptr<InAppWebViewSettings> settings;
|
||||
InAppBrowser* inAppBrowser = nullptr;
|
||||
std::unique_ptr<UserContentController> userContentController;
|
||||
|
@ -148,13 +148,18 @@ namespace flutter_inappwebview_plugin
|
|||
return isLoading_;
|
||||
}
|
||||
void stopLoading() const;
|
||||
void evaluateJavascript(const std::string& source, const std::function<void(std::string)> completionHanlder) const;
|
||||
void evaluateJavascript(const std::string& source, const std::shared_ptr<ContentWorld> contentWorld, const std::function<void(std::string)> completionHandler) const;
|
||||
void getCopyBackForwardList(const std::function<void(std::unique_ptr<WebHistory>)> completionHandler) const;
|
||||
void addUserScript(const std::shared_ptr<UserScript> userScript) const;
|
||||
void removeUserScript(const int64_t index, const std::shared_ptr<UserScript> userScript) const;
|
||||
void removeUserScriptsByGroupName(const std::string& groupName) const;
|
||||
void removeAllUserScripts() const;
|
||||
|
||||
std::string pageFrameId() const
|
||||
{
|
||||
return pageFrameId_;
|
||||
}
|
||||
|
||||
static bool isSslError(const COREWEBVIEW2_WEB_ERROR_STATUS& webErrorStatus);
|
||||
private:
|
||||
// custom_platform_view
|
||||
|
@ -166,11 +171,13 @@ namespace flutter_inappwebview_plugin
|
|||
VirtualKeyState virtualKeys_;
|
||||
|
||||
bool callShouldOverrideUrlLoading_ = true;
|
||||
std::map<UINT64, std::shared_ptr<NavigationAction>> navigationActions_ = {};
|
||||
std::shared_ptr<NavigationAction> lastNavigationAction_;
|
||||
bool isLoading_ = false;
|
||||
std::string pageFrameId_;
|
||||
|
||||
void InAppWebView::registerEventHandlers();
|
||||
void InAppWebView::registerSurfaceEventHandlers();
|
||||
void registerEventHandlers();
|
||||
void registerSurfaceEventHandlers();
|
||||
};
|
||||
}
|
||||
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_WEBVIEW_H_
|
|
@ -1,3 +1,4 @@
|
|||
#include <nlohmann/json.hpp>
|
||||
#include <wil/wrl.h>
|
||||
|
||||
#include "../utils/log.h"
|
||||
|
@ -14,6 +15,67 @@ namespace flutter_inappwebview_plugin
|
|||
: webView_(webView)
|
||||
{}
|
||||
|
||||
void UserContentController::registerEventHandlers()
|
||||
{
|
||||
if (!webView_ || !(webView_->webView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
wil::com_ptr<ICoreWebView2DevToolsProtocolEventReceiver> executionContextCreated;
|
||||
if (succeededOrLog(webView_->webView->GetDevToolsProtocolEventReceiver(L"Runtime.executionContextCreated", &executionContextCreated))) {
|
||||
auto hr = executionContextCreated->add_DevToolsProtocolEventReceived(
|
||||
Callback<ICoreWebView2DevToolsProtocolEventReceivedEventHandler>(
|
||||
[this](
|
||||
ICoreWebView2* sender,
|
||||
ICoreWebView2DevToolsProtocolEventReceivedEventArgs* args) -> HRESULT
|
||||
{
|
||||
wil::unique_cotaskmem_string json;
|
||||
if (succeededOrLog(args->get_ParameterObjectAsJson(&json))) {
|
||||
nlohmann::json context = nlohmann::json::parse(wide_to_utf8(json.get()))["context"];
|
||||
auto id = context["id"].get<int>();
|
||||
auto name = context["name"].get<std::string>();
|
||||
nlohmann::json auxData = context["auxData"];
|
||||
auto isDefault = auxData["isDefault"].get<bool>();
|
||||
auto frameId = auxData["frameId"].get<std::string>();
|
||||
if (string_equals(webView_->pageFrameId(), frameId)) {
|
||||
if (isDefault) {
|
||||
contentWorlds_.insert_or_assign(ContentWorld::page()->name, id);
|
||||
}
|
||||
else {
|
||||
contentWorlds_.insert_or_assign(name, id);
|
||||
addPluginScriptsIfRequired(std::make_shared<ContentWorld>(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
})
|
||||
.Get(), nullptr);
|
||||
|
||||
failedLog(hr);
|
||||
}
|
||||
|
||||
/*
|
||||
wil::com_ptr<ICoreWebView2DevToolsProtocolEventReceiver> executionContextDestroyed;
|
||||
if (succeededOrLog(webView_->webView->GetDevToolsProtocolEventReceiver(L"Runtime.executionContextDestroyed ", &executionContextDestroyed))) {
|
||||
failedLog(executionContextDestroyed->add_DevToolsProtocolEventReceived(
|
||||
Callback<ICoreWebView2DevToolsProtocolEventReceivedEventHandler>(
|
||||
[this](
|
||||
ICoreWebView2* sender,
|
||||
ICoreWebView2DevToolsProtocolEventReceivedEventArgs* args) -> HRESULT
|
||||
{
|
||||
wil::unique_cotaskmem_string json;
|
||||
if (succeededOrLog(args->get_ParameterObjectAsJson(&json))) {
|
||||
debugLog("executionContextDestroyed: " + wide_to_utf8(json.get()));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
})
|
||||
.Get(), nullptr));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<UserScript>> UserContentController::getUserOnlyScriptsAt(const UserScriptInjectionTime& injectionTime) const
|
||||
{
|
||||
return userOnlyScripts_.at(injectionTime);
|
||||
|
@ -25,18 +87,8 @@ namespace flutter_inappwebview_plugin
|
|||
return;
|
||||
}
|
||||
|
||||
if (userScript->injectionTime == UserScriptInjectionTime::atDocumentStart && webView_) {
|
||||
failedLog(webView_->webView->AddScriptToExecuteOnDocumentCreated(ansi_to_wide(userScript->source).c_str(),
|
||||
Callback<ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler>(
|
||||
[userScript](HRESULT error, PCWSTR id) -> HRESULT
|
||||
{
|
||||
if (succeededOrLog(error)) {
|
||||
userScript->id = id;
|
||||
}
|
||||
return S_OK;
|
||||
}).Get()));
|
||||
}
|
||||
|
||||
addPluginScriptsIfRequired(userScript->contentWorld);
|
||||
addScriptToWebView(userScript, nullptr);
|
||||
userOnlyScripts_.at(userScript->injectionTime).push_back(std::move(userScript));
|
||||
}
|
||||
|
||||
|
@ -54,7 +106,7 @@ namespace flutter_inappwebview_plugin
|
|||
}
|
||||
|
||||
if (webView_) {
|
||||
failedLog(webView_->webView->RemoveScriptToExecuteOnDocumentCreated(userScript->id.c_str()));
|
||||
removeScriptFromWebView(userScript, nullptr);
|
||||
}
|
||||
|
||||
vector_remove_erase(userOnlyScripts_.at(userScript->injectionTime), std::move(userScript));
|
||||
|
@ -70,9 +122,7 @@ namespace flutter_inappwebview_plugin
|
|||
|
||||
auto& userScript = vec.at(index);
|
||||
if (userScript) {
|
||||
if (webView_) {
|
||||
failedLog(webView_->webView->RemoveScriptToExecuteOnDocumentCreated(userScript->id.c_str()));
|
||||
}
|
||||
removeScriptFromWebView(userScript, nullptr);
|
||||
vec.erase(vec.begin() + index);
|
||||
}
|
||||
}
|
||||
|
@ -84,10 +134,10 @@ namespace flutter_inappwebview_plugin
|
|||
|
||||
if (webView_) {
|
||||
for (auto& userScript : userScriptsAtStart) {
|
||||
failedLog(webView_->webView->RemoveScriptToExecuteOnDocumentCreated(userScript->id.c_str()));
|
||||
removeScriptFromWebView(userScript, nullptr);
|
||||
}
|
||||
for (auto& userScript : userScriptsAtEnd) {
|
||||
failedLog(webView_->webView->RemoveScriptToExecuteOnDocumentCreated(userScript->id.c_str()));
|
||||
removeScriptFromWebView(userScript, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,18 +189,7 @@ namespace flutter_inappwebview_plugin
|
|||
return;
|
||||
}
|
||||
|
||||
if (pluginScript->injectionTime == UserScriptInjectionTime::atDocumentStart && webView_) {
|
||||
failedLog(webView_->webView->AddScriptToExecuteOnDocumentCreated(ansi_to_wide(pluginScript->source).c_str(),
|
||||
Callback<ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler>(
|
||||
[pluginScript](HRESULT error, PCWSTR id) -> HRESULT
|
||||
{
|
||||
if (succeededOrLog(error)) {
|
||||
pluginScript->id = id;
|
||||
}
|
||||
return S_OK;
|
||||
}).Get()));
|
||||
}
|
||||
|
||||
addScriptToWebView(pluginScript, nullptr);
|
||||
pluginScripts_.at(pluginScript->injectionTime).push_back(std::move(pluginScript));
|
||||
}
|
||||
|
||||
|
@ -168,7 +207,7 @@ namespace flutter_inappwebview_plugin
|
|||
}
|
||||
|
||||
if (webView_) {
|
||||
failedLog(webView_->webView->RemoveScriptToExecuteOnDocumentCreated(pluginScript->id.c_str()));
|
||||
removeScriptFromWebView(pluginScript, nullptr);
|
||||
}
|
||||
|
||||
vector_remove_erase(pluginScripts_.at(pluginScript->injectionTime), std::move(pluginScript));
|
||||
|
@ -181,10 +220,10 @@ namespace flutter_inappwebview_plugin
|
|||
|
||||
if (webView_) {
|
||||
for (auto& pluginScript : pluginScriptsAtStart) {
|
||||
failedLog(webView_->webView->RemoveScriptToExecuteOnDocumentCreated(pluginScript->id.c_str()));
|
||||
removeScriptFromWebView(pluginScript, nullptr);
|
||||
}
|
||||
for (auto& pluginScript : pluginScriptsAtEnd) {
|
||||
failedLog(webView_->webView->RemoveScriptToExecuteOnDocumentCreated(pluginScript->id.c_str()));
|
||||
removeScriptFromWebView(pluginScript, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,7 +237,18 @@ namespace flutter_inappwebview_plugin
|
|||
return false;
|
||||
}
|
||||
|
||||
return vector_contains(pluginScripts_.at(pluginScript->injectionTime), std::move(pluginScript));
|
||||
auto injectionTime = pluginScript->injectionTime;
|
||||
return vector_contains(pluginScripts_.at(injectionTime), std::move(pluginScript));
|
||||
}
|
||||
|
||||
|
||||
bool UserContentController::containsPluginScript(std::shared_ptr<PluginScript> pluginScript, const std::shared_ptr<ContentWorld> contentWorld) const
|
||||
{
|
||||
if (!pluginScript || !map_contains(pluginScriptsInContentWorlds_, contentWorld->name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return vector_contains(pluginScriptsInContentWorlds_.at(contentWorld->name), std::move(pluginScript));
|
||||
}
|
||||
|
||||
bool UserContentController::containsPluginScriptByGroupName(const std::string& groupName) const
|
||||
|
@ -225,31 +275,150 @@ namespace flutter_inappwebview_plugin
|
|||
}
|
||||
}
|
||||
|
||||
std::string UserContentController::generatePluginScriptsCodeAt(const UserScriptInjectionTime& injectionTime) const
|
||||
|
||||
std::vector<std::shared_ptr<PluginScript>> UserContentController::getPluginScriptsRequiredInAllContentWorlds() const
|
||||
{
|
||||
std::string code;
|
||||
std::vector<std::shared_ptr<PluginScript>> pluginScripts = pluginScripts_.at(injectionTime);
|
||||
for (auto& pluginScript : pluginScripts) {
|
||||
code += ";" + pluginScript->source;
|
||||
std::vector<std::shared_ptr<PluginScript>> res;
|
||||
|
||||
std::vector<std::shared_ptr<PluginScript>> pluginScriptsAtStart = pluginScripts_.at(UserScriptInjectionTime::atDocumentStart);
|
||||
std::vector<std::shared_ptr<PluginScript>> pluginScriptsAtEnd = pluginScripts_.at(UserScriptInjectionTime::atDocumentEnd);
|
||||
|
||||
for (auto& pluginScript : pluginScriptsAtStart) {
|
||||
if (!pluginScript->contentWorld && pluginScript->isRequiredInAllContentWorlds()) {
|
||||
res.push_back(pluginScript);
|
||||
}
|
||||
}
|
||||
return code;
|
||||
|
||||
for (auto& pluginScript : pluginScriptsAtEnd) {
|
||||
if (!pluginScript->contentWorld && pluginScript->isRequiredInAllContentWorlds()) {
|
||||
res.push_back(pluginScript);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string UserContentController::generateUserOnlyScriptsCodeAt(const UserScriptInjectionTime& injectionTime) const
|
||||
void UserContentController::createContentWorld(const std::shared_ptr<ContentWorld> contentWorld, const std::function<void(int)> completionHandler)
|
||||
{
|
||||
std::string code;
|
||||
std::vector<std::shared_ptr<UserScript>> userScripts = userOnlyScripts_.at(injectionTime);
|
||||
for (auto& userScript : userScripts) {
|
||||
code += ";" + userScript->source;
|
||||
if (!webView_ || !(webView_->webView) || ContentWorld::isPage(contentWorld)) {
|
||||
if (completionHandler) {
|
||||
completionHandler(-1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto& worldName = contentWorld->name;
|
||||
if (!map_contains(contentWorlds_, worldName)) {
|
||||
nlohmann::json parameters = {
|
||||
{"frameId", webView_->pageFrameId()},
|
||||
{"worldName", worldName}
|
||||
};
|
||||
auto hr = webView_->webView->CallDevToolsProtocolMethod(L"Page.createIsolatedWorld", utf8_to_wide(parameters.dump()).c_str(), Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
|
||||
[this, completionHandler, worldName](HRESULT errorCode, LPCWSTR returnObjectAsJson)
|
||||
{
|
||||
if (succeededOrLog(errorCode) && completionHandler) {
|
||||
auto id = nlohmann::json::parse(wide_to_utf8(returnObjectAsJson))["executionContextId"].get<int>();
|
||||
addPluginScriptsIfRequired(std::make_shared<ContentWorld>(worldName));
|
||||
completionHandler(id);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
).Get());
|
||||
if (failedAndLog(hr) && completionHandler) {
|
||||
completionHandler(-1);
|
||||
}
|
||||
}
|
||||
else if (completionHandler) {
|
||||
completionHandler(contentWorlds_.at(worldName));
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
std::string UserContentController::generateWrappedCodeForDocumentEnd() const
|
||||
void UserContentController::addScriptToWebView(std::shared_ptr<UserScript> userScript, const std::function<void(std::string)> completionHandler) const
|
||||
{
|
||||
std::string code = generatePluginScriptsCodeAt(UserScriptInjectionTime::atDocumentEnd);
|
||||
code += generateUserOnlyScriptsCodeAt(UserScriptInjectionTime::atDocumentEnd);
|
||||
return replace_all_copy(USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE, VAR_PLACEHOLDER_VALUE, code);
|
||||
if (!webView_ || !(webView_->webView)) {
|
||||
if (completionHandler) {
|
||||
completionHandler(userScript->id);
|
||||
}
|
||||
}
|
||||
|
||||
std::string source = userScript->source;
|
||||
if (userScript->injectionTime == UserScriptInjectionTime::atDocumentEnd) {
|
||||
source = replace_all_copy(USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE, VAR_PLACEHOLDER_VALUE, source);
|
||||
std::ostringstream address;
|
||||
address << std::addressof(userScript);
|
||||
replace_all(source, VAR_PLACEHOLDER_MEMORY_ADDRESS_VALUE, address.str());
|
||||
}
|
||||
|
||||
nlohmann::json parameters = {
|
||||
{"source", source}
|
||||
};
|
||||
|
||||
if (userScript->contentWorld && !ContentWorld::isPage(userScript->contentWorld)) {
|
||||
parameters["worldName"] = userScript->contentWorld->name;
|
||||
}
|
||||
|
||||
auto hr = webView_->webView->CallDevToolsProtocolMethod(L"Page.addScriptToEvaluateOnNewDocument", utf8_to_wide(parameters.dump()).c_str(), Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
|
||||
[userScript, completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson)
|
||||
{
|
||||
if (succeededOrLog(errorCode)) {
|
||||
nlohmann::json json = nlohmann::json::parse(wide_to_utf8(returnObjectAsJson));
|
||||
userScript->id = json["identifier"].get<std::string>();
|
||||
}
|
||||
if (completionHandler) {
|
||||
completionHandler(userScript->id);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
).Get());
|
||||
|
||||
if (failedAndLog(hr) && completionHandler) {
|
||||
completionHandler(userScript->id);
|
||||
}
|
||||
}
|
||||
|
||||
void UserContentController::removeScriptFromWebView(std::shared_ptr<UserScript> userScript, const std::function<void()> completionHandler) const
|
||||
{
|
||||
if (!webView_ || !(webView_->webView)) {
|
||||
if (completionHandler) {
|
||||
completionHandler();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nlohmann::json parameters = {
|
||||
{"identifier", userScript->id}
|
||||
};
|
||||
|
||||
auto hr = webView_->webView->CallDevToolsProtocolMethod(L"Page.removeScriptToEvaluateOnNewDocument", utf8_to_wide(parameters.dump()).c_str(), Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
|
||||
[userScript, completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson)
|
||||
{
|
||||
failedLog(errorCode);
|
||||
if (completionHandler) {
|
||||
completionHandler();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
).Get());
|
||||
|
||||
if (failedAndLog(hr) && completionHandler) {
|
||||
completionHandler();
|
||||
}
|
||||
}
|
||||
|
||||
void UserContentController::addPluginScriptsIfRequired(const std::shared_ptr<ContentWorld> contentWorld)
|
||||
{
|
||||
if (contentWorld && !ContentWorld::isPage(contentWorld)) {
|
||||
std::vector<std::shared_ptr<PluginScript>> pluginScriptsRequiredInAllContentWorlds = getPluginScriptsRequiredInAllContentWorlds();
|
||||
for (auto& pluginScript : pluginScriptsRequiredInAllContentWorlds) {
|
||||
if (!containsPluginScript(pluginScript, contentWorld)) {
|
||||
if (!map_contains(pluginScriptsInContentWorlds_, contentWorld->name)) {
|
||||
pluginScriptsInContentWorlds_.insert({ contentWorld->name, {} });
|
||||
}
|
||||
pluginScriptsInContentWorlds_.at(contentWorld->name).push_back(pluginScript);
|
||||
addPluginScript(pluginScript->copyAndSet(contentWorld));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UserContentController::~UserContentController()
|
||||
|
@ -257,6 +426,8 @@ namespace flutter_inappwebview_plugin
|
|||
debugLog("dealloc UserContentController");
|
||||
removeAllUserOnlyScripts();
|
||||
removeAllPluginScripts();
|
||||
contentWorlds_.clear();
|
||||
pluginScriptsInContentWorlds_.clear();
|
||||
webView_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_USER_CONTENT_CONTROLLER_H_
|
||||
#define FLUTTER_INAPPWEBVIEW_PLUGIN_USER_CONTENT_CONTROLLER_H_
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "../plugin_scripts_js/javascript_bridge_js.h"
|
||||
#include "../plugin_scripts_js/plugin_scripts_util.h"
|
||||
#include "../types/content_world.h"
|
||||
#include "../types/plugin_script.h"
|
||||
#include "../types/user_script.h"
|
||||
|
||||
|
@ -13,11 +15,12 @@ namespace flutter_inappwebview_plugin
|
|||
{
|
||||
class InAppWebView;
|
||||
|
||||
const std::string USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE =
|
||||
"if (window." + JAVASCRIPT_BRIDGE_NAME + " != null && (window." + JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentEndLoaded == null || !window." + JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentEndLoaded)) { \
|
||||
window." + JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentEndLoaded = true; \
|
||||
const std::string USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE = "window.addEventListener('load', () => { \
|
||||
if (window." + JAVASCRIPT_BRIDGE_NAME + " != null && (window." + JAVASCRIPT_BRIDGE_NAME + "._userScript" + VAR_PLACEHOLDER_MEMORY_ADDRESS_VALUE + "AtDocumentEndLoaded == null || !window." + JAVASCRIPT_BRIDGE_NAME + "._userScript" + VAR_PLACEHOLDER_MEMORY_ADDRESS_VALUE + "AtDocumentEndLoaded)) { \
|
||||
window." + JAVASCRIPT_BRIDGE_NAME + "._userScript" + VAR_PLACEHOLDER_MEMORY_ADDRESS_VALUE + "AtDocumentEndLoaded = true; \
|
||||
" + VAR_PLACEHOLDER_VALUE + " \
|
||||
}";
|
||||
} \
|
||||
});";
|
||||
|
||||
class UserContentController
|
||||
{
|
||||
|
@ -34,20 +37,28 @@ namespace flutter_inappwebview_plugin
|
|||
bool containsUserOnlyScript(std::shared_ptr<UserScript> userScript) const;
|
||||
bool containsUserOnlyScriptByGroupName(const std::string& groupName) const;
|
||||
void removeUserOnlyScriptsByGroupName(const std::string& groupName);
|
||||
|
||||
std::vector<std::shared_ptr<PluginScript>> getPluginScriptsAt(const UserScriptInjectionTime& injectionTime) const;
|
||||
void addPluginScript(std::shared_ptr<PluginScript> pluginScript);
|
||||
void addPluginScripts(std::vector<std::shared_ptr<PluginScript>> pluginScripts);
|
||||
void removePluginScript(std::shared_ptr<PluginScript> pluginScript);
|
||||
void removeAllPluginScripts();
|
||||
bool containsPluginScript(std::shared_ptr<PluginScript> pluginScript) const;
|
||||
bool containsPluginScript(std::shared_ptr<PluginScript> pluginScript, const std::shared_ptr<ContentWorld> contentWorld) const;
|
||||
bool containsPluginScriptByGroupName(const std::string& groupName) const;
|
||||
void removePluginScriptsByGroupName(const std::string& groupName);
|
||||
std::string generatePluginScriptsCodeAt(const UserScriptInjectionTime& injectionTime) const;
|
||||
std::string generateUserOnlyScriptsCodeAt(const UserScriptInjectionTime& injectionTime) const;
|
||||
std::string generateWrappedCodeForDocumentEnd() const;
|
||||
std::vector<std::shared_ptr<PluginScript>> getPluginScriptsRequiredInAllContentWorlds() const;
|
||||
|
||||
void registerEventHandlers();
|
||||
void createContentWorld(const std::shared_ptr<ContentWorld> contentWorld, const std::function<void(int)> completionHandler);
|
||||
private:
|
||||
InAppWebView* webView_;
|
||||
|
||||
// used to track Content World names -> Execution Context ID
|
||||
std::map<std::string, int> contentWorlds_;
|
||||
// used only to track plugin script to inject inside new Content Worlds
|
||||
std::map<std::string, std::vector<std::shared_ptr<PluginScript>>> pluginScriptsInContentWorlds_;
|
||||
|
||||
std::map<UserScriptInjectionTime, std::vector<std::shared_ptr<PluginScript>>> pluginScripts_ = {
|
||||
{UserScriptInjectionTime::atDocumentStart, {}},
|
||||
{UserScriptInjectionTime::atDocumentEnd, {}}
|
||||
|
@ -57,6 +68,11 @@ namespace flutter_inappwebview_plugin
|
|||
{UserScriptInjectionTime::atDocumentStart, {}},
|
||||
{UserScriptInjectionTime::atDocumentEnd, {}}
|
||||
};
|
||||
|
||||
void addScriptToWebView(std::shared_ptr<UserScript> userScript, const std::function<void(std::string)> completionHandler) const;
|
||||
void removeScriptFromWebView(std::shared_ptr<UserScript> userScript, const std::function<void()> completionHandler) const;
|
||||
|
||||
void addPluginScriptsIfRequired(const std::shared_ptr<ContentWorld> contentWorld);
|
||||
};
|
||||
}
|
||||
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_USER_CONTENT_CONTROLLER_H_
|
|
@ -1,5 +1,6 @@
|
|||
#include "../in_app_browser/in_app_browser.h"
|
||||
#include "../types/base_callback_result.h"
|
||||
#include "../types/content_world.h"
|
||||
#include "../utils/flutter.h"
|
||||
#include "../utils/log.h"
|
||||
#include "../utils/strconv.h"
|
||||
|
@ -112,7 +113,9 @@ namespace flutter_inappwebview_plugin
|
|||
auto result_ = std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>>(std::move(result));
|
||||
|
||||
auto source = get_fl_map_value<std::string>(arguments, "source");
|
||||
webView->evaluateJavascript(source, [result_ = std::move(result_)](const std::string& value)
|
||||
auto contentWorldMap = get_optional_fl_map_value<flutter::EncodableMap>(arguments, "contentWorld");
|
||||
std::shared_ptr<ContentWorld> contentWorld = contentWorldMap.has_value() ? std::make_shared<ContentWorld>(contentWorldMap.value()) : ContentWorld::page();
|
||||
webView->evaluateJavascript(source, std::move(contentWorld), [result_ = std::move(result_)](const std::string& value)
|
||||
{
|
||||
result_->Success(value);
|
||||
});
|
||||
|
@ -130,7 +133,7 @@ namespace flutter_inappwebview_plugin
|
|||
result->Success(true);
|
||||
}
|
||||
else if (string_equals(methodName, "removeUserScript")) {
|
||||
auto index = get_fl_map_value<int64_t>(arguments, "index");
|
||||
auto index = get_fl_map_value<int>(arguments, "index");
|
||||
auto userScript = std::make_unique<UserScript>(get_fl_map_value<flutter::EncodableMap>(arguments, "userScript"));
|
||||
webView->removeUserScript(index, std::move(userScript));
|
||||
result->Success(true);
|
||||
|
@ -264,6 +267,19 @@ namespace flutter_inappwebview_plugin
|
|||
channel->InvokeMethod("onCallJsHandler", std::move(arguments), std::move(callback));
|
||||
}
|
||||
|
||||
void WebViewChannelDelegate::onConsoleMessage(const std::string& message, const int64_t& messageLevel) const
|
||||
{
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto arguments = std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
|
||||
{"message", message},
|
||||
{"messageLevel", messageLevel}
|
||||
});
|
||||
channel->InvokeMethod("onConsoleMessage", std::move(arguments));
|
||||
}
|
||||
|
||||
WebViewChannelDelegate::~WebViewChannelDelegate()
|
||||
{
|
||||
debugLog("dealloc WebViewChannelDelegate");
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace flutter_inappwebview_plugin
|
|||
void onTitleChanged(const std::optional<std::string>& title) const;
|
||||
void onUpdateVisitedHistory(const std::optional<std::string>& url, const std::optional<bool>& isReload) const;
|
||||
void onCallJsHandler(const std::string& handlerName, const std::string& args, std::unique_ptr<CallJsHandlerCallback> callback) const;
|
||||
void onConsoleMessage(const std::string& message, const int64_t& messageLevel) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@ namespace flutter_inappwebview_plugin
|
|||
JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
||||
JAVASCRIPT_BRIDGE_JS_SOURCE,
|
||||
UserScriptInjectionTime::atDocumentStart,
|
||||
allowedOriginRules
|
||||
allowedOriginRules,
|
||||
nullptr,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
namespace flutter_inappwebview_plugin
|
||||
{
|
||||
const std::string VAR_PLACEHOLDER_VALUE = "$IN_APP_WEBVIEW_PLACEHOLDER_VALUE";
|
||||
const std::string VAR_PLACEHOLDER_VALUE = "$IN_APP_WEBVIEW_PLACEHOLDER_VALUE";
|
||||
const std::string VAR_PLACEHOLDER_MEMORY_ADDRESS_VALUE = "$IN_APP_WEBVIEW_PLACEHOLDER_MEMORY_ADDRESS_VALUE";
|
||||
}
|
||||
|
||||
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_SCRIPTS_UTIL_H_
|
|
@ -0,0 +1,60 @@
|
|||
#include "content_world.h"
|
||||
|
||||
namespace flutter_inappwebview_plugin
|
||||
{
|
||||
namespace {
|
||||
const std::shared_ptr<ContentWorld> ContentWorldPage = std::make_shared<ContentWorld>("page");
|
||||
const std::shared_ptr<ContentWorld> ContentWorldDefaultClient = std::make_shared<ContentWorld>("defaultClient");
|
||||
}
|
||||
|
||||
ContentWorld::ContentWorld(const std::string& name)
|
||||
: name(name)
|
||||
{}
|
||||
|
||||
ContentWorld::ContentWorld(const flutter::EncodableMap& map)
|
||||
: name(get_fl_map_value<std::string>(map, "name"))
|
||||
{}
|
||||
|
||||
bool ContentWorld::isSame(const ContentWorld& contentWorld) const
|
||||
{
|
||||
return name == contentWorld.name;
|
||||
}
|
||||
|
||||
bool ContentWorld::isSame(const std::shared_ptr<ContentWorld> contentWorld) const
|
||||
{
|
||||
return contentWorld && name == contentWorld->name;
|
||||
}
|
||||
|
||||
const std::shared_ptr<ContentWorld> ContentWorld::page()
|
||||
{
|
||||
return ContentWorldPage;
|
||||
}
|
||||
|
||||
const std::shared_ptr<ContentWorld> ContentWorld::defaultClient()
|
||||
{
|
||||
return ContentWorldDefaultClient;
|
||||
}
|
||||
|
||||
bool ContentWorld::isPage(const ContentWorld& contentWorld)
|
||||
{
|
||||
return contentWorld.isSame(*ContentWorld::page());
|
||||
}
|
||||
|
||||
bool ContentWorld::isPage(const std::shared_ptr<ContentWorld> contentWorld)
|
||||
{
|
||||
return ContentWorld::page()->isSame(contentWorld);
|
||||
}
|
||||
|
||||
bool ContentWorld::isDefaultClient(const ContentWorld& contentWorld)
|
||||
{
|
||||
return contentWorld.isSame(*ContentWorld::defaultClient());
|
||||
}
|
||||
|
||||
bool ContentWorld::isDefaultClient(const std::shared_ptr<ContentWorld> contentWorld)
|
||||
{
|
||||
return ContentWorld::defaultClient()->isSame(contentWorld);
|
||||
}
|
||||
|
||||
ContentWorld::~ContentWorld()
|
||||
{}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CONTENT_WORLD_H_
|
||||
#define FLUTTER_INAPPWEBVIEW_PLUGIN_CONTENT_WORLD_H_
|
||||
|
||||
#include <flutter/standard_method_codec.h>
|
||||
#include <string>
|
||||
|
||||
#include "../utils/flutter.h"
|
||||
|
||||
namespace flutter_inappwebview_plugin
|
||||
{
|
||||
class ContentWorld
|
||||
{
|
||||
public:
|
||||
|
||||
const std::string name;
|
||||
|
||||
ContentWorld(const std::string& name);
|
||||
ContentWorld(const flutter::EncodableMap& map);
|
||||
~ContentWorld();
|
||||
|
||||
bool isSame(const ContentWorld& contentWorld) const;
|
||||
bool isSame(const std::shared_ptr<ContentWorld> contentWorld) const;
|
||||
|
||||
const static std::shared_ptr<ContentWorld> page();
|
||||
const static std::shared_ptr<ContentWorld> defaultClient();
|
||||
|
||||
static bool isPage(const ContentWorld& contentWorld);
|
||||
static bool isPage(const std::shared_ptr<ContentWorld> contentWorld);
|
||||
static bool isDefaultClient(const ContentWorld& contentWorld);
|
||||
static bool isDefaultClient(const std::shared_ptr<ContentWorld> contentWorld);
|
||||
};
|
||||
}
|
||||
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_CONTENT_WORLD_H_
|
|
@ -6,9 +6,25 @@ namespace flutter_inappwebview_plugin
|
|||
const std::optional<std::string>& groupName,
|
||||
const std::string& source,
|
||||
const UserScriptInjectionTime& injectionTime,
|
||||
const std::vector<std::string>& allowedOriginRules
|
||||
) : UserScript(groupName, source, injectionTime, allowedOriginRules)
|
||||
const std::vector<std::string>& allowedOriginRules,
|
||||
std::shared_ptr<ContentWorld> contentWorld,
|
||||
const bool& requiredInAllContentWorlds
|
||||
) : UserScript(groupName, source, injectionTime, allowedOriginRules, std::move(contentWorld)),
|
||||
requiredInAllContentWorlds_(requiredInAllContentWorlds)
|
||||
{}
|
||||
|
||||
|
||||
std::shared_ptr<PluginScript> PluginScript::copyAndSet(const std::shared_ptr<ContentWorld> cw) const
|
||||
{
|
||||
return std::make_unique<PluginScript>(
|
||||
this->groupName,
|
||||
this->source,
|
||||
this->injectionTime,
|
||||
this->allowedOriginRules,
|
||||
cw,
|
||||
this->requiredInAllContentWorlds_
|
||||
);
|
||||
}
|
||||
|
||||
PluginScript::~PluginScript() {}
|
||||
}
|
|
@ -13,9 +13,21 @@ namespace flutter_inappwebview_plugin
|
|||
const std::optional<std::string>& groupName,
|
||||
const std::string& source,
|
||||
const UserScriptInjectionTime& injectionTime,
|
||||
const std::vector<std::string>& allowedOriginRules
|
||||
const std::vector<std::string>& allowedOriginRules,
|
||||
std::shared_ptr<ContentWorld> contentWorld,
|
||||
const bool& requiredInAllContentWorlds
|
||||
);
|
||||
~PluginScript();
|
||||
|
||||
bool isRequiredInAllContentWorlds() const
|
||||
{
|
||||
return requiredInAllContentWorlds_;
|
||||
}
|
||||
|
||||
std::shared_ptr<PluginScript> copyAndSet(const std::shared_ptr<ContentWorld> cw) const;
|
||||
|
||||
private:
|
||||
bool requiredInAllContentWorlds_;
|
||||
};
|
||||
}
|
||||
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_SCRIPT_H_
|
|
@ -7,15 +7,17 @@ namespace flutter_inappwebview_plugin
|
|||
const std::optional<std::string>& groupName,
|
||||
const std::string& source,
|
||||
const UserScriptInjectionTime& injectionTime,
|
||||
const std::vector<std::string>& allowedOriginRules
|
||||
) : groupName(groupName), source(source), injectionTime(injectionTime), allowedOriginRules(allowedOriginRules)
|
||||
const std::vector<std::string>& allowedOriginRules,
|
||||
std::shared_ptr<ContentWorld> contentWorld
|
||||
) : groupName(groupName), source(source), injectionTime(injectionTime), allowedOriginRules(allowedOriginRules), contentWorld(std::move(contentWorld))
|
||||
{}
|
||||
|
||||
UserScript::UserScript(const flutter::EncodableMap& map)
|
||||
: groupName(get_optional_fl_map_value<std::string>(map, "groupName")),
|
||||
source(get_fl_map_value<std::string>(map, "source")),
|
||||
injectionTime(static_cast<UserScriptInjectionTime>(get_fl_map_value<int>(map, "injectionTime"))),
|
||||
allowedOriginRules(functional_map(get_fl_map_value<flutter::EncodableList>(map, "allowedOriginRules"), [](const flutter::EncodableValue& m) { return std::get<std::string>(m); }))
|
||||
allowedOriginRules(functional_map(get_fl_map_value<flutter::EncodableList>(map, "allowedOriginRules"), [](const flutter::EncodableValue& m) { return std::get<std::string>(m); })),
|
||||
contentWorld(std::make_shared<ContentWorld>(get_fl_map_value<flutter::EncodableMap>(map, "contentWorld")))
|
||||
{}
|
||||
|
||||
UserScript::~UserScript()
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "../utils/flutter.h"
|
||||
#include "content_world.h"
|
||||
|
||||
namespace flutter_inappwebview_plugin
|
||||
{
|
||||
|
@ -18,17 +19,19 @@ namespace flutter_inappwebview_plugin
|
|||
class UserScript
|
||||
{
|
||||
public:
|
||||
std::wstring id;
|
||||
std::string id;
|
||||
const std::optional<std::string> groupName;
|
||||
const std::string source;
|
||||
const UserScriptInjectionTime injectionTime;
|
||||
const std::vector<std::string> allowedOriginRules;
|
||||
const std::shared_ptr<ContentWorld> contentWorld;
|
||||
|
||||
UserScript(
|
||||
const std::optional<std::string>& groupName,
|
||||
const std::string& source,
|
||||
const UserScriptInjectionTime& injectionTime,
|
||||
const std::vector<std::string>& allowedOriginRules
|
||||
const std::vector<std::string>& allowedOriginRules,
|
||||
std::shared_ptr<ContentWorld> contentWorld
|
||||
);
|
||||
UserScript(const flutter::EncodableMap& map);
|
||||
~UserScript();
|
||||
|
|
|
@ -7,82 +7,96 @@
|
|||
#include <type_traits>
|
||||
|
||||
#include "strconv.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace flutter_inappwebview_plugin
|
||||
{
|
||||
template <typename T>
|
||||
static inline void debugLog(const std::basic_string<T>& msg, const bool& isError = false)
|
||||
static inline void debugLog(const std::basic_string<T>& msg, const bool& isError = false, const std::string& filename = "", const int& line = 0)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
std::basic_string<T> debugMsg = msg;
|
||||
if (!filename.empty() && line > 0) {
|
||||
auto filenameSplit = split(filename, std::string{ "\\flutter_inappwebview_windows\\" });
|
||||
std::string reduceFilenamePath = filenameSplit.size() > 0 ? "flutter_inappwebview_windows\\" + filenameSplit.back() : filename;
|
||||
debugMsg = reduceFilenamePath + "(" + std::to_string(line) + "): " + debugMsg;
|
||||
}
|
||||
if (isError) {
|
||||
std::cerr << msg << std::endl;
|
||||
std::cerr << debugMsg << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << msg << std::endl;
|
||||
std::cout << debugMsg << std::endl;
|
||||
}
|
||||
OutputDebugString(ansi_to_wide(msg + "\n").c_str());
|
||||
OutputDebugString(utf8_to_wide("\n" + debugMsg + "\n").c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void debugLog(const char* msg, const bool& isError = false)
|
||||
static inline void debugLog(const char* msg, const bool& isError = false, const std::string& filename = "", const int& line = 0)
|
||||
{
|
||||
debugLog(std::string(msg), isError);
|
||||
debugLog(std::string(msg), isError, filename, line);
|
||||
}
|
||||
|
||||
static inline void debugLog(const std::wstring& msg, const bool& isError = false)
|
||||
static inline void debugLog(const std::wstring& msg, const bool& isError = false, const std::string& filename = "", const int& line = 0)
|
||||
{
|
||||
debugLog(wide_to_ansi(msg), isError);
|
||||
debugLog(wide_to_utf8(msg), isError, filename, line);
|
||||
}
|
||||
|
||||
static inline void debugLog(const bool& value, const bool& isError = false)
|
||||
static inline void debugLog(const bool& value, const bool& isError = false, const std::string& filename = "", const int& line = 0)
|
||||
{
|
||||
debugLog(value ? "true" : "false", isError);
|
||||
debugLog(value ? "true" : "false", isError, filename, line);
|
||||
}
|
||||
|
||||
template<
|
||||
typename T,
|
||||
typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type
|
||||
>
|
||||
static inline void debugLog(const T& value, const bool& isError = false)
|
||||
static inline void debugLog(const T& value, const bool& isError = false, const std::string& filename = "", const int& line = 0)
|
||||
{
|
||||
debugLog(std::to_string(value), isError);
|
||||
}
|
||||
|
||||
static inline std::string getHRMessage(const HRESULT& error)
|
||||
{
|
||||
return wide_to_ansi(_com_error(error).ErrorMessage());
|
||||
return wide_to_utf8(_com_error(error).ErrorMessage());
|
||||
}
|
||||
|
||||
static inline void debugLog(const HRESULT& hr)
|
||||
static inline void debugLog(const HRESULT& hr, const std::string& filename = "", const int& line = 0)
|
||||
{
|
||||
auto isError = hr != S_OK;
|
||||
debugLog((isError ? "Error: " : "Message: ") + getHRMessage(hr), isError);
|
||||
debugLog((isError ? "Error: " : "Message: ") + getHRMessage(hr), isError, filename, line);
|
||||
}
|
||||
|
||||
static inline bool succeededOrLog(const HRESULT& hr)
|
||||
static inline bool succeededOrLog(const HRESULT& hr, const std::string& filename = "", const int& line = 0)
|
||||
{
|
||||
if (SUCCEEDED(hr)) {
|
||||
return true;
|
||||
}
|
||||
debugLog(hr);
|
||||
debugLog(hr, filename, line);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool failedAndLog(const HRESULT& hr)
|
||||
static inline bool failedAndLog(const HRESULT& hr, const std::string& filename = "", const int& line = 0)
|
||||
{
|
||||
if (FAILED(hr)) {
|
||||
debugLog(hr);
|
||||
debugLog(hr, filename, line);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void failedLog(const HRESULT& hr)
|
||||
static inline void failedLog(const HRESULT& hr, const std::string& filename = "", const int& line = 0)
|
||||
{
|
||||
if (FAILED(hr)) {
|
||||
debugLog(hr);
|
||||
debugLog(hr, filename, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define debugLog(value) debugLog(value, false, __FILE__, __LINE__)
|
||||
#define succeededOrLog(value) succeededOrLog(value, __FILE__, __LINE__)
|
||||
#define failedAndLog(value) failedAndLog(value, __FILE__, __LINE__)
|
||||
#define failedLog(value) failedLog(value, __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_UTIL_H_
|
|
@ -1,8 +1,10 @@
|
|||
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_STRING_H_
|
||||
#define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_STRING_H_
|
||||
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "strconv.h"
|
||||
|
||||
|
@ -42,12 +44,12 @@ namespace flutter_inappwebview_plugin
|
|||
|
||||
static inline bool string_equals(const std::string& s1, const std::wstring& s2)
|
||||
{
|
||||
return string_equals(s1, wide_to_ansi(s2));
|
||||
return string_equals(s1, wide_to_utf8(s2));
|
||||
}
|
||||
|
||||
static inline bool string_equals(const std::wstring& s1, const std::string& s2)
|
||||
{
|
||||
return string_equals(wide_to_ansi(s1), s2);
|
||||
return string_equals(wide_to_utf8(s1), s2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -107,6 +109,33 @@ namespace flutter_inappwebview_plugin
|
|||
|
||||
return newString;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline std::basic_string<T> join(const std::vector<std::basic_string<T>>& vec, const std::basic_string<T>& delim)
|
||||
{
|
||||
return vec.empty() ? std::basic_string<T>{ "" } : /* leave early if there are no items in the list */
|
||||
std::accumulate( /* otherwise, accumulate */
|
||||
++vec.begin(), vec.end(), /* the range 2nd to after-last */
|
||||
*vec.begin(), /* and start accumulating with the first item */
|
||||
[delim](auto& a, auto& b) { return a + delim + b; });
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline std::vector<std::basic_string<T>> split(const std::basic_string<T>& s, std::basic_string<T> delimiter)
|
||||
{
|
||||
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
|
||||
std::basic_string<T> token;
|
||||
std::vector<std::basic_string<T>> res;
|
||||
|
||||
while ((pos_end = s.find(delimiter, pos_start)) != std::basic_string<T>::npos) {
|
||||
token = s.substr(pos_start, pos_end - pos_start);
|
||||
pos_start = pos_end + delim_len;
|
||||
res.push_back(token);
|
||||
}
|
||||
|
||||
res.push_back(s.substr(pos_start));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_STRING_H_
|
Loading…
Reference in New Issue