V8 engine, needless to say, is well-known, so far the fastest js engine.
Such a good thing is too wasteful to be used in a browser, and it is also expected to be used in other places, such as some client development.
This is the beginning.
Download source code
Go to Official Website: https://code.google.com/p/v8/
I like to use git, So download it from here
git clone git://github.com/v8/v8.git v8 && cd v8
Compile
I compiled it for the android platform. It took a long time to record some important points. First you should look at this: http://code.google.com/p/v8/wiki/BuildingWithGYP
The key is
make dependencies
This takes a long time (well, no way. The domestic network speed is not good. I downloaded it several times )...
Then, compile on android (other platforms? So easy, see the document). You can first check the compilation of D8OnAndroid (a js command line on the android platform, but it is useless.
My Own compilation method is cross-compiled.
Cross-compiling
Similar to building with Clang, you can also use a cross-compiler. Just export your toolchain (CXX/LINKEnvironment variables shocould be enough) and compile. For example:
export CXX=/path/to/cross-compile-g++export LINK=/path/to/cross-compile-g++make arm.release
(Compilation is waiting .....)
After that, you can use it.
Use on android
First, create a project (how to create it? This... Find it by yourself), an Activity project, and then create a jni directory under the project directory.
I don't want to talk about how to use ndk. Find it by yourself. I'll focus on it:
1. Copy the header file and Library File
For convenience, I put the header file and library file under the include and lib under jni. The header file can be directly copied from the v8/include folder. The library file is a little more complicated and must be copied:
libicudata.a libicui18n.a libicuuc.a libv8.a libv8_snapshot.a
You can find it in the v8/out directory (Use find, but you cannot remember the specific location) when compilation is missing, the system will report errors that cannot be found)
2. Pay attention to the Android. mk format.
Note the following when writing Android. mk:
1. The reference sequence of the database is very important. The sequence is wrong and symbols cannot be found.
2. Use stl,
The code for Android. mk and Application. mk (required by STL) is as follows, which saves you the trouble of detours for reference.
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 \ /
/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)
(I'm stupid. I can't find the stl link without all the paths. Er, is it another time that God liked me? Do you want to train me ......)
Remember the lib sequence and stl...
Application. mk
APP_CFLAGS += -fexceptionsAPP_CFLAGS += -frttiAPP_STL := stlport_static#gnustl_static
Compile and use ndk-build.
Code Writing
As for the jni part of the code, I will not write it. baidu and google, you know.
Header file? Just use a "v8.h.
1. Initialization
v8::V8::InitializeICU();
(Finished? Yes, that's simple)
2. Create Isolate and Context
isolate_ = v8::Isolate::New(); isolate_->Enter(); v8::HandleScope handle_scope(isolate_); v8::Handle
global = v8::ObjectTemplate::New(isolate_); //create Log object v8::Handle
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));
The content is a bit Doha. Don't worry. Let me hear it.
First, create a v8: Isolate with v8: Isolate: New (). What is isolate? In fact, I am not quite clear about this. It is like a virtual machine. All javascript objects are on this isolate, and they are not too busy with isolate.
Then you need to call isolate _-> Enter (). Of course, when you want to destroy isolate _-> Leave (), call isolate _-> Leave ().
By the way, v8 is c ++, and the first letter of the member method is uppercase.
Second, we can create an ObjectTemplate. ObjectTemplate is an object template. It corresponds to C ++ and java. You can think of it as a static class and there are a bunch of static methods.
Let's take a look at the last sentence: v8: Context: New (isolate _, NULL, global ). Register a global template. That is to say, if I register a print function in global, I can directly write it in js as follows:
print ("Hi, I\'m from native");
In our example, the sub-ObjectTempl of a Log is registered, and the Log contains the e, I, v, and d methods, which are actually the corresponding android. util. log. e, I, v, d.
The registration method is to call the Set, and the C ++ function pointer needs to be used
v8::FunctionTemplate::New
. You just need to know this. You don't have to go into it (but I don't understand it either)
The above code is actually part of a class. Here there are two member variables:
v8::Persistent
context_; v8::Isolate* isolate_;
Isolate uses pointers directly, while Context must use Persistent, which is a pointer that can persistently keep objects (to prevent v8 from being garbage collected). Rest is used.:
context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));
3. Define a function
Code first: (I use js_func_log_x to implement the public part of functions such as js_func_log_ I)
void js_func_log_x(int level, const v8::FunctionCallbackInfo
& 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 contains parameters and runtime. You must call
v8::HandleScope handle_scope(args.GetIsolate());
(Why? I don't known ....)
To retrieve a string from the Value, use ToCString, which is also very simple:
static const char* ToCString(const v8::String::Utf8Value& value) { return *value ? *value : "
";}
The function used by v8 is as follows:
void js_func_log_i(const v8::FunctionCallbackInfo
& args) { js_func_log_x(ANDROID_LOG_INFO, args);}void js_func_log_v(const v8::FunctionCallbackInfo
& args) { js_func_log_x(ANDROID_LOG_VERBOSE, args);}void js_func_log_d(const v8::FunctionCallbackInfo
& args) { js_func_log_x(ANDROID_LOG_DEBUG, args);}void js_func_log_e(const v8::FunctionCallbackInfo
& args) { js_func_log_x(ANDROID_LOG_ERROR, args);}
Now, the first experience is over.
Some important knowledge points 1. Associate an object to Isolate
There can be multiple Isolate objects. If one object is associated with Isolate, how can I find this object from Isolate?
Use Isolate's GetData/SetData
For example
JavaWrapper* JavaWrapper::fromIsolate(Isolate* isolate) { if (isolate == NULL) { return NULL; } void *data = isolate->GetData(ISOLATE_SLOT_JAVA_WRAPPER); JavaWrapper* javawrap = reinterpret_cast
(data); return javawrap && javawrap->isolate_ == isolate ? javawrap : NULL;}JavaWrapper::JavaWrapper(Isolate* isolate):isolate_(isolate){ isolate_->SetData(ISOLATE_SLOT_JAVA_WRAPPER, (void*)this);}
2. How to Get parameters of other types from v8: Value
V8: Value is a composite object. We can do this:
for (int i = 0; i < count; i++) { HandleScope handle_scope(args.GetIsolate()); Local
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); } }
For more information, see v8.h.
Okay. Come here first.