Skip to content

Commit

Permalink
support evaluateJavascript
Browse files Browse the repository at this point in the history
  • Loading branch information
SinyimZhi committed Jan 15, 2024
1 parent 2d19389 commit 9dc814f
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 24 deletions.
5 changes: 5 additions & 0 deletions common/webview_app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ void WebviewApp::OnWebKitInitialized()
}
}
external.EvaluateCallback = (nReqID, result) => {
native function EvaluateCallback();
EvaluateCallback(nReqID, result);
}
external.StartRequest = (nReqID, strCmd, strCallBack, strArgs, strLog) => {
native function StartRequest();
StartRequest(nReqID, strCmd, strCallBack, strArgs, strLog);
Expand Down
55 changes: 40 additions & 15 deletions common/webview_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <sstream>
#include <string>
#include <iostream>
#include <chrono>

#include "include/base/cef_callback.h"
#include "include/cef_app.h"
Expand Down Expand Up @@ -64,6 +65,17 @@ bool WebviewHandler::OnProcessMessageReceived(
onJavaScriptChannelMessage(
fun_name,param,std::to_string(js_callback_id),std::to_string(frame->GetIdentifier()));
}
else if(message_name == kEvaluateCallbackMessage){
CefString callbackId = message->GetArgumentList()->GetString(0);
CefString param = message->GetArgumentList()->GetString(1);
if(!callbackId.empty() && !param.empty()){
auto it = js_callbacks_.find(callbackId.ToString());
if(it != js_callbacks_.end()){
it->second(param.ToString());
js_callbacks_.erase(it);
}
}
}
return false;
}

Expand Down Expand Up @@ -373,35 +385,35 @@ void WebviewHandler::deleteCookie(const std::string& domain, const std::string&
}
}

bool WebviewHandler::visitAllCookies(std::function<void(std::map<std::string, std::map<std::string, std::string>>)> callback){
void WebviewHandler::visitAllCookies(std::function<void(std::map<std::string, std::map<std::string, std::string>>)> callback){
CefRefPtr<CefCookieManager> manager = CefCookieManager::GetGlobalManager(nullptr);
if (!manager)
{
return false;
return;
}

CefRefPtr<WebviewCookieVisitor> cookieVisitor = new WebviewCookieVisitor();
cookieVisitor->setOnVisitComplete(callback);

return manager->VisitAllCookies(cookieVisitor);
manager->VisitAllCookies(cookieVisitor);
}

bool WebviewHandler::visitUrlCookies(const std::string& domain, const bool& isHttpOnly, std::function<void(std::map<std::string, std::map<std::string, std::string>>)> callback){
void WebviewHandler::visitUrlCookies(const std::string& domain, const bool& isHttpOnly, std::function<void(std::map<std::string, std::map<std::string, std::string>>)> callback){
CefRefPtr<CefCookieManager> manager = CefCookieManager::GetGlobalManager(nullptr);
if (!manager)
{
return false;
return;
}

CefRefPtr<WebviewCookieVisitor> cookieVisitor = new WebviewCookieVisitor();
cookieVisitor->setOnVisitComplete(callback);

std::string httpDomain = "https://" + domain + "/cookiestorage";

return manager->VisitUrlCookies(httpDomain, isHttpOnly, cookieVisitor);
manager->VisitUrlCookies(httpDomain, isHttpOnly, cookieVisitor);
}

bool WebviewHandler::setJavaScriptChannels(const std::vector<std::string> channels)
void WebviewHandler::setJavaScriptChannels(const std::vector<std::string> channels)
{
std::string extensionCode = "";
for(auto& channel : channels)
Expand All @@ -411,10 +423,10 @@ bool WebviewHandler::setJavaScriptChannels(const std::vector<std::string> channe
extensionCode += channel;
extensionCode += "',e,r)};";
}
return executeJavaScript(extensionCode);
executeJavaScript(extensionCode);
}

bool WebviewHandler::sendJavaScriptChannelCallBack(const bool error, const std::string result, const std::string callbackId, const std::string frameId)
void WebviewHandler::sendJavaScriptChannelCallBack(const bool error, const std::string result, const std::string callbackId, const std::string frameId)
{
CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create(kExecuteJsCallbackMessage);
CefRefPtr<CefListValue> args = message->GetArgumentList();
Expand All @@ -427,13 +439,18 @@ bool WebviewHandler::sendJavaScriptChannelCallBack(const bool error, const std::
if (frame->GetIdentifier() == atoll(frameId.c_str()))
{
frame->SendProcessMessage(PID_RENDERER, message);
return true;
}
}
return false;
}

bool WebviewHandler::executeJavaScript(const std::string code)
static std::string GetCallbackId()
{
auto time = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
time_t timestamp = time.time_since_epoch().count();
return std::to_string(timestamp);
}

void WebviewHandler::executeJavaScript(const std::string code, std::function<void(std::string)> callback)
{
if(!code.empty())
{
Expand All @@ -442,13 +459,21 @@ bool WebviewHandler::executeJavaScript(const std::string code)
if ((*bit).get()) {
CefRefPtr<CefFrame> frame = (*bit)->GetMainFrame();
if (frame) {
frame->ExecuteJavaScript(code, frame->GetURL(), 0);
return true;
std::string finalCode = code;
if(callback != nullptr){
std::string callbackId = GetCallbackId();
finalCode = "external.EvaluateCallback('";
finalCode += callbackId;
finalCode += "',(function(){return ";
finalCode += code;
finalCode += "})());";
js_callbacks_[callbackId] = callback;
}
frame->ExecuteJavaScript(finalCode, frame->GetURL(), 0);
}
}
}
}
return false;
}

void WebviewHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect &rect) {
Expand Down
13 changes: 8 additions & 5 deletions common/webview_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <functional>
#include <list>
#include <unordered_map>

#include "webview_cookieVisitor.h"

Expand Down Expand Up @@ -122,12 +123,12 @@ public CefRenderHandler{

void setCookie(const std::string& domain, const std::string& key, const std::string& value);
void deleteCookie(const std::string& domain, const std::string& key);
bool visitAllCookies(std::function<void(std::map<std::string, std::map<std::string, std::string>>)> callback);
bool visitUrlCookies(const std::string& domain, const bool& isHttpOnly, std::function<void(std::map<std::string, std::map<std::string, std::string>>)> callback);
void visitAllCookies(std::function<void(std::map<std::string, std::map<std::string, std::string>>)> callback);
void visitUrlCookies(const std::string& domain, const bool& isHttpOnly, std::function<void(std::map<std::string, std::map<std::string, std::string>>)> callback);

bool setJavaScriptChannels(const std::vector<std::string> channels);
bool sendJavaScriptChannelCallBack(const bool error, const std::string result, const std::string callbackId, const std::string frameId);
bool executeJavaScript(const std::string code);
void setJavaScriptChannels(const std::vector<std::string> channels);
void sendJavaScriptChannelCallBack(const bool error, const std::string result, const std::string callbackId, const std::string frameId);
void executeJavaScript(const std::string code, std::function<void(std::string)> callback = nullptr);

private:
uint32_t width = 1;
Expand All @@ -138,6 +139,8 @@ public CefRenderHandler{
// List of existing browser windows. Only accessed on the CEF UI thread.
typedef std::list<CefRefPtr<CefBrowser>> BrowserList;
BrowserList browser_list_;

std::unordered_map<std::string, std::function<void(std::string)>> js_callbacks_;

// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(WebviewHandler);
Expand Down
27 changes: 27 additions & 0 deletions common/webview_js_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ bool CefJSHandler::Execute(const CefString& name,
int reqID = CefJSBridge::GetNextReqID();
retval = CefV8Value::CreateInt(reqID);
}
else if (name == "EvaluateCallback") {
CefString callbackId = arguments[0]->GetStringValue();
CefString result = arguments[1]->GetStringValue();
if (!js_bridge_->EvaluateCallback(callbackId, result)) {
std::ostringstream strStream;
strStream << "Failed to callback: " << callbackId.c_str() << ".";
strStream.flush();

exception = strStream.str();
}
}
else {
exception = "NativeHost no this fun.";
}
Expand Down Expand Up @@ -125,6 +136,22 @@ bool CefJSBridge::StartRequest(int reqId,
return false;
}

bool CefJSBridge::EvaluateCallback(const CefString& callbackId, const CefString& result){
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
if(context){
CefRefPtr<CefFrame> frame = context->GetFrame();
if(frame){
CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create(kEvaluateCallbackMessage);
message->GetArgumentList()->SetString(0, callbackId);
message->GetArgumentList()->SetString(1, result);
frame->SendProcessMessage(PID_BROWSER, message);
return true;
}
}
return false;
}


int CefJSBridge::GetNextReqID()
{
long nRet = ++s_nReqID;
Expand Down
2 changes: 2 additions & 0 deletions common/webview_js_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

static const char kJSCallCppFunctionMessage[] = "JSCallCppFunction"; //js call c++ message
static const char kExecuteJsCallbackMessage[] = "ExecuteJsCallback"; //c++ call js message
static const char kEvaluateCallbackMessage[] = "EvaluateCallback"; //js callback c++ message
static const char kFocusedNodeChangedMessage[] = "FocusedNodeChanged"; //elements that capture focus in web pages changed message

class CefJSBridge
Expand All @@ -22,6 +23,7 @@ class CefJSBridge
public:
static int GetNextReqID();
bool StartRequest(int reqId, const CefString& strCmd, const CefString& strCallback, const CefString& strArgs);
bool EvaluateCallback(const CefString& callbackId, const CefString& result);

bool CallCppFunction(const CefString& function_name, const CefString& params, CefRefPtr<CefV8Value> callback, CefRefPtr<CefV8Value> rawdata);
void RemoveCallbackFuncWithFrame(CefRefPtr<CefFrame> frame);
Expand Down
8 changes: 8 additions & 0 deletions common/webview_plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ namespace webview_cef {
handler.get()->executeJavaScript(code);
result(1, nullptr);
}
else if(name.compare("evaluateJavascript") == 0){
const auto code = webview_value_get_string(webview_value_get_list_value(values, 0));
handler.get()->executeJavaScript(code, [=](std::string values){
WValue* retValue = webview_value_new_string(values.c_str());
result(1, retValue);
webview_value_unref(retValue);
});
}
else {
result = 0;
}
Expand Down
3 changes: 2 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ class _MyAppState extends State<MyApp> {
//normal JavaScriptChannels
await _controller.setJavaScriptChannels(jsChannels);
//also you can build your own jssdk by execute JavaScript code to CEF
await _controller.executeJavaScript("function abc(e){console.log(e)}");
await _controller.executeJavaScript("function abc(e){return 'abc:'+ e}");
_controller.evaluateJavascript("abc('test')").then((value) => print(value));
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
Expand Down
10 changes: 9 additions & 1 deletion lib/src/webview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,22 @@ class WebViewController extends ValueNotifier<bool> {
'sendJavaScriptChannelCallBack', [error, result, callbackId, frameId]);
}

Future<dynamic> executeJavaScript(String code) async {
Future<void> executeJavaScript(String code) async {
if (_isDisposed) {
return;
}
assert(value);
return _pluginChannel.invokeMethod('executeJavaScript', [code]);
}

Future<dynamic> evaluateJavascript(String code) async {
if (_isDisposed) {
return;
}
assert(value);
return _pluginChannel.invokeMethod('evaluateJavascript', [code]);
}

/// Moves the virtual cursor to [position].
Future<void> _cursorMove(Offset position) async {
if (_isDisposed) {
Expand Down
4 changes: 2 additions & 2 deletions macos/Classes/CefWrapper.mm
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,9 @@ + (void) handleMethodCallWrapper: (FlutterMethodCall*)call result:(FlutterResult
result([NSNumber numberWithLong:textureId]);
}else{
WValue *encodeArgs = [self encode_flvalue_to_wvalue:call.arguments];
int ret = webview_cef::HandleMethodCall(name, encodeArgs, [=](int ret, WValue* args){
webview_cef::HandleMethodCall(name, encodeArgs, [=](int ret, WValue* args){
if(ret != 0){
result([self encode_wvalue_to_flvalue:args])
result([self encode_wvalue_to_flvalue:args]);
}
else{
result(nil);
Expand Down

0 comments on commit 9dc814f

Please sign in to comment.