NativeScript简介
- NativeScript是一个相当新的开源开发系统,几乎完全用JavaScript创建跨平台移动应用程序,带有一些可选的CSS和XML来简化显示布局的开发。您可以在https://github.com/NativeScript 找到构成NativeScript的每个主要项目的位置。即使它是市场上的新手,它已经完全兼容Apple的iOS和谷歌的Android。 此外,还有微软的Windows Mobile。 NativeScript 使用Android上的V8引擎(由GoogleChrome和node.js使用)和iOS设备上的Apple的JavaScriptCore引擎。
-
现在,还有其他几种用于移动设备的JavaScript开发系统。 其中一些竞争对手已经建立了一段时间。其他开发系统可能有大公司在开发它们。 但这些都不会使任何其他工具成为最佳选择。NativeScript从众多其他JavaScript环境中脱颖而出的原因在于其独特的设计。其他每个JavaScript环境都需要一个特殊的桥接器或某种类型的编译扩展,它基本上将主机操作系统的一些本机功能暴露给您的JavaScript代码。其中很多实际上只是包含在应用程序shell中的Web浏览器,因此您所做的所有工作实际上都在浏览器中。如果您决定在其他产品中使用iOS手机上的蓝牙,则必须找到使用其他非JavaScript语言制作iOS蓝牙桥接器或扩展模块的人。在很多情况下,您甚至必须编译模块,然后该模块才具有您需要的所有功能。
1 例如,要找出文件是否存在,我们可以在JavaScript中调用原生Android方法: 2 var javaFile = new java.io.File('/some/file/name.ext'); 3 var exists = javaFile.exists(); 4 5 或者JavaScript中的原生iOS Objective C代码: 6 var fileManager = NSFileManager.defaultManager(); 7 var exists = fileManager.fileExistsAtPath('/some/file/name.ext');
- 由于NativeScript允许您从JavaScript代码访问完整的操作系统库和第三方库,因此您无需等待其他人创建包装器或桥接器来与iOS或Android的API任何部分进行通信。 您现在可以完全使用任何API作为一等公民,甚至可以使用任何在首次发布的新API。
-
现在,在您担心必须掌握iOS和Android来制作应用程序之前,NativeScript已经替你解决了这一点。 为简化起见,NativeScript已经拥有大量组件或模块,这些组件或模块包含了开发人员需要的最常见的东西,NativeScript称为通用核心模块。 因此,您不必像上面那样编写Android或iOS特定代码来查看文件是否存在,您只需编写以下代码即可:
1 var fs = require('file-system'); 2 var exists = fs.File.exists(path);
NativeScript文件系统模块包含了每个本机平台的API,因此您只需要写入通用接口即可。 但是,当您需要在内置模块和组件之外执行某些操作时,NativeScript是唯一允许您通过JavaScript轻松完全访问设备提供的所有内容的环境。
- NativeScript 命令行,实用程序,通用模块和组件都是用TypeScript编写的。 然后将TypeScript转换为JavaScript,然后分发给所有开发人员以供下载,安装和使用。 因此,除非您实际从NativeScript存储库中提取开源代码,否则您将看到的所有代码都是JavaScript。
- 创建通用模块是为了解决JavaScript文件使用变量和函数污染全局命名空间的问题,而另一个JavaScript文件可能会意外的覆盖。 JavaScript允许您随心所欲地重新声明或修改您的功能,这是使其如此强大的一部分。 然而,有了这么大的功能,能够很容易地也误伤自己。 然后,出现各种无头无脑的错误。 为了解决一个文件功能或变量被另一个文件覆盖的问题,开发人员提出了几种技术,这些技术演变成我们今天的通用模块格式。 您可以使用三种标准:CommonJSmodule格式,即node.js推广的格式; AMDmodule格式,专为在浏览器环境中异步解析JavaScript文件而设计; 以及全新的ECMAscript 6模块格式,在最终发布时,应该成为事实上的模块格式。 它们都包装了源代码,因此默认情况下模块中的所有代码都不会干扰全局命名空间。 NativeScript遵循CommonJSmodule格式,您可以在其中使用exports和module.export来告诉您希望向外部各方公开的模块中的代码部分。 当您看到var coolModule = require('cool-module');时,这是CommonJSmodule格式用于加载模块的语法。
安装NativeScript
- 要开始使用NativeScript,我们首先必须安装多个工具。 几乎所有内容的主要工具是nativescript命令,或者您也可以使用较短的tns别名(Telerik NativeScript的缩写)。
- 要安装nativescript命令并使其工作,必须首先安装node.js,可以从 https://nodejs. org/ 下载和安装。nativescript命令也是用TypeScript编写的,在你下载它之前已经预转换为JavaScript。 它使用node.js和其他几个常用模块来执行其所有工作。
- 一旦你安装了node.js,你只需要在终端做一个简单的npm install -g nativescript 命令,(或者在Windows上称为命令提示符窗口)。 然后npm将下载并安装所需的NativeScript代码和命令行工具。 它将全局安装它,以便可以从您正在处理的任何项目中使用它。
- 更多安装细节请移步:https://docs.nativescript.org/start/quick-setup
- 这里不在过多废话。。。这里不在过多废话。。。
NativeScript项目结构
-
根文件夹
- package.json —— 这是适用于整个应用程序的NativeScript主项目配置文件。 它基本概述了项目的基本信息和所有平台要求。 当您添加和删除任何插件或平台时,它也将由nativescriptl修改。
- app文件夹 —— 此文件夹包含您的所有代码和资源文件; 这是您将花费大部分时间的地方。 这也是您应该置源代码管理下的主文件夹,因为它应该包含您的所有应用程序代码和资源。
- lib文件夹 —— 如果您的项目需要它,那么在Android目标的构建阶段使用此文件夹; 在运行或构建Android平台的应用程序期间,Android.jar,android-support-v4.jara和nativescript.jar文件以及任何其他添加的库会自动复制到此文件夹中。 您几乎可以忽略此文件夹,因为它只是在构建期间使用。
- hooks文件夹 —— 如果您安装了任何nativescript命令增强功能的其他模块,则此文件夹由nativescript命令创建。 此文件夹将包含挂钩的源代码,因此nativescript命令知道何时以及要运行什么。 一些流行的hooks是TypeScript和Protect hooks。 在构建应用程序之前,TypeScript hook会自动将TypeScript代码编译为JavaScript。并使TypeScript成为NativeScript生态系统中的一流公民。 Protect hooks在构建应用程序之前最小化并加密所有JavaScript代码; 让你的应用程序不会被别人复制。
- node_modules文件夹 —— 此文件夹用于存储NativeScript公共核心库模块和任何已安装的插件。 它是所有JavaScript源代码插件安装后的主副本文件夹。因为相关源文件的另一个副本被放入平台目录中。 平台副本是构建系统用于实际构建应用程序的内容。如果你想看看插件是如何工作的,你安装的每个插件都会有一个子文件夹在node_modules文件夹中。
- tns-core-modules文件夹 —— tns-core-modules文件夹包含核心常见NativeScript模块的所有源代码。 这些模块是粘合剂,允许您编写适用于每个平台的通用代码。 例如,如果执行var fs = require('file-system')命令,则应用程序将加载文件系统JavaScript “tns-core-modules / file-system / fle-system.js“ 文件。此文件夹中有相应的Android和iOS版本; 它们都具有您将使用的相同界面,但它们具有与各自平台上的本机文件系统进行通信的代码。 将自动加载正确的JavaScript版本。
- platforms文件夹 —— 这是NativeScript为每个目标平台提供所有特定平台代码和库的地方,这些平台代码和库是为特定平台编译应用程序所需的。 当您执行nativescript platform add android命令时,Platforms 文件夹中将会创建一个名为Android的文件夹。 您添加的任何平台都将在Platforms文件夹中包含一个具有相同名称的子文件夹。 您基本不用管这些文件夹,因为它们几乎完全由nativescript命令处理。
- platforms/ android文件夹 —— 您可能需要访问平台文件夹中的文件的一个原因是您需要添加或更改任何Android应用程序权限或需要在应用程序的AndroidManifest.xml文件中进行的任何其他应用程序范围的更改。 AndroidManifest.xml文件位于Platforms / Android / app / src / mainfolder中。 这是构建系统使用的唯一副本。一个预防措施是,当您安装任何插件时,您应该查看AndroidManifest.xml文件以验证它没有添加任何重复的权限。 nativescript命令当前没有任何检查来验证权限是否重复。 如果您有任何重复的权限,那么下次编译或运行您的应用程序时,它可能无法启动
-
APP文件夹
- .gradle文件夹 —— 此文件夹用于gradle构建系统; 它基本上只包含在构建应用程序时使用的缓存和数据项。 您可以在首次构建应用程序时创建此文件夹。
- App_Resources文件夹 —— 此文件夹包含iOS和Android的子文件夹。 这是NativeScript目前在跨平台抽象方面没有提供太多帮助的一个领域。 每个平台都有自己的资源特性,您必须以平台期望的方式为每个平台创建资源。 例如,在iOS文件夹中,您将看到八个文件, 这些都用作iOS应用程序的启动屏幕资源。 这八个屏幕基本上是相同的图像,但只是不同的大小,分辨率或方向。 同样的事情适用于十四个不同的图标文件。 这些都是相同的图标,并且只有不同的分辨率和大小。
- fonts文件夹 —— fonts文件夹实际上并不存在,但是如果你想在你的应用程序中使用任何很酷的字体,你只需要在你的App文件夹中创建fonts文件夹并使用任何truetype字体。
- package.json文件 —— 此文件包含有关已安装的当前模板的基本信息。 当您通过nativescript create 命令创建新应用程序时,默认情况下,此文件会复制tns-template-hello-world模板项目中的所有内容。 将来,NativeScript将允许您选择模板,但是目前,这是唯一可用且有效的模板。 您可以随意修改此package.json文件,以便它与您项目的名称和项目详细信息相匹配。 除了模板文档和main 应用的文件的链接之外,这个文件目前还没有多大用处。
- app.js —— 这个文件是整个应用程序的引导文件。 在前面的package.json文件中,你可以看到package.json在main 键下指向这个文件(app.js)。 package.json文件中的这个键是NativeScript用来指定整个应用程序的入口。
- app.css —— 这是应用程序的全局CSS文件,NativeScript CSS的工作方式与Web CSS的非常接近。
- main-page.js文件 —— 这个页面的JavaScript部分可能是您花费大部分时间开发的地方,因为它包含页面的所有逻辑。 要创建页面,您通常需要一个JavaScript文件,因为您可以使用JavaScript执行所有操作,并且它是页面所有逻辑所在的位置。
- main-page.css文件 —— 这个文件实际上并不存在于我们的新应用程序中,但您可以创建它,然后它将为主页面提供CSS。 NativeScript会自动加载此文件并在其存在时应用它。
- main-page.xml文件 —— 这是最终文件,也称为主页; 它是页面布局文件。
- main-view-model.js文件 —— 最后文件是模型文件。
-
基础组件
- 应用程序组件 —— 这是整个应用程序生命周期的主要组件。此组件为我们提供的部分功能是访问所有应用程序范围的事件。通常,在应用程序中,它负责在前台和后台进行交互。
- 框架组件 —— 框架组件是控制看到哪个页面的逻辑视图。 框架组件只有几个功能和属性,因为它只用于加载新页面或返回到先前页面。 这是您通常不需要创建其实例类型的组件之一。 在这种情况下,您通常通过特殊的topmost()单例函数访问顶部框架,然后从该顶部框架对象再调用其他的框架函数。 您将使用的主要方法是 navigate(pageName),它将加载新页面,goBack()函数将返回到前一页面。 您可能经常使用的功能是函数canGoBack(),它可以返回任何更多页面,可以使用它来查找。
- 页面组件 —— 页面组件包含整个页面,并提供所有页面生命周期事件。 之前,我们探讨了构成页面的三个文件,但现在我们将查看这三个文件的实际页面组件。 页面组件的部分工作是诸如 加载(loaded),导航(navigate)和卸载(unloaded) 页面之类的事物提供事件。 如果你还记得,我们在main-page.js文件中导出了一个 onNavigatingTo()函数。 这个函数实际上与 main-page.xml 文件的 loaded 事件(event) 绑定,当加载实际的主页面时,它会从该组件中被调用。 在这种情况下,loaded 事件(event)允许我们为主页面设置模型。 由于此页面的代码现在正在运行,因此您可以使用加载的事件设置在页面开头可能还需要的任何其他逻辑,然后用户才能看到该逻辑。 此外,所有页面事件还允许您作为事件参数的一部分访问页面组件,该参数可用于配置任何其他页面组件更改。 页面组件为您管理的其他一些事件是 unloaded,navigating(进来),navigated(过来)和 showsModally。
小结
您可以访问要离开的页面和正在加载的页面。 除了Page组件提供的事件之外,它还包含一些基本属性,如实际的actionBar属性,它允许您访问 actionBar 组件及其所有函数,属性和方法。 最后,它有几个方法,比如addCss()函数,它允许你以编程方式将CSS添加到页面,还有一个showModal()函数,它允许你加载另一个页面以在当前页面上模态显示。 与所有其他可视组件一样,Page组件是View组件的后代,因此它还包含与其他View后代相同的所有View属性,方法和函数。
小练习
1.在app目录创建 settings.js 文件。敲入下面的代码。
1 //导入组件 2 //框架组件没有实例化 3 var frame = require("tns-core-modules/ui/frame"); 4 //页面组件得实例化。 5 var Page = require("tns-core-modules/ui/page").Page; 6 var StackLayout = require("tns-core-modules/ui/layouts/stack-layout").StackLayout; 7 var Label = require("tns-core-modules/ui/label").Label; 8 var Button = require("tns-core-modules/ui/button").Button; 9 10 //创建NativeScript构建页面所需的函数 11 exports.createPage = function () { 12 //创建页面组件 13 const page = new Page(); 14 const stacklayout = new StackLayout(); 15 const welcomelabel = new Label(); 16 const backbutton = new Button(); 17 18 //设置页面标题 19 page.actionBar.title = "settings"; 20 21 //设置welcome按钮 22 welcomelabel.text = "You are welcome~ settings!" 23 welcomelabel.cssType = "message" 24 25 //设置返回按钮 26 backbutton.text = "Go back!" 27 backbutton.on("tap", function () { 28 frame.topmost().goBack(); 29 }); 30 31 //把布局按钮添加到页面布局 32 stacklayout.addChild(welcomelabel); 33 stacklayout.addChild(backbutton); 34 35 //将布局放入一个页面内 36 page.content = stacklayout; 37 38 //返回页面 39 return page; 40 41 // 我想在这里提到的一件事是,如果你完全创建一个页面 42 // 以编程方式,不使用Declarative XML文件,createPage 43 // 函数必须返回Page组件。 Frame组件期待 44 // 有一个Page组件
2.修改已有的 main-view-mode.js 文件。
1 var Observable = require("data/observable").Observable; 2 var frame = require("tns-core-modules/ui/frame") //添加的代码 3 4 function getMessage(counter) { 5 frame.topmost().navigate("settings"); //添加的代码 6 if (counter <= 0) { 7 return "Hoorraaay! You unlocked the NativeScript clicker achievement!"; 8 } else { 9 return counter + " taps left"; 10 } 11 } 12 13 function HelloWorldModel() { 14 var viewModel = new Observable(); 15 viewModel.counter = 42; 16 viewModel.message = getMessage(viewModel.counter); 17 18 viewModel.onTap = function() { 19 this.counter--; 20 this.set("message", getMessage(this.counter)); 21 } 22 23 return viewModel; 24 } 25 26 exports.HelloWorldModel = HelloWorldModel;
运行后可能会发现页面直接显示新建页面,自己考虑如何能让点击事件完成后自动跳转到新页面。
自己需要理解并查看哪些是 应用组件,哪些是布局组件,哪些是页面组件,这对后边的学习非常有帮助。