04. WebApp2.0时代启程:跨平台的JSPatch

简介: 紧接上回,Cocos2d-JS通过JSBinding从C++API到JSAPI,完成了H5的跨平台加速,这一回,我们一起来见证一下JSPatch的跨平台实现,为JS语言增加消息转发机制,无需修改js脚本,让下面这段代码可以正确地运行起来: var controller = UIViewController.alloc().init(); 而不是让app翻译成: U

紧接上回,Cocos2d-JS通过JSBinding从C++API到JSAPI,完成了H5的跨平台加速,这一回,我们一起来见证一下JSPatch的跨平台实现,为JS语言增加消息转发机制,无需修改js脚本,让下面这段代码可以正确地运行起来:

var controller = UIViewController.alloc().init();

而不是让app翻译成:

UIViewController.__c('alloc')().__c('init')();

JSPatch依赖JavaScriptCore作为运行环境,在iOS7.0之后越来越受到终端开发者的欢迎,我们简单地分析JSPatch的技术框架和原理,来引出SpiderMonkey在Patch上的lazy加载机制:

1. JSPatch通过JS动态调用OC的代码

使用反射机制
`

    Class class = NSClassFromString("UIViewController");
    id viewController = [[class alloc] init];
    SEL selector = NSSelectorFromString("viewDidLoad");
    [viewController performSelector:selector];

`
使用runtime机制动态注册类,并添加函数
`

    Class superCls = NSClassFromString(superClassName);
    cls = objc_allocateClassPair(superCls, className.UTF8String, 0);
    objc_registerClassPair(cls);
    class_addMethod(cls, @selector(ORIGforwardInvocation:), originalForwardImp, "v@:@");

`
替换掉掉原有的实现,增加JS拦截
`

IMP originalImp = class_respondsToSelector(cls, selector) ? class_getMethodImplementation(cls, selector) : NULL;
IMP msgForwardIMP = _objc_msgForward;
class_replaceMethod(cls, selector, msgForwardIMP, typeDescription);

`
通过require增加全局变量
`

var _require = function(clsName) {
    if (!global[clsName]) {
        global[clsName] = {
        __isCls: 1,
        __clsName: clsName;
        };
    }
    return global[clsName]
}

`

修改JS脚本,通过正则替换JS的表达式:

UIView.alloc().init();
替换后
UIView.__c('alloc')().__c('init')();

2. 因为JS语言没有转发机制,无法用懒加载机制,来动态的改版语言的调用,因此,JSPatch绕了很大一个弯,使用runtime替换了Objective-C的函数,动态注册新的类和函数,新增加了一些JSAPI,尽可能的让JS的写法更贴近Native方式,降低Native开发者对JSPatch的门槛,然而并没有像wax框架一样,让脚本的写法更自然。

问题的核心是,JS能否拥有API的转发机制,通过运行时动态加载和调用,打开JSClass,查看描述信息:
screenshot

查看JSResolveOp方法的说明:
`
解决在一个Obj对象上的懒加载属性,这些属性按照需求映射在Native对象;
JS会首先在Obj上查找该属性,如果没有找到,则调用该方法解析该属性;
如果解析成功,JS引擎将再次调用Obj.ID,如果没有找到,会提交给它的父类解析;
JSNewResolveOp提供了更便宜的方式来解决延迟属性;
`

3. 我们看一下我们将采用的技术架构:

screenshot

  1. 当SpiderMonkey遇到UIVIew的时候,会触发全局global对象的属性查找,如果没有找到,交给JSResolveOp方法处理,这里我们重载的JSResolveOp方法:
bool AJContext::Resolve(JSContext *cx, HandleObject handle, HandleId handId, MutableHandleObject retval) {
    char* name = JS_EncodeStringToUTF8(cx, RootedString(cx, JSID_TO_STRING(handId)));
    Class clazz = objc_getClass(name);
    if (clazz) {
        AJContext*   nactx = (AJContext*)JS_GetContextPrivate(cx);
        RootedObject proxy(cx, JS_NewObject(cx, &AJProxy::Clazz, RootedObject(cx, nactx->prototypeProxy()), NullPtr()));
        JS_SetPrivate(proxy, new AJProxy(false, clazz));
        JS_DefinePropertyById(cx, handle, handId, proxy, 0);
        retval.set(handle.get());
    }
    return true;
}
  1. 这里我们只是使用JSObject的空的代理,我们将所有数据保存在一个Native的对象中:
class AJProxy {
public:
    void* prt;
    bool isObject;
    char* className
public:
    GetterAndSetterMethods....
}
  1. 调用对象的init方法:
bool AJProxy::NewResolve(JSContext *cx, JS::HandleObject handle, JS::HandleId handId, JS::MutableHandleObject retval) {
    const char* name = JS_EncodeStringToUTF8(cx, RootedString(cx, JSID_TO_STRING(handId)));
    fprintf(stderr, "%s\n", name);
    AJProxy* proxy = (AJProxy*)JS_GetPrivate(handle);
    if (proxy->isObject()) {
        //...处理对象方法
    }
    else {
        // ...处理类方法
        id clazz  = (id)proxy->target();
        id object = objc_msgSend(clazz, sel_registerName(name));
        AJContext*   nactx = (AJContext*)JS_GetContextPrivate(cx);
        RootedObject proxy(cx, JS_NewObject(cx, &AJProxy::Clazz, RootedObject(cx, nactx->prototypeProxy()), NullPtr()));
        JS_SetPrivate(proxy, new AJProxy(true, object));
        JS_DefineFunction(cx, handle, name, NewFunction, 0, 0);
        retval.set(handle.get());
    }
    return true;
}

4. 至此,一个跨平台的JSPatch的Demo写完了。

需要补充的地方也很多,比如继承、类型转换等,作者很喜欢SpiderMonkey、C++,这种兼容iOS和Android的事情,还需要很多很多的工作。
这里我们主要讲得时SpiderMonkey,通过这个小巧的JsVM,我们可以重新改写很多JS的不擅长的地方,毕竟js的开发者要比lua、wax、swift多很多。
相信不需要多久,就会有人写出跨平台的JSPatch,使用JS开发的同学会越来越多。

(总结)想要了解的更多,就要深入底层,下一站,我们带来OpenGL ES2.0 与JS的混合开发。

目录
相关文章
|
移动开发 JavaScript Java
08. WebApp2.0时代启程:倒立者赢,NativePixi,所见即所得的开发方式
紧接上文,在终端设备中,不管是游戏引擎还是UIKit,图形图像都是基于跨平台的OpenGL ES技术,区分不同的场景,图形图像分为两个分支,一个以高性能的图形显示为目标的cocos2d-x引擎,一个是以省电节能适合App的UIKit框架。 ####一)今天我们继续逆向思维 Game VS App,既然都是基于OpenGL ES,那我们找出共同点,是否可以让二者的界限,变得更模糊?既
2365 0
|
移动开发 JavaScript 前端开发
01. WebApp2.0时代启程:Cocos2d-JS详解(一)
(一)WebApp时代,追求App开发效率的同时,我们也要求终端的体验和性能,2/8原则可以很好的阐述当前的hybird开发方式:20%的Native代码+80%的H5代码。 ![5a96ccb3abc157b98a67b7bcfa8c2e9d](http://img2.tbcdn.cn/L1/461/1/f0fe01c8c83bbc680afd4e785eb21e53d3367bc5) (二
4038 0
|
Web App开发 JavaScript Java
02. WebApp2.0时代启程:Cocos2d-JS为什么选择SpiderMonkey(二)
紧接上文,cocos2d-JS为我们提供了图形引擎、物理引擎、JS引擎等基础库,在多终端时代提供了非常nice的游戏引擎,在浏览器普及在各个终端的今天,为什么还要单独搞一套JS引擎呢? 1. 我们先看看使用SpiderMonkey的技术产品有哪些? ![screenshot](http://img1.tbcdn.cn/L1/461/1/aec02fdece92d563ae07a7dc0c0
4117 0
|
Web App开发 JavaScript Java
03. WebApp2.0时代启程:Cocos2d-JS让C++代码支持JS脚本(三)
紧接上文,JS在单线程下,性能不会比Java差,注意场景是单线程。Java的优势不仅是高级语言的特性,还具备了丰富的系统内核资源,如多线程、网络等支持,要比JS灵活的多很多,这里暂时不在讨论这些问题。 回到主题,如果我们把一个完整的C++图形引擎注入到SpiderMonkey中,把复杂的预算放到C/C++内核中,而JS只作为业务处理和内存管理,是否可以获得C/C++的运行能力,有获得了良好的
3377 0
|
Web App开发 新零售 移动开发
05. WebApp2.0时代启程:倒立者赢,从过去到现在的变化,看将来的发展(一)
####1. 移动互联网的兴起,我认为2009年是个分水岭。 开始的时候,我也是做Java开发,习惯了Webx架构,可以熟练的使用Spring、iBatis、veloctiy、HSF、Notify、Tair、Session这些阿里具有代表性的Java框架,也会使用IC、UIC、SC、DC等等服务集群做电商核心业务。 概括起来,基本也是三层服务端架构: ![screenshot](http:/
2113 0
|
Java 测试技术 Android开发
06. WebApp2.0时代启程:倒立者赢,跨平台技术离我们很近
紧接上文,我们提到移动互联网时代,前端的成本重复而臃肿,后端开发基本稳定,作为商业公司:利润和成本使我们不断追求的目标。这里我们从跨平台的角度,来看待如何降低成本。 ####1. 首先我们看一段视频: 3个平台:浏览器、Android、iOS,一套JS代码,运行在不同设备上【注意,终端展示没有用WebView相关容器】 ![screenshot](http://img4.tbcd
2074 0
|
缓存 Android开发 iOS开发
07. WebApp2.0时代启程:倒立者赢,从CPU到GPU,一张图片的旅行
紧接上文,终端开发使用的WindVane、wax、ReactNative等已经是一种跨平台的技术,我们称之为上层跨平台,Cocos2d-x这种直接使用C/C++,我们成为底层跨平台。上层跨平台,提升开发效率;下层跨平台,提升程序性能。 ####1. 为什么Cocos2d-x性能比Native开发要好? 因为Cocos2d-X是游戏引擎呗,人家是专业做游戏特效的好不好,直接调用GPU的Ope
2726 0
|
前端开发 JavaScript Java
09. WebApp2.0时代启程:倒立者赢,挑战Android性能极限
紧接上文,在终端硬件资源有限的大背景下,业务脚本+图形内核,将是未来主流的开发方式。AEPixi使用C/C++、JS、JNI、OC等混合语言开发,将pixi.js变成高性能的Native内核,提供上层pixi.js标准的API,无缝的兼容浏览器开发好的代码,实现浏览器开发,无需编译,到处运行的开发方式。 今天我们做一个H5的Demo,使用FireFox开发,开发完成之后,直接使用上一
2329 0
|
移动开发 JavaScript 前端开发
用开发本地tcpip程序的思路开发webapp
本文关键字:the headless cms,b/s web to c/s web, headless webapp backend.
469 0
用开发本地tcpip程序的思路开发webapp
|
Web App开发 监控 Serverless
十分钟上线-基于函数计算开发 Restful web api & asp.net core web app
.NET Core是一个开源通用的开发框架,支持跨平台, 阿里云函数计算推出了 dotnetcore2.1 runtime, 使用 C# 编写 serverless 函数, 除了很好地支持通常意义上的函数外, 还可以基于函数计算开发 asp.
5733 0