ReactNative源码篇:代码调用
ReactNative源码篇:代码调用作者: 郭孝星 关于作者
关于文章
文章目录:https://github.com/guoxiaoxing/react-native-android-container/blob/master/README.md
Java与C++的交互我们都知道如果需要用Java调用C/C++,需要用到Java中的JNI,但是用过JNI的同学都知道这是个繁琐且低效的调用方式,在大型工程体现的更加明显,因为我们需要将Java与C/C++的 RN框架便有着优秀的Java与Native访问框架,这套框架的核心在于JNI智能指针,我们来详细的看一看它的实现原理。 Java对象(jobject)在Native层有3种引用类型: 全局引用 全局引用:使用NewGlobalRef创建,使用DeleteGlobalRef销毁。支持跨线程访问,在调用DeleteGlobalRef销毁前,GC无法回收该引用对应的Java Object。
局部引用 局部引用:使用NewLocalRef创建,使用DeleteLocalRef销毁。只能在本线程内安全访问,当创建该引用的Native调用链返回至JVM时,未被销毁的局部引用可以被GC回收,但是局部引用表容量有限,应该 在返回JVM前,调用DeleteLocalRef先行销毁,避免局部引用表超限引用崩溃。 弱全局引用 局部引用:使用NewWeekGlobalRef创建,使用DeleteWeekGlobalRef销毁。与全局引用一样具有全局作用域,但是不会影响GC回收,GC可以随时回收该引用。 JNI动态注册 JNI在注册Native函数时,可以利用javah命令生成函数签名,而静态注册就是利用这些函数名在JNI层中寻找着写函数,如果没有找到就会报错,如果找到了就会建立一个关联关系,以后 动态注册
函数映射表中函数的结构如下所示: typedef struct {
const char* name; //Java中Native方法的名字
const char* signature; //Java中Native方法的参数和返回值。
void* fnPtr; //函数指针,指向C函数
} JNINativeMethod;
JNI_OnLoad()函数在System.loadLibrary加载完JNI动态库后会自动调用,我们在这里完成动态注册工作,该函数有2个作用: 1 指定JNI版本,告诉虚拟机应该使用哪一个JNI版本。
2 注册Native函数,调用方法jint RegisterNatives(jclass clazz,const JNINativeMethod* methods,jint nMethods)来实现。
我们来看一个简单的例子。 1 在Java层编写本地方法 public class HelloJni {
static {
System.loadLibrary("hello-jni");
}
public static final main(String[] args){
System.out.println(stringFromJNI());
}
public native String stringFromJNI();
}
2 在JNI中进行动态注册 #include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <jni.h>
#include <assert.h>
/* This is a trivial JNI example where we use a native method * to return a new VM String. See the corresponding Java source * file located at: * * apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java */
jstring native_hello(JNIEnv* env,jobject thiz)
{
return (*env)->NewStringUTF(env,"动态注册JNI");
}
/** * 方法对应表 */
static JNINativeMethod gMethods[] = {
{"stringFromJNI","()Ljava/lang/String;",(void*)native_hello},};
/* * 为某一个类注册本地方法 */
static int registerNativeMethods(JNIEnv* env,const char* className,JNINativeMethod* gMethods,int numMethods) {
jclass clazz;
clazz = (*env)->FindClass(env,className);
if (clazz == NULL) {
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env,clazz,gMethods,numMethods) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
/* * 为所有类注册本地方法 */
static int registerNatives(JNIEnv* env) {
//指定要注册的类
const char* kClassName = "com/example/hellojni/HelloJni";
return registerNativeMethods(env,kClassName,sizeof(gMethods) / sizeof(gMethods[0]));
}
/* * System.loadLibrary("lib")时调用自动调用JNI_OnLoad * 如果成功返回JNI版本,失败返回-1 */
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm,void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
if ((*vm)->GetEnv(vm,(void**) &env,JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
assert(env != NULL);
if (!registerNatives(env)) {//注册
return -1;
}
//成功
result = JNI_VERSION_1_4;
return result;
}
JavaScript与C++的交互RN解析JS用的是Webkit的脚本引擎JavaScriptCore,JavaScriptCore负责JS的解释与执行。
JavaScriptCore API数据结构: JSGlobalContextRef:JavaScript全局上下文。也就是JavaScript的执行环境。
JSValueRef:JavaScript的一个值,可以是变量、object、函数。
JSObjectRef:JavaScript的一个object或函数。
SStringRef:JavaScript的一个字符串。
JSClassRef:JavaScript的类。
JSClassDefinition:JavaScript的类定义,使用这个结构,C、C++可以定义和注入JavaScript的类。
JavaScriptCore API主要函数: JSGlobalContextCreateJSGlobalContextRelease:创建和销毁JavaScript全局上下文。
JSContextGetGlobalObject:获取JavaScript的Global对象。
JSObjectSetPropertyJSObjectGetProperty:JavaScript对象的属性操作。
JSEvaluateScript:执行一段JS脚本。
JSClassCreate:创建一个JavaScript类。
JSObjectMake:创建一个JavaScript对象。
JSObjectCallAsFunction:调用一个JavaScript函数。
JSStringCreateWithUTF8CstringJSStringRelease:创建、销毁一个JavaScript字符串
JSValueToBooleanJSValueToNumber JSValueToStringCopy:JSValueRef转为C++类型
JSValueMakeBooleanJSValueMakeNumber JSValueMakeString:C++类型转为JSValueRef
C++调用JavaScript1 获取Global全局对象 JSGlobalContextRef context = JSGlobalContextCreate(NULL);
JSObjectRef global = JSContextGetGlobalObject(ctx);
2 获取JavaScript的全局变量、全局函数或者全局复杂对象,并完成调用。 //获取全局变量
JSStringRef varName = JSStringCreateWithUTF8CString("JavaScript变量名");
JSValueRef var = JSObjectGetProperty(ctx,globalObj,varName,NULL); JSStringRelease(varName);
//转化为C++类型
int n = JSValueToNumber(ctx,var,NULL);
//获取全局函数
JSStringRef funcName = JSStringCreateWithUTF8CString("JavaScript函数名");
JSValueRef func = JSObjectGetProperty(ctx,funcName,NULL); JSStringRelease(funcName);
//装换为函数对象
JSObjectRef funcObject = JSValueToObject(ctx,func,NULL);
//组织参数,将两个数值1和2作为两个参数
JSValueRef args[2];
args[0] = JSValueMakeNumber(ctx,1);
args[1] = JSValueMakeNumber(ctx,2);
//调用函数
JSValueRef returnValue = JSObjectCallAsFunction(ctx,funcObject,NULL,2,args,NULL);
//处理返回值
int ret = JSValueToNumber(ctx,returnValue,NULL);
//获取复杂的对象
JSStringRef objName=JSStringCreateWithUTF8CString("JavaScript复杂对象名");
JSValueRef obj = JSObjectGetProperty(ctx,objName,NULL); JSStringRelease(objName);
//装换为对象
JSObjectRef object = JSValueToObject(ctx,obj,NULL);
//获取对象的方法
JSStringRef funcObjName =JSStringCreateWithUTF8CString("JavaScript复杂对象的方法");
JSValueRef objFunc = JSObjectGetProperty(ctx,object,funcObjName,NULL); JSStringRelease(funcObjName);
//调用复杂对象的方法,这里省略了参数和返回值
JSObjectCallAsFunction(ctx,objFunc,0,NULL);
JavaScript调用C++JavaScript想要调用C++,就必须先要将C++里的变量、函数与类注入到JavaScript中。 1 定义一个C++类,在类中定义一组全局函数,并封装JavaScriptCore对C++类的调用,提供给JavaScriptCore进行CallBack回调。 class test{
public:
test(){
number=0;
};
void func(){
number++;
}
int number;
};
test g_test;//变量定义
//全局函数,封装test类的func方法调用
JSValueRef testFunc(JSContextRef ctx,JSObjectRef,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef*){
test* t =static_cast<test*>(JSObjectGetPrivate(thisObject));
t->func();
returnJSValueMakeUndefined(ctx);
}
//全局函数,封装test类的成员变量number的get操作
JSValueRef getTestNumber(JSContextRef ctx,JSObjectRefthisObject,JSStringRef,JSValueRef*){
test* t =static_cast<test*>(JSObjectGetPrivate(thisObject));
returnJSValueMakeNumber(ctx,t->number);
}
//使用一个函数,创建JavaScript类
JSClassRef createTestClass(){
//类成员变量定义,可以有多个,最后一个必须是{ 0,0 },也可以指定set操作
static JSStaticValuetestValues[] = {
{"number",getTestNumber,kJSPropertyAttributeNone },{ 0,0}
};
//类的方法定义,可以有多个,最后一个必须是{ 0,0 }
staticJSStaticFunction testFunctions[] = {
{"func",testFunc,0 }
};
//定义一个类
staticJSClassDefinition classDefinition = {
0,kJSClassAttributeNone,"test",testValues,testFunctions,0
};
//JSClassCreate执行后,就创建一个了JavaScript test类
staticJSClassRef t = JSClassCreate(&classDefinition);
return t;
}
2 创建JavaScript类 createTestClass (); JSGlobalContextRef ctx = JSGlobalContextCreate(NULL); JSObjectRef globalObj = JSContextGetGlobalObject(ctx);
3 新建一个JavaScript类对象,并使之绑定g_test变量 JSObjectRef classObj= JSObjectMake(ctx,testClass(),&g_test);
4 将新建的对象注入JavaScript中 JSStringRef objName= JSStringCreateWithUTF8CString("g_test");
JSObjectSetProperty(ctx,classObj,kJSPropertyAttributeNone,NULL);
将C++类和类指针注入到JavaScript后,在JavaScript中就可以这样使用了: “` g_test.func(); var n = g_test.number; var t = new test; ““ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |