예제 #1
0
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
                    {
예제 #3
0
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;
}