V8 javascript引擎初步體驗__UI

來源:互聯網
上載者:User

v8 引擎,不必多說,大名鼎鼎,迄今最快的js引擎。

這麼好的東西,如果盡在瀏覽器中使用,太浪費了,也希望用到其他地方,比如一些用戶端開發中。


閑言少講,這就開始


下載源碼

去官方網站:https://code.google.com/p/v8/

我喜歡用git,所以從這裡下載

git clone git://github.com/v8/v8.git v8 && cd v8

編譯

我為android平台編譯的,折騰了好久,記錄一些重點。你首先要看這個:http://code.google.com/p/v8/wiki/BuildingWithGYP

其實關鍵是

make dependencies
這需要花很長時間(呃,沒辦法,國內網速不給力,我下載了好幾次)。。。


然後,在android上編譯(其他平台。so easy,看文檔), 你可以先看看D8OnAndroid (是android平台的一個js命令列吧,不明覺厲)的編譯,不過沒什麼用處。

我自己的編譯方法,是用交叉編譯的

Cross-compiling

Similar to building with Clang, you can also use a cross-compiler. Just export your toolchain (CXX/LINK environment variables should be enough) and compile. For example:

export CXX=/path/to/cross-compile-g++export LINK=/path/to/cross-compile-g++make arm.release

(編譯等待中.....)


完了之後,你就可以使用了。


在android上使用

首先,建立一個工程(怎麼建立。這個。。。還是自己找吧),一個Activity工程就行,然後在工程目錄下建立一個jni目錄。

具體怎麼使用ndk,我就不說,自己找吧,我說重點的: 1. 拷貝標頭檔和庫檔案

為了方便,我把標頭檔和庫檔案放在jni下的include和lib下。標頭檔直接從v8/include檔案夾下拷貝就可以,庫檔案比較麻煩一些,必須拷貝這些:

 

libicudata.a  libicui18n.a  libicuuc.a  libv8.a  libv8_snapshot.a 你可以從v8/out目錄下尋找(用find吧,反正記不住具體在什麼位置了) 少了編譯時間就會報找不到符合的錯誤(說多了都是淚啊)


2. 注意Android.mk的寫法

在寫Android.mk的時候,必須注意:

   1. 庫的引用順序很重要,順序錯了,一樣找不到符號

   2. 要用stl,

Android.mk和Application.mk(STL需要的)的代碼如下,給大家和參考,省得走彎路

Android.mk:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_CFLAGS += -I$(LOCAL_PATH)/includeLOCAL_LDFLAGS += \    $(LOCAL_PATH)/lib/libv8.a \    $(LOCAL_PATH)/lib/libv8_snapshot.a \    $(LOCAL_PATH)/lib/libicui18n.a \    $(LOCAL_PATH)/lib/libicuuc.a \    $(LOCAL_PATH)/lib/libicudata.a \    /<path>/android-ndk-r9d//sources/cxx-stl/stlport/libs/armeabi/libstlport_static.aLOCAL_MODULE := jswrapperLOCAL_LDLIBS := -llogLOCAL_SRC_FILES := \    registers.cpp \    JavaScriptContextWrap.cpp \    javautils.cpp \    JsJavaClassProxy.cpp \    javawrap.cpp#sample.cpp sample-jni.cpp \LOCAL_ALLOW_UNDEFINED_SYMBOLS := trueLOCAL_WHOLE_STATIC_LIBRARIES += android_supportinclude $(BUILD_SHARED_LIBRARY)$(call import-module, android/support)
(我很笨啊,stl不全路徑連結就找不到,呃,難道上天又一次中意我,要給我磨練嗎......)

記得lib的順序和stl噢。。。


Application.mk

APP_CFLAGS += -fexceptionsAPP_CFLAGS += -frttiAPP_STL := stlport_static#gnustl_static

編譯用ndk-build就好了。


代碼編寫

至於jni部分的代碼,我就不寫了,不懂的baidu和google,你懂的。


標頭檔。用一個 "v8.h"就好了。
1. 初始化

v8::V8::InitializeICU();

(完了。是的,就這麼簡單) 2. 建立Isolate和Context

    isolate_ = v8::Isolate::New();    isolate_->Enter();    v8::HandleScope handle_scope(isolate_);    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);        //create Log object    v8::Handle<v8::ObjectTemplate> log = v8::ObjectTemplate::New(isolate_);    log->Set(v8::String::NewFromUtf8(isolate_, "e"),            v8::FunctionTemplate::New(isolate_, js_func_log_e));    log->Set(v8::String::NewFromUtf8(isolate_, "i"),            v8::FunctionTemplate::New(isolate_, js_func_log_i));    log->Set(v8::String::NewFromUtf8(isolate_, "v"),            v8::FunctionTemplate::New(isolate_, js_func_log_v));    log->Set(v8::String::NewFromUtf8(isolate_, "d"),            v8::FunctionTemplate::New(isolate_, js_func_log_d));    global->Set(v8::String::NewFromUtf8(isolate_, "Log"), log);    //TODO others    global->Set(v8::String::NewFromUtf8(isolate_, "import_java_class"),             v8::FunctionTemplate::New(isolate_, js_func_import_java_class));            context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));

內容有點多哈。別著急,聽我慢慢道來。

首先,建立一個v8::Isolate, 用v8::Isolate::New()。 isolate是什麼東東。這個嘛,其實我也不太清楚,大概類似一個虛擬機器,所有的javascript對象都在這個isolate上,不太的isolate老死不相往來。

然後需要調用一下isolate_->Enter(),當然要銷毀時,調用一下isolate_->Leave()。

對了,v8是c++的,成員方法首字母都是大寫的。

第二,我們可以建立一個ObjectTemplate了。ObjectTemplate望文生義,是對象的模版,怎麼說呢,對應到C++和java裡面,你可以認為是靜態類,有一堆靜態方法。

各位請先看最後一句:v8::Context::New(isolate_, NULL, global)。這句話註冊一個全域的模版,也就是說,如果我在global中註冊一個print函數,那麼可以直接在js中這樣寫:

print ("Hi, I\'m from native");

我們的例子裡面,是註冊了一個Log的子ObjectTempl,Log又包含e, i,  v, d幾個方法,其實就是對應的android.util.Log.e, i, v, d。


註冊方法是調用Set,C++函數指標需要用

v8::FunctionTemplate::New
來封裝。這些知道就行了,不必深究(其實我也不懂 )


還有一點必須說明:上面的代碼實際上是一個類的一部分,這裡有兩個成員變數:

    v8::Persistent<v8::Context> context_;    v8::Isolate* isolate_;
isolate直接使用指標,而Context必須用Persistent,這是一個可以持久保持對象的指標(防止被v8當記憶體回收了),使用方法是用 Rest:

    context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));

3. 定義一個函數 

凡事先看代碼:(我用js_func_log_x來實現js_func_log_i等函數的公用部分)

void js_func_log_x(int level, const v8::FunctionCallbackInfo<v8::Value>& args) {    if (args.Length() == 0) {        return ;    }        //get tag    char szTag[1024] = "";    {        v8::HandleScope handle_scope(args.GetIsolate());        v8::String::Utf8Value str(args[0]);        const char* cstr = ToCString(str);                strcpy(szTag, cstr);    }    char szLog[1024*8] = "";    bool first = true;    int len = 0;    for (int i = 1; i < args.Length(); i++)    {        v8::HandleScope handle_scope(args.GetIsolate());        if (first) {            first = false;        } else {            len += sprintf(szLog + len, " ");        }        v8::String::Utf8Value str(args[i]);        const char* cstr = ToCString(str);        len += sprintf(szLog + len, "%s", cstr);    }    __android_log_print(level, szTag, "%s", szLog);}

args 包含了參數和運行時。在每次取參數處理參數時,必須調用

        v8::HandleScope handle_scope(args.GetIsolate());

(why。I don't known 。。。。)

從Value中取字串,則需要用ToCString,他也很簡單:

static const char* ToCString(const v8::String::Utf8Value& value) {  return *value ? *value : "<string conversion failed>";}

正經的給v8使用的函數是這樣的:

void js_func_log_i(const v8::FunctionCallbackInfo<v8::Value>& args) {    js_func_log_x(ANDROID_LOG_INFO, args);}void js_func_log_v(const v8::FunctionCallbackInfo<v8::Value>& args) {    js_func_log_x(ANDROID_LOG_VERBOSE, args);}void js_func_log_d(const v8::FunctionCallbackInfo<v8::Value>& args) {    js_func_log_x(ANDROID_LOG_DEBUG, args);}void js_func_log_e(const v8::FunctionCallbackInfo<v8::Value>& args) {    js_func_log_x(ANDROID_LOG_ERROR, args);}

好了,初體驗到此結束


一些重要的知識點 1. 關聯一個對象到Isolate上

Isolate可以有多個,如果有一個對象關聯到Isolate,該如何從Isolate找到該對象呢。

使用Isolate的GetData/SetData

比如

JavaWrapper* JavaWrapper::fromIsolate(Isolate* isolate) {    if (isolate == NULL) {        return NULL;    }    void *data = isolate->GetData(ISOLATE_SLOT_JAVA_WRAPPER);    JavaWrapper* javawrap = reinterpret_cast<JavaWrapper*>(data);        return javawrap && javawrap->isolate_ == isolate ? javawrap : NULL;}JavaWrapper::JavaWrapper(Isolate* isolate):isolate_(isolate){    isolate_->SetData(ISOLATE_SLOT_JAVA_WRAPPER, (void*)this);}

2. 怎樣從v8::Value中得到其他類型的參數

v8::Value是個綜合物件,我們可以這樣做:

    for (int i = 0; i < count; i++) {        HandleScope handle_scope(args.GetIsolate());        Local<Value> v = args[i];        if (v->IsUndefined() || v->IsNull()) {            types[i] = JsJavaClassProxy::NullClass();            values[i] = JsJavaClassProxy::NullObject();            LOGV(" arg(%d) is null\n", i);        } else if (v->IsTrue() || v->IsFalse()) {            types[i] = JsJavaClassProxy::BooleanClass();            jboolean jv = (jboolean)(v->IsTrue() ? true : false);            values[i] = jreflect::ValueOf(env, jv);            LOGV(" arg(%d) is boolean:%d", i, jv);        } else if (v->IsString()) {            types[i] = JsJavaClassProxy::StringClass();            String::Utf8Value str(v);            const char* cstr = ToCString(str);            values[i] = env->NewStringUTF(cstr);            LOGV(" arg(%d) is String:%s", i, cstr);        } else if (v->IsBoolean()) {            types[i] = JsJavaClassProxy::BooleanClass();            jboolean jv = v->ToBoolean()->Value();            values[i] = jreflect::ValueOf(env, jv);            LOGV(" arg(%d) is boolean:%d", i, jv);        } else if (v->IsInt32() || v->IsUint32()) {            types[i] = JsJavaClassProxy::IntClass();            jint jv = v->ToInt32()->Value();            values[i] = jreflect::ValueOf(env, jv);            LOGV(" arg(%d) is int:%d", i, jv);        } else if (v->IsNumber()) {            types[i] = JsJavaClassProxy::DoubleClass();            jdouble jv = v->ToNumber()->Value();            values[i] = jreflect::ValueOf(env, jv);            LOGV(" arg(%d) is double:%f", i, jv);        } /** TODO MORE **/ else {            LOGE("Invalidate Arg type!");            ASSERT(false);        }    }
更多的,從v8.h中看就可以了。


好了,先到這裡吧。




相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.