OurJS


OurJS-我们的JS, 我们的技术-IT文摘; 专注JS相关领域;
我们热爱编程, 我们热爱技术;我们是高大上, 有品味的码农;

欢迎您订阅我们的技术周刊


我们会向您分享我们精心收集整理的,最新的行业资讯,技术动态,外文翻译,热点文章;
我们使用第三方邮件列表向您推送,我们不保存您的任何个人资料,注重您的隐私,您可以随时退订,

欢迎分享您的观点,经验,技巧,心得

让我们一起找寻程序员的快乐,探索技术, 发现IT人生的乐趣;


本网站使用缓存技术每次加载仅需很小流量, 可在手机中流畅浏览;
如果您发现任何BUG,请即时告知我们: ourjs(at)ourjs.com

NativeScript的工作原理:用JavaScript调用原生API实现跨平台


分享到
分类 技术前沿   关键字 JavaScript   发布 ourjs  1426143477762
注意 转载须保留原文链接,译文链接,作者译者等信息。  
注* NativeScript是最近推出的一个跨平台解决方案,可以让你可以用JavaScript来直接写Android、iOS本地应用程序,未来还即将扩展到Windows平台。是最近比较受关注的项目。它与nw (原名node-webkit ,用Web写winodw/linux桌面应用)和phonegap内嵌webview写APP的实现方式有着本质的不同,它直接用JavaScript调用系统原生API,因而有一些原生应用的特点。

NativeScript


NativeScript是一个运行环境,可以让你使用通用的JavaScript代码,打造原生的iOS,Android和Windows(即将推出)应用程序。 NativeScript有很多很酷的功能,比如支持JavaScript对象双向绑定到原生UI组件,以及用CSS为原生应用程序写样式。但我最喜欢的功能是NativeScript可以让您直接访问本地平台的原生API。

注* 可以理解为NativeScript是一个JavaScript V8运行环境的命令转发代理,将JavaScript调用转发给不同平台上的原生API如Android、iOS,以及即将支持的Windows。

例如,看看这个NativeScript写的Android应用程序的代码:

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

你只需要一两分钟来分析一下就明白了,这段JavaScript代码实例化一个Java android.text.format.Time()对象,调用其set()方法,然后打印format后的返回值,是字符串“01/01/15”。

我知道你已经很激动了,先不要慌,让我们再来看看iOS的代码:

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

这段JavaScript代码实例化一个Objective-C UIAlertView类,设置它的信息属性,然后调用它的addButtonWithTitle()和show()方法。当您运行这段代码,你会看到hello word的警告框。

NativeScript运行时


该NativeScript运行环境看起来可能像变魔术一样,不管你信不信,该架构并不是那么的复杂。一切从JavaScript虚拟机开始,NativeScript从这里开始执行JavaScript指令。具体来说,NativeScript在Android采用v8;在iOS上采用JavaScriptCore。由于NativeScript使用JavaScript虚拟机,你访问原生API的所有JavaScript代码,仍然需要遵守JavaScript的语法结构和规范。

一般来说,NativeScript会同时采用V8和JavaScriptCore的最新稳定版;因此NativeScript对ECMAScript语言的支持在iOS的桌面Safari上面几乎是相同的,并且NativeScript在Android上面也几乎与桌面浏览器相同。包括一些ES6的新语法。

了解NativeScript使用了JavaScript虚拟机是很重要的,但这只是实现的第一步,让我们来看看上文示例的第一行代码:

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

在NativeScript Android运行环境中,该代码会被编译(JIT)并在V8中执行。这我们可能会很容易理解变...:

var x = 1 + 2;

但是接下来的问题是...V8怎么知道什么是android.text.format.Time()呢?

我们将重点讲V8和Android的实现,基本架构模式同样适用于iOS上的JavaScriptCore。如果出现显着差别,本文会提到。

这里将不讨论NativeScript在Windows上的实现细节,因为解决方案可能还会变,但是,当前的Windows实现跟iOS上的JavaScriptCore运行原理几乎一样。


NativeScript是怎样管理JavaScript虚拟机的


V8知道android是什么,因为NativeScript在运行时进行了注入,因为V8拥有一堆让你配置JavaScript环境的API。在JavaScript中您可以使用自定义的C++代码来分析CPU使用率,管理的JavaScript垃圾收集,等等一大堆API

面对这些API的是几个“Context”类,可以让你操纵全局变量,从而有可能为NativeScript注入一个全局的android对象。这实际上使用了与Node.js的相同运行机制,使全局API可用 - 如 require() - NativeScript使用它注入可以让你访问本地代码的API。 JavaScriptCore的也有类似的机制。酷吧?

让我们回到我们的代码:

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

现在你知道这个代码在V8中运行时,而V8已经知道什么是android.text.format.Time()了,因为NativeScript注入了必需的对象到全局范围。但仍存在着一些大的悬而未决的问题,如何让NativeScript明白那些注入的API到底是干什么的,然后调用?

Metadata(元数据)


对于NativeScript,反射是让NativeScript可以调用每个平台上的API的基石。包括android.text.format.Time。因为从性能角度来看重构这些API是很困难的,NativeScript会提前做掉这些,并在Android/iOS预编绎过程中嵌入预先生成的元数据。

考虑到这一点,让我们再次回到我们的代码:

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

现在你了解了这个V8代码是这样运行的,即NativeScript注入了android.text.format.Time的JavaScript对象,通过每一个单独的元数据注入。下一个问题:如何将NativeScript里的JavaScript调用Time()转发到本机android.text.format.Time()?

调用本地代码


NativeScript如何调用本机代码的答案就在于JavaScript虚拟机的API。我们上次使用V8的API是注入全局变量。这一次,我们将着眼于在JavaScript回调中调用给定的C++代码。

例如,JavaScript函数调用的代码 new android.text.format.Time(),V8会产生一个回调。也就是说V8有一个回调,让NativeScript拦截函数调用,然后用自定义的C ++代码执行一些动作,并返回一​​个新的结果。

在Android中的情​​况下,NativeScript运行的C++代码不能直接访问Java API,如android.text.format.Time。然而,Android的JNI ,或Java本地接口,提供了C++和Java之间的桥接能力,所以NativeScript使用JNI完成转发。在iOS中这个桥梁是不必要的,因为C++代码可以直接调用Objective-C的API。

了解了这些,让我们再回到代码:

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

我们已经知道,这个代码在V8中运行;是因为NativeScript注入过对象,它知道什么是android.text.format.Time;并且NativeScript中有这些基于元数据生成的API。我们现在知道,当 Timer() 执行时,会发生下面的事情:

1)V8运行回调函数。
2)NativeScript运行时通过它的元数据知道,Time()调用需要实例化一个android.text.format.Time对象。
3)NativeScript运行时使用JNI来实例化一个android.text.format.Time对象并保持对它的引用。
4)NativeScript运行时将代理的Java Time对象转化成JavaScript对象返回。
5)控制返回的JavaScript代理对象为被存储起来的本地时间变量。

代理对象是在NativeScript中保持JavaScript对象与本地平台对象的人工映射。例如,让我们来看看前面代码的下一行:

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

基于所生成的元数据,NativeScript知道代理对象上的所有方法。在这种情况下,代码调用Timer对象的set()方法时。此方法会再次调用V8及其功能回调; 然后NativeScript通过Android JNI转发到Java时间对象上相应的方法调用。

这就是NativeScript在部分的工作原理。酷吧?

现在,还遗留下了一些非常复杂的部分,因为将Objective-C和Java对象转换成JavaScript对象可能会很麻烦,尤其是考虑到不同的继承类型语言时。

我们不打算深入探讨这些问题的细节,NativeScript的另一个特点让你不必深入到本地代码,比如:TNS模块。


TNS Modules


TNS modules是Telerik NativeScript modules的简写。跟Node模块一样,它同样使用CommonJS。因此如果你已经会用require()和exports对象,那么你就已经掌握了TNS模块。

TNS模块允许你将特定的本地调用抽象成平台无关的API,NativeScript本身提供了几十个这样的模块供您使用。举个例子,假设您需要在您的iOS / Android应用程序创建的文件。你可能在Android中要写以下代码:

new java.io.File( path );

同样在iOS里写下面的代码:

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

但是如果你使用TNS文件系统模块,你的代码将是一样的,而不必担心的iOS / Android的内部实现细节:

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

更酷的是,你可以自己写TNS模块。比如这里有一个TNS模块,检索设备的操作系统版本:

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

// device.android.js
module.exports = {
    version: android.os.Build.VERSION.RELEASE
}
此代码只检索一个版本属性,但它给你多少灵感?使用自定义TNS模块是微不足道的,跟在nodejs中使用NPM模块一样:

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

如果你已经熟悉了npm的使用,NativeScript模块非常容易编写,分发和使用。就个人而言,作为一个Web开发人员,原生的iOS和Android代码让我害怕,尤其是当Java / Objective-C的API文档扔在一起的功能,它降低了我们跨平台开发的障碍。


原文地址: 点此
社区评论 ( Beta版 )
OnceDoc 您自己的企业内容管理系统——文档、流程、知识库、报表、网盘All In One

访问404页面,寻找丢失儿童
 热门文章 - 分享最多
  1. 将BootstrapJS和AngularJS结合使用以及为什么不用jQuery
  2. 让我们写快速的JavaScript,JS性能优化小窍门
  3. CSS Sprite小图片自动合并工具(NodeJS,Python,Java,Ruby)
  4. Session劫持与Session-ID的安全长度
  5. 用原生HTML5控件实现输入框自动提示(下拉列表补全)功能
  6. 使用Node.JS监听文件夹变化
  7. 我为什么不再用Compass写CSS(缺点分析)
  8. 微软博客:Angular 2将基于TypeScript
  9. 微软,IBM,ARM等大公司先后加入对Node.js/io.js的支持
  10. 使用Google Analytics跟踪捕获JavaScript,AngularJS,jQuery的在线错误和异常
  11. AirJD-简单好用的免费建站工具

 相关阅读 - 技术前沿
  1. 微软博客:Angular 2将基于TypeScript
  2. 专为控制打印设计的CSS样式
  3. 什么是Viewport Meta(width详解)及在手机上的应用
  4. io.js新支持的ECMAScript 6功能特性详解
  5. NodeJS连接Redis:安装及开机自动启动设置
  6. Duktape:一个新的小巧的超精简可嵌入式JavaScript引擎
  7. HTML5的TCP和UDP Web Socket API草案定稿
  8. SpiderMonkey的JavaScript引擎[Firefox]性能超越V8[Chrome]
  9. 基于 Web 的 Go 语言 IDE
  10. Nginx的大计划:将原生支持JavaScript

 关键字 - JavaScript
  1. JavaScript中的继承,构造函数以及new关键字的作用
  2. 纽约时报使用Html5 WebRTC记录访问者IP地址
  3. 正则中test、exec、match的简单区别,以及括号的用法
  4. NativeScript的工作原理:用JavaScript调用原生API实现跨平台
  5. 2015年的JavaScript:Angular之类的框架将被库取代
  6. 少年,不要滥用箭头函数啊:JS中lambda表达式的优缺点和使用场景
  7. JavaScript中NaN的秘密
  8. 如何用CSS将select/option文本居中或居右对齐
  9. 什么是Ajax? 详解原生js ajax
  10. 用原生HTML5控件实现输入框自动提示(下拉列表补全)功能

 欢迎订阅 - 技术周刊

我们热爱编程, 我们热爱技术; 我们是高端, 大气, 上档次, 有品味, 时刻需要和国际接轨的码农; 欢迎您订阅我们的技术周刊; 您只需要在右上角输入您的邮箱即可; 我们注重您的隐私,您可以随时退订.
加入我们吧! 让我们一起找寻码农的快乐,探索技术, 发现IT人生的乐趣;


 关注我们

我们的微信公众号: ourjs-com
打开微信扫一扫即可关注我们:
IT文摘-程序员(码农)技术周刊

ourjs官方微信号