void Application::runJavaScript( const std::string& js ) { // ToDo: call the cordova.xxxx JS functions directly via the context // if there is no _exposedJSObject do nothing if(_exposedJSObject.get()) { //if (CefCurrentlyOn(TID_UI)) { CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext(); CefRefPtr<CefFrame> frame = context->GetFrame(); frame->ExecuteJavaScript(js, frame->GetURL(), 0); } //else //{ // CefPostTask(TID_UI, NewCefRunnableMethod(this, &Application::runJavaScript, js)); //} } }
bool CefAppUnmanagedWrapper::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId sourceProcessId, CefRefPtr<CefProcessMessage> message) { auto handled = false; auto name = message->GetName(); auto argList = message->GetArgumentList(); auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier(), false); //Error handling for missing/closed browser if (browserWrapper == nullptr) { if (name == kJavascriptCallbackDestroyRequest || name == kJavascriptRootObjectRequest || name == kJavascriptAsyncMethodCallResponse) { //If we can't find the browser wrapper then we'll just //ignore this as it's likely already been disposed of return true; } CefString responseName; if (name == kEvaluateJavascriptRequest) { responseName = kEvaluateJavascriptResponse; } else if (name == kJavascriptCallbackRequest) { responseName = kJavascriptCallbackResponse; } else { //TODO: Should be throw an exception here? It's likely that only a CefSharp developer would see this // when they added a new message and haven't yet implemented the render process functionality. throw gcnew Exception("Unsupported message type"); } auto callbackId = GetInt64(argList, 1); auto response = CefProcessMessage::Create(responseName); auto responseArgList = response->GetArgumentList(); auto errorMessage = String::Format("Request BrowserId : {0} not found it's likely the browser is already closed", browser->GetIdentifier()); //success: false responseArgList->SetBool(0, false); SetInt64(responseArgList, 1, callbackId); responseArgList->SetString(2, StringUtils::ToNative(errorMessage)); browser->SendProcessMessage(sourceProcessId, response); return true; } //these messages are roughly handled the same way if (name == kEvaluateJavascriptRequest || name == kJavascriptCallbackRequest) { bool success = false; CefRefPtr<CefV8Value> result; CefString errorMessage; CefRefPtr<CefProcessMessage> response; if (name == kEvaluateJavascriptRequest) { response = CefProcessMessage::Create(kEvaluateJavascriptResponse); } else { response = CefProcessMessage::Create(kJavascriptCallbackResponse); } //both messages have the frameId stored at 0 and callbackId stored at index 1 auto frameId = GetInt64(argList, 0); int64 callbackId = GetInt64(argList, 1); if (name == kEvaluateJavascriptRequest) { JavascriptRootObjectWrapper^ rootObjectWrapper; browserWrapper->JavascriptRootObjectWrappers->TryGetValue(frameId, rootObjectWrapper); //NOTE: In the rare case when when OnContextCreated hasn't been called we need to manually create the rootObjectWrapper //It appears that OnContextCreated is only called for pages that have javascript on them, which makes sense //as without javascript there is no need for a context. if (rootObjectWrapper == nullptr) { rootObjectWrapper = gcnew JavascriptRootObjectWrapper(browser->GetIdentifier(), browserWrapper->BrowserProcess); browserWrapper->JavascriptRootObjectWrappers->TryAdd(frameId, rootObjectWrapper); } auto callbackRegistry = rootObjectWrapper->CallbackRegistry; auto script = argList->GetString(2); auto frame = browser->GetFrame(frameId); if (frame.get()) { auto context = frame->GetV8Context(); if (context.get() && context->Enter()) { try { CefRefPtr<CefV8Exception> exception; success = context->Eval(script, result, exception); //we need to do this here to be able to store the v8context if (success) { auto responseArgList = response->GetArgumentList(); SerializeV8Object(result, responseArgList, 2, callbackRegistry); } else { errorMessage = StringUtils::CreateExceptionString(exception); } } finally { context->Exit(); } } else {
void V8ValueAppendToCefListValue(CefRefPtr<CefV8Value> v8Value, CefRefPtr<CefListValue> listValue, int nestingLevel) { if (!v8Value->IsValid()) { DebugLog("V8ValueAppendToCefListValue(): IsValid() FAILED"); return; } if (nestingLevel > 8) { DebugLog("V8ValueAppendToCefListValue(): WARNING: max nesting level (8) " \ "exceeded"); return; } if (v8Value->IsUndefined() || v8Value->IsNull()) { listValue->SetNull((int)listValue->GetSize()); } else if (v8Value->IsBool()) { listValue->SetBool((int)listValue->GetSize(), v8Value->GetBoolValue()); } else if (v8Value->IsInt()) { listValue->SetInt((int)listValue->GetSize(), v8Value->GetIntValue()); } else if (v8Value->IsUInt()) { uint32 uint32_value = v8Value->GetUIntValue(); CefRefPtr<CefBinaryValue> binaryValue = CefBinaryValue::Create( &uint32_value, sizeof(uint32_value)); listValue->SetBinary((int)listValue->GetSize(), binaryValue); } else if (v8Value->IsDouble()) { listValue->SetDouble((int)listValue->GetSize(), v8Value->GetDoubleValue()); } else if (v8Value->IsDate()) { // TODO: in time_utils.pyx there are already functions for // converting cef_time_t to python DateTime, we could easily // add a new function for converting the python DateTime to // string and then to CefString and expose the function using // the "public" keyword. But how do we get the cef_time_t // structure from the CefTime class? GetDateValue() returns // CefTime class. listValue->SetNull((int)listValue->GetSize()); } else if (v8Value->IsString()) { listValue->SetString((int)listValue->GetSize(), v8Value->GetStringValue()); } else if (v8Value->IsArray()) { // Check for IsArray() must happen before the IsObject() check. int length = v8Value->GetArrayLength(); CefRefPtr<CefListValue> newListValue = CefListValue::Create(); for (int i = 0; i < length; ++i) { V8ValueAppendToCefListValue(v8Value->GetValue(i), newListValue, nestingLevel + 1); } listValue->SetList((int)listValue->GetSize(), newListValue); } else if (v8Value->IsFunction()) { // Check for IsFunction() must happen before the IsObject() check. if (CefV8Context::InContext()) { CefRefPtr<CefV8Context> context = \ CefV8Context::GetCurrentContext(); CefRefPtr<CefFrame> frame = context->GetFrame(); std::string strCallbackId = PutJavascriptCallback(frame, v8Value); /* strCallbackId = '####cefpython####' \ '{"what"=>"javascript-callback", ..}' */ listValue->SetString((int)listValue->GetSize(), strCallbackId); } else { listValue->SetNull((int)listValue->GetSize()); DebugLog("V8ValueAppendToCefListValue() FAILED: not in V8 context" " , FATAL ERROR!"); } } else if (v8Value->IsObject()) { // Check for IsObject() must happen after the IsArray() // and IsFunction() checks. listValue->SetDictionary((int)listValue->GetSize(), V8ObjectToCefDictionaryValue(v8Value, nestingLevel + 1)); } else { listValue->SetNull((int)listValue->GetSize()); DebugLog("V8ValueAppendToCefListValue() FAILED: unknown V8 type"); } }
bool CefJSHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) { // 当Web中调用了"NimCefWebFunction"函数后,会触发到这里,然后把参数保存,转发到Broswer进程 // Broswer进程的BrowserHandler类在OnProcessMessageReceived接口中处理kJsCallbackMessage消息,就可以收到这个消息 if (arguments.size() < 2) { exception = "Invalid arguments."; return false; } CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext(); CefRefPtr<CefFrame> frame = context->GetFrame(); CefRefPtr<CefBrowser> browser = context->GetBrowser(); int64_t browser_id = browser->GetIdentifier(); int64_t frame_id = frame->GetIdentifier(); if (name == "call") { // 允许没有参数列表的调用,第二个参数为回调 // 如果传递了参数列表,那么回调是第三个参数 CefString function_name = arguments[0]->GetStringValue(); CefString params = "{}"; CefRefPtr<CefV8Value> callback; if (arguments[0]->IsString() && arguments[1]->IsFunction()) { callback = arguments[1]; } else if (arguments[0]->IsString() && arguments[1]->IsString() && arguments[2]->IsFunction()) { params = arguments[1]->GetStringValue(); callback = arguments[2]; } else { exception = "Invalid arguments."; return false; } // 执行 C++ 方法 if (!js_bridge_->CallCppFunction(function_name, params, callback)) { exception = nbase::StringPrintf("Failed to call function %s.", function_name).c_str(); return false; } return true; } else if (name == "register") { if (arguments[0]->IsString() && arguments[1]->IsFunction()) { std::string function_name = arguments[0]->GetStringValue(); CefRefPtr<CefV8Value> callback = arguments[1]; if (!js_bridge_->RegisterJSFunc(function_name, callback)) { exception = "Failed to register function."; return false; } return true; } else { exception = "Invalid arguments."; return false; } } return false; }