NativeScript工作规律

NativeScript是一个runtime,它提供一些建制好行使JavaScript构建原生的IOS、Android甚至WP(未来会加入)应用。NativeScript有不少老非常的作用,比如MVVM和CSS渲染原生UI。但是NativeScript最令人兴奋的是它们一旦JavaScript可以直接调用native
API。

顿时任起可见面令人困惑,首先看一个例子,下面是利用NativeScript编写Android
app的一致截代码:

var time = new android.text.format.Time();
time.set( 1, 0, 2015 );
console.log( time.format( "%D" ) ); //01/01/15

上述的JavaScript代码实例化了一个Java对象android.text.format.Time,调用它的set方法和format方法而以控制高出口log。

俺们先行不说明上述代码的落实原理,再看一个运用NativeScript编写IOS
app的事例:

var alert = new UIAlertView();
alert.message = "Hello world!";
alert.addButtonWithTitle( "OK" );
alert.show();

上述的JavaScript代码实例化了一个Objective-C类UIAlertView,随后为它们的message特性赋值,调用了addButtonWithTitle方法和show方法,运行效果使下图:
图片 1

NativeScript并非就包含JavaScript化的Objective-C和Java代码,还聚集了相同多样的跨平台module,比如发送http请求、构建UI组件等等。大部分app都待调用原生的API,NativeScript的runtime简化了原生API的调用方式。

马上句话可以这样明白,Objective-C和Java也需调用原生API并且调用方式存在差别,NativeScript削减了差异化,令原生API的调用方式更是简明统一。

脚我们看看NativeScript的干活规律。

1. NativeScript runtime

虽NativeScript的代码看起十分神奇,但是中的劳作规律其实挺简短。NativeScript本质上依然是JavaScript,解析执行JavaScript的当然是JavaScript引擎。在不同之阳台,NativeScript使用平台默认的JavaScript引擎,比如Android平台的V8引擎、IOS平台的JavaScriptCore。既然用JavaScript引擎解析代码,那么具有的native
API的调用语法必须写成规范之JavaScript语法,这样才可以被JavaScript引擎成功解析。

NativeScript使用的凡流行稳定版本的V8和JavaScriptCore。因此,NativeScript对ECMAScript规范的支持情况跟它们采取JavaScript的引擎完全相同。也就是说,Android平台因V8对ECMAScript规范之兑现程度,IOS依赖JavaScriptCore对ECMAScript规范的贯彻程度。

天天谨记NativeScript是依赖JavaScript引擎这无异接触大重要。

咱俩再度看率先独例中的首先实行代码:

var time = new android.text.format.Time();

于Android平台,上述NativeScript代码由V8及时编译(JIT
Compiled)并履行。对于简易的表达式(比如var x = 1 + 2),我们很容易了解是怎么工作之。但是V8是怎么样识别android.text.format.Time的呢?

2. NativeScript哪些操作JavaScript引擎

V8之所以能分辨android靶是出于NativeScript
runtime把她注入到了JavaScript运行环境受到。V8提供了大量的API供应使用者配置个性化的JavaScript运行条件,甚至好注入C++代码用来统计JavaScript的CPU使用状态、管理JavaScript的GC等等。
图片 2

在这些API当中,有些Context类似可供操作全局作用域的API,这就是NativeScript之所以能当全局意图域内注入android靶的规律。这种规律其实和Node.js全局方法(比如require())的实现原理同。IOS的JavaScriptCore引擎也供了仿佛的编制。

俺们重回想一下事先的代码:

var time = new android.text.format.Time();

今咱们理解了当时段代码运行在V8上,并且V8可以辨认android.text.format.Time()大凡坐NativeScript在全局意图域内注入了android对象。但是仍然有成千上万问号尚未缓解,比如NativeScript如何晓得要注入哪些API?NativeScript如何了解调用Time()见面产生什么效益?

下面我们逐个解决这些疑问。

3. Metadata(元数据)

NativeScript通过reflection(反射)来构建它所运行平台的可用API。不熟悉其他编程语言的JavaScript开发者可能并无了解reflection,JavaScript是一模一样流派大自由之言语,并不需要reflection。但是当旁编程语言中,尤其是Java,reflection是以runtime时得有class详细信息的唯一路径。

得省略的把reflection理解吧以runtime(运行时)而未是编译期获取有object或class完整结构的门径。reflection的事无巨细介绍谢兴趣的得参见这里)。

NativeScript使用reflection构建了适用于各个平台的API列表。从性质角度来讲,生成这些API数据是雅有必要的,NativeScript在编译之前生成这些多少,然后以Android/IOS编译阶段嵌入已成形的初数据。

询问了以上机制下,我们更回想一下事先的代码:

var time = new android.text.format.Time();

如今咱们了解了以上代码用会在V8上运行,使坐NativeScript注入了android.text.format.Time对象。NativeScript通过一个独自的首届数据处理过程中显然了索要注入的API,并且以Android和IOS的编译阶段嵌入了所用的头版数据。

好,我们后续解答下一个题材:NativeScript是怎么用JavaScript的Time()调用映射到原生的android.text.format.Time()调用呢?

4. 原生代码的招机制

NativeScript唤起原生代码调用同样凭借于JavaScript引擎的API。上文提到了NativeScript如何对V8引擎注入全局变量,接下去介绍如何通过回调函数实现以JavaScript代码中调用C++代码。

遵照当履行new android.text.format.Time()立即段代码,V8引擎将见面来一个转调函数。利用这种体制,NativeScript可以监听JavaScript函数的调用,并且在V8扭曲调函数里实行C++代码,从而实现原生代码的调用。

这里涉及的反过来调函数连无是JavaScript的回调函数,而是V8引擎内部的C++函数。V8解析执行JavaScript函数时首先将JavaScript函数映射为C++函数,然后再实行。

Android平台下,NativeScript的C++代码不可知直接调用Java的API(比如android.text.format.Time)。这种情景下用借助Android平台的JNI(Java
Native
Interface,Java本地接口)实现C++与Java的桥接。借助于JNI,NativeScript便得以调用Android平台的原本生Java
API。

IOS平台并不需要类似JNI的桥接机制,因为C++可以一直唤起Objective-C的调用。

刺探了上述机制,我们再度回首一下前的代码:

var time = new android.text.format.Time();

上文的叙述中,我们了解以上代码可以尽之原理是NativeScript通过单独的正负数据变化过程注入了JavaScript引擎android全局对象。然后在实践Time()函数时,依次有了以下行为:

  1. V8回调函数执行;
  2. NativeScript
    runtime通过长数据显然Time()的行是实例化native对象android.text.format.Time
  3. NativeScript
    runtime通过JNI实例化android.text.format.Time靶又维持对这目标的援;
  4. NativeScript
    runtime返回一个JavaScript对象用来代理Java本地对象android.text.format.Time
  5. 回去JavaScript运行条件受到,第4步回去的代办对象囤于地面转移了time中。

此处涉及的代理对象凡NativeScript用来维持JavaScript对象与native对象的照关系(mapping)。比如执行为下JavaScript代码:

var time = new android.text.format.Time();
time.set( 1, 0, 2015 );

冲变化的首家数据,NativeScript知道代理对象time的所用API。按照上述手续,当调用JavaScript函数Time()时,V8执行相应之回调函数,NativeScript监测到函数的调用,便由此JNI唤起Java的Time目标的调用。

上述就是是NativeScript的办事原理。

至于如何用Objective-C对象与Java对象映射为JavaScript对象,这有些干活非常复杂,因为要考虑到各个种编程语言实现连续模式之别。感兴趣之好参照IOS的贯彻方案和Android的落实方案。

经过以上内容,虽然咱解了哪些下JavaScript代码调用原生API,但是要是对每个不同平台都分别编制对应的代码,仍然未克落实“write
once,run
anywhere”。为了贯彻此目标,NativeScript提供了一如既往种植十分强劲的功用:NativeScript
modules

5. NativeScript modules

NativeScript modules的原理和Node
Modules的规律类似,同样仍CommonJS规范,如果您熟悉Node中require()exports的办事原理,那么NativeScript
modules对你吧就是非常容易入手了。

NativeScript
modules把各国平台专有的API封装成与平台无关的API(类似大家熟知的JavaScript各种兼容性工厂函数)。比如现在我们得调用各平台的file
API,针对Android平台的代码如下:

new java.io.File( path );

对IOS平台的代码 如下:

NSFileManager.defaultManager();
fileManager.createFileAtPathContentsAttributes( path );

凡是未是大麻烦?但是若运用NativeScript file-system
module,你只有待利用统一之API:

var fs = require( "file-system" );
var file = new fs.File( path );

一经您既掌握了本文提到的NativeScript工作规律,便足以非常易之编NativeScript
Module。比如要修一个module来博装备OS的版:

// device.ios.js
module.exports = {
    version: UIDevice.currentDevice().systemVersion
}

// device.android.js
module.exports = {
    version: android.os.Build.VERSION.RELEASE
}

调用上述Module的法子同调用npm模块相同,使用require()如下:

var device = require( "./device" );
console.log( device.version );

NativeScript
Module降低了web开发者开发native应用之秘诀,即使你不熟识native
API,也可以花费好少之年华读书各平台的API文档,然后编写一个NativeScript
Module来增加后续之支出效率。

6. 总结

本文简单介绍了NativeScript的干活规律,总结如下:

  1. 透过reflection获取native
    API的详实结构,并生成元数据。这些表现都是以runtime中JIT编译;
  2. 据悉变化的老大数据信息,NativeScript利用JavaScript引擎的callback机制向JavaScript运行条件被流入需要的JavaScript全局对象。这些全局对象本质上是native对象的代办对象;
  3. 通过NativeScript Modules统一API。

深深上资料:

  • UI Layout机制;
  • UI组件。