NW.js开发环境搭建

NW.js开发环境搭建

文章目录

    • NW.js开发环境搭建
      • 简介:NW.js是什么?
      • 1. 选择Build Flavors SDK
      • 2. 下载安装NWJS
      • 3. 创建第一个应用
      • 4. 运行应用
      • 5. 打包应用
      • 6. APIs
      • 扩展
        • 1. 配置文件(package.json)
        • 2. 使用NW.js APIs
        • 3. 使用Node.js API(`require`)
        • 4. 开发工具与调试
        • 5. NW.js中独立环境和混合环境模式
          • 5.1 独立环境模式
            • 5.1.1 浏览器环境
            • 5.1.2 Node环境
          • 5.2 混合环境模式
          • 5.3 混合环境模式和独立环境模式对比
        • 6. JavaScript源码保护
        • 7. 应用签名
        • 7. 自动更新
        • 8. Node.js 自定义模块
        • 9. ES6与NodeJS模块导入导出区别
          • NodeJs
          • ES6
        • 10. [ES6 入门教程](https://es6.ruanyifeng.com/)

简介:NW.js是什么?

NW.js基于Chromium和Node.js。它使您可以直接从浏览器中调用Node.js代码和模块,也可以在应用程序中使用Web技术。此外,您可以轻松地将Web应用程序打包到本机应用程序。

NW.js官网

NW.js中文网

1. 选择Build Flavors SDK

NW.js支持各种构建样式以减小应用程序大小。当前,NW.js支持以下构建风格:

  • SDK风格(SDK):内置了对DevTools和NaCl插件的支持。SDK风味与0.13.0之前的版本具有相同的功能(适用于开发调试环境);
  • 正常风格(Normal):是不带DevTools和NaCl插件支持的最低版本(适用于发布环境)。

建议您选择SDK构建风格来开发应用程序,这使您可以使用DevTools调试应用程序。

2. 下载安装NWJS

对于国内用户,如果下载连接下载速度太慢的话,可以考虑的可选项是:

  • 淘宝NPM镜像
  • 百度网盘链接,提取码为: ivh3

或者进入官网下载根据自己需要下载对应的版(我这里下载的是mac版本的v0.44.5,osx-x64,normal
v0.44.5,osx-x64,sdk

  • 下载后直接解压,将nwjs.app拖到应用程序中(便于从桌面点击图标启动)
    <img

  • 设置别名和环境变量(以便从命令行可直接启动)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #打开bash_profile环境变量配置文件
    vim ~/.bash_profile

    #设置环境变量-nwjs的别名
    alias nw="/Applications/nwjs.app/Contents/MacOS/nwjs"

    #应用环境变量
    source ~/.bash_profile

    #命令行输入nw 回车启动即可(等同于桌面点击图标启动)
    nw

    启动后如下如:
    在这里插入图片描述

3. 创建第一个应用

  • 创建package.json文件

    通过node.js初始化一个项目(首先,确保你已经安装好了node.js的环境),生成package.json文件,package.json是JSON 格式格式的配置文件. main 属性定义了应用首页, 如本例的 "index.html". name则定义了应用名称. 具体查看 配置文件章节.

    1
    2
    3
    4
    5
    6
    #创建项目目录
    mkdir NWDemo
    #进入项目根目录
    cd NWDemo
    #执行初始化生成package.json
    npm init

    package.json

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {
      "name": "test1",
      "version": "1.0.0",
      "description": "",
      "main": "index.html",
      "scripts": {
        "test": "echo "Error: no test specified" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }

    您可以将 "main"属性设置如 "main.js"的js文件. 该文件在应用启动时默认不打开窗口并在后台执行。 您可以稍后进行一些初始化并手动打开窗口。 例如:

    1
    2
    // 初始化你的应用程序之后 ...
    nw.Window.open('index.html', {}, function(win) {});
  • 创建入口页面index.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <!DOCTYPE html>
    <html>
      <head>
        <title>Hello World!</title>
      </head>
      <body>
        <h1>Hello World!</h1>
      </body>
    </html>

4. 运行应用

进入我们创建的项目中,执行nw . 运行当前应用(nw .是NW.js执行文件)

  • Windows系统中是 nw.exe;
  • Linux系统中是 nw;
  • Mac系统中是 nwjs.app/Contents/MacOS/nwjs;
1
2
3
4
#进入项目根目录
cd NWDemo
#运行
nw .

【注意】

Windows系统中 , 可拖拽包含 package.json的文件夹至 nw.exe直接运行应用。

5. 打包应用

可以使用以下工具自动完成打包NW.js应用进行发布 .

  • nwjs-builder-phoenix (推荐:用于为Windows,macOS和Linux构建和打包可分发的NW.js应用程序。)
  • nw-builder

或者可以使用以下步骤手动构建应用 ,具体步骤参考手动构建应用

这里使用nwjs-builder-phoenix构建方式详细使用参见github

6. APIs

详细使用参见地址

扩展

1. 配置文件(package.json)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
{
  "name": "nw-demo",       #应用名称,应确保该字段内容全局唯一性
  "main": "index.html",      #应用起始页
  "nodejs":true,                     #是否支持Node
  "node-main":"xxxx",            #指定Node.js脚本文件路径并且它将在加载DOM窗口之前启动Node环境时执行
  "domain":"xxxx",               #指定主机域名
  "single-instance":false, #是否以单实例运行(false则允许应用多开,默认 true)
  "bg-script":"xxxx",      #应用启动时执行的后台脚本
  /**
   *窗体样式控制(窗口子字段默认情况被继承到使用 window.open()或 <a target="_blank">打开的子窗口
   *未继承子字段将被设置为打开窗口时的默认值)
   *列表如下:
     *  fullscreen -> false
     *  kiosk -> false
     *  position -> null
     *  resizable -> true
     *  show -> true
   */
  "window":{                         
     "id":"xxx",           #内含窗口尺寸与位置的状态的窗口ID,打开同ID的窗口时会还原该状态
     "title":"xxx",        #NW.js创建的窗口标题 . 在应用启动时显示的标题信息
     "width":200,          #窗口宽高
     "height":200,         #窗口高
     "toolbar":true,       #是否显示导航栏中的工具条
     "icon":"xxxx",        #窗口图标路径
     "position":"xxx",     #窗口位置:默认 null(不固定) , center(屏幕居中) , mouse(鼠标所在位置)
     "min_width":100,      #窗口最小宽高
     "min_height":100,
     "max_width":500,      #窗口最大宽高
     "max_height":500,
     "as_desktopLinux":false, #X11环境下,作为桌面背景显示(true显示, false不显示)
 
     "resizable":true,        #是否可调整窗口大小(在OS X上将该属性设置为 false,并将frame设置true,
                              #用户还是可以将窗口全屏显示。只有将全屏也设置为 false才可禁用全屏控件。
 
     "always_on_top":false,   #是否允许窗口始终置顶(在其余窗口之上,true允许, false不允许)
 
     "visible_on_all_workspaces Mac & Linux",: #支持多工作区的系统(如Mac & Linux)中,将窗口同时显示
                                                                                         #在所有工作区中(true允许, false不允许)
 
     "fullscreen":false,      #是否允许窗口全屏(窗体和全屏框架(frame)应当一致,窗口设置为 false时,
                              #则全屏框架(frame)不应设为 true,避免窗体将阻止鼠标获取屏幕边缘)
 
     "frame":true,            #窗口是否为框架(窗体和全屏框架应当一致,窗口设置为 false时,则全屏框架
                              #不应设为 true,避免窗体将阻止鼠标获取屏幕边缘.)
 
     "show_in_taskbar":true,  #是否允许显示在任务栏或停靠栏中(true允许, false不允许,默认 true)
     "show":true,                       #启动时是否显示应用(true显示, false不显示)
 
     "kiosk":true,                  #是否使用 Kiosk模式(该模式即应用将全屏并阻止用户离开(关闭)应用,比如常见
                                                    #的公共触摸屏演示,银行排队取票机洁界面,直到页面返回响应)   
 
     "transparent":false,     #窗口是否透明(true允许, false不允许,默认 false)
                              #窗口的透明度由CSS中的背景透明值控制,
                                                            #使用命令行参数 --disable-transparency 可完全禁止透明功能.
                                                            #使用命令行参数 --disable-gpu 禁用GPU后,可实现透明窗体的穿透点击
            },
  /**
   *WebKit特性控制
   */
  "webkit":{
    "double_tap_to_zoom_enabled":false,  #是否启用两指缩放功能(true允许, false不允许,默认 false)
    "plugin":true,             #是否可加载扩展插件,比如Flash插件(true允许, false不允许,默认 true),
    },

  "user-agent":"xxx",         #重写应用请求页面中的 User-Agent信息
                               #以下变量内容可以动态设置 User-Agent内容:
                               #%name: 替换配置文件中的name字段 .
                               #%ver: 替换配置文件中的version字段 .
                               #%nwver: 替换NW.js版本 .
                               #%webkit_ver: 替换WebKit引擎版本 .
                               #%osinfo: 替换系统以及CPU信息 .

  "chromium-args":"xxx",      #分发应用时自定义chromium命令行参数至应用(想要禁用GPU加速视频显示,
                                                             #只需添加添加参数 "chromium-args" : "--disable-accelerated-
                               #video".)

  "crash_report_url":"xxx",   #应用崩溃时,崩溃转存报告将被发送到设定的服务器

  "inject_js_start":"xxx",    #CSS文件执行之后 , 其他DOM或脚本运行之前 , 执行的JavaScript代码
  "inject_js_end":"xxx",      #页面document对象加载之后 , 触发 onload之前 , 执行的JavaScript
                                                         #代码 . 主要作为新窗口中 Window.open()的参数执行JavaScript代码

  "additional_trust_anchors", #证书作为附加可用的根证书使用 , 允许连接自签名证书或者CA签发机构颁发
                                                             #证书的服务(Array - 数多个PEM编码的证书组成的数组)

  "dom_storage_quota":500,    #Mb为单位的DOM存数限制数量(建议设置为期望值的两倍)
   
  /**
   *其他字段
   */
  "description":"xxx"         #配置的描述说明,以.结束
  "version":1.0,              #应用版本信息

  "maintainers":[{             #维护成员
       "name": "Bill Bloggs",
       "email": "[email protected]",
       "web": "http://www.bblogmedia.com",
     }],

    "contributors":[{        #贡献者,与维护成员格式一致,但首个应为作者
       "name": "xxx",
       "email": "xxx",
       "web": "xxx",
    }],

    "bugs":"xxx",            #提交错误的网址,如mail或http地址
    "licenses":"xxx",        #许可证列表
    "dependencies":"xxx",    #必要依赖,组的顺序非常重要,较前条目具有较高优先级.
    "homepage":"xxx",        #网站URL地址
}

2. 使用NW.js APIs

NW.js中的APIs都被加载到nw全局对象中,并能够在javascript代码中直接使用

旧版本加载nw方式为require('nw.gui'),返回nw对象。

举个??:通过NW.js提供的API来创建应用此单(当用户鼠标右击打开上下文菜单显示)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<html>
  <head>
    <title>创建上下文菜单</title>
  </head>
  <body>
    <P>右击显示上下文菜单</P>
    <script>
      //1.通过NW.js 创建一个空菜单
      let menu = new nw.Menu();   //js中可直接使用 nw 对象,已经被加载到全局对象中
     
      //2.创建三个菜单项目
      let menuItem1 = new nw.MenuItem({label:'菜单1',click:()=>{alert('选择菜单1')}});
      let menuItem2 = new nw.MenuItem({label:'菜单2',click:()=>{alert('选择菜单2')}});
      let menuItem3 = new nw.MenuItem({label:'菜单3',click:()=>{alert('选择菜单3')}});
   
      //3.将菜单项添加到菜单中
      menu.append(menuItem1);
      menu.append(menuItem2);
      menu.append(menuItem3);
     
      //4.对当前html文档body标签内的正文内容设置监听事件
      document.body.addEventListener('contextmenu',(ev)=>{
           //阻止默认的弹出框
           ev.preventDefault();
           //弹出自定义的Menu菜单
           menu.popup(ev.x,ev.y);
           return false;
      },false);
    </script>
  </body>
</html>

效果如下图:
在这里插入图片描述

PS:

  • 更多HTML DOM Event事件可参见**《HTML DOM 事件》**

3. 使用Node.js API(require

我们除了上述在DOM中直接使用NW.js的APIS之外,还可以在DOM中直接调用node.js代码及模块。这样就可以通过NW.js轻松开发PC桌面应用了。

举个??:利用Node.js的os模块擦护心操作系统的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<html>
  <head>
    <title>创建上下文菜单</title>
  </head>
  <body>
    <!--这里使用Flex弹性布局-->
    <div style="display:flex;flex-direction:row;justify-content:center;align-item:center">
      <div style="flex:30%">您的当前系统为:</div>
      <div style="flex:70%" id='os_platform'></div>
    </div>
    <script>
      //1.将node.js中os模块脚本赋值给 mOS对象
      let mOS = require('os');
     
      //2.通过document的getElementById方法获取对应的div对象,然后通过innerHTML修改div内容
      document.getElementById('os_platform').innerHTML=mOS.platform();
    </script>
  </body>
</html>

PS:

  • 您可以在NW.js中通过npm进行模块的安装然后使用。
  • 详细Flex布局参见《Flex 布局语法教程》
  • 【注意】当使用 npm install构建原生模块时无法兼容 NW.js ABI. 如需使用则需要根据 nw-gyp进行NW.js的重建. 详细参考使用原生模块章节.

4. 开发工具与调试

开发工具只能在SDK构建方式中使用。

  • Open Developer Tools 开启开发工具

    Windows和Linux系统中使用快捷键F12开启 , Mac系统中使用??i.

    此外 , windows系统中可以使用win.showDevTools()`开启开发工具进行编程

  • 调试Node.js模块

    NW.js默认进行独立环境模式运行,调试Node.js模块需要在引用中右键并选择Inspect Background Page,当运行到Node.js模块代码时,调试器会自动聚焦并暂停运行。

    混合模式下,Node.js模块可以在开发工具中直接进行调试。

  • 远程调试

    使用命令行参数--remote-debugging-port=port指定端口进行监听。例如,运行nw --remote-debugging-port=9222,通过浏览器访问http://localhost:9222/进行远程调试

  • 开发工具扩展

    开发工具支持全部扩展,包括ReactJS

    使用扩展需要在配置文件manifest.json添加chrome-extension://*权限,并在nw运行时增加 --load-extension=path/to/extension命令行参数 . 扩展的文件从Chrome应用商店安装之后拷贝到本地Chrome浏览器目录下 .

5. NW.js中独立环境和混合环境模式

NW.js基于Chrome应用构建,因此NW.js在开始运行时候,自动完成后台加载。当创建一个窗口时,同时创建一个JavaScript环境。

NW.js中,默认情况下,Node.js模块加载到后台运行环境。

5.1 独立环境模式

除浏览器环境,NW.js默认在后台增加Node.js环境运行Node模块,这样NW.js同时拥有两个JavaScript环境:

浏览器环境Node环境

5.1.1 浏览器环境
  • 加载脚本

    • 编译

      JS源码编译为本地二进制代码需要使用nwjc工具,同时需要提供SDK构建方式的NW.

      1
      nwjc source.js binary.bin

      *.bin文件需要发布到应用中,可以任意命名bin文件。

    • 加载

      NW.js 加载已编译的JS文件

      1
      nw.Window.get().evalNWBin(frame,'binary.bin');

      Win.evalNWBin()方法中的参数与Window.eal()方法相同,第一个参数为目标frame(null为主frame),第二个参数为已编译的bin文件

    • 加载远程已编译的JS文件

      NW.js可以从远程(例如AJAX)获取已编译的JavaScropt,并且即时执行。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      //创建请求实例HMLHttpRequest
      var xhr = new HMLHttpRequest();
      //设置响应类型-ArrayBuffer对象二进制数据(告诉服务器期望的响应格式)
      xhr.responseType = 'arraybuffer';
      //设置请求方式和地址
      xhr.open('GET',url,true);
      //发起请求
      xhr.send();
      //接收响应
      xhr.onload=()=>{
        //接收到响应使用NW加载已编译的js文件
        nw.Window.get().evalNWBin(null,xhr.response);
      }

    **PS:**已编译代码在浏览器环境中执行 . 可以像其他运行在浏览器环境中的其他脚本 , 就像您使用任何Web API(如DOM)以及NW.js API和Node API

  • 不足

    已编译代码不支持跨平台也不兼容不同版本的NW.js的版本,因此在打包应用时需要在各自系统平台中运行nwjc .

7. 应用签名

应用签名可阻止正式应用中加载未签名的文档。

注意:应用签名并不能阻止别有用心的人黑进你的应用,或者使用其他NW代码加载你的应用,可考虑使用C++编写,并使用Node.js模块和NaCl加载,或者结合使用nwjc对源码进行编译为本地二进制文件后使用!

  • 签名文件

    NW.js的应用签名文件为verified_contents.json,它提供了密钥对,该文件由sign.py工具与私钥文件private_key.pem所创建,公钥已经内置于NW.js应用中。

  • 如何签名

    要运行签名的应用程序,在应用程序目录中调用nw --verify-content=enfore_strict命令执行严格验证模式,之后显示签名页面,完成签名动作。

    在此之后对index.html进行任意修改,NW将报告文件已损坏并立即退出。

  • 签名步骤

    使用密钥对签名应用,步骤如下:

    1. 切换到应用目录中
    2. 确认verified_contents.jsoncomputed_hashes.json文件不在当前目录(如果存在删除)
    3. 运行payload生成sign.py所需的配置文件payload.json文件
    4. 运行python sign.py > /tmp/verifid_content.json,需要注意 tmp目录不能是应用所在目录
    5. 将生成的verified_contents.json文件拷贝到应用目录,完成签名动作。
  • 使用自己密钥对重新构建应用

    要使用您自己的密钥对,您需要重建NW,并命令行参数--verify-content=默认设置为enfoce_strict

    1. openssl genrsa -out private_key.pem 2048生成密钥对,输出公私钥文件
    2. 运行python convertkey.py,它会将公钥转换为C源代码
    3. 将生成的代码复制到NW安装包的content/nw/src/nw_content_verifier_delegate.cc,替换原文件默认的key值
    4. 更改文件中第73行为Mode experiment_value = ContentVerifierDelegate::ENFORCE_STRICT;
    5. 重新构建NW

7. 自动更新

详细使用参见此链接

8. Node.js 自定义模块

Node应用由模块组成,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。每个模块内部,module变量代表当前模块。这个变量是一个对象

它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

  • module.export(导出模块)

    module.exports是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

    举个??

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /**
     *创建一个名为test.js的 Node.js文件
     */
    var x = 5;
    var addX = (value)=>{
    return value + x;
    }
    module.export.x = x;
    module.export.addX = addX;

    上面代码通过module.export导出变量x和函数addX

  • require(加载模块)

    1
    2
    3
    4
    5
    6
    7
    8
    /**
     *创建名为 index.js 的 javascript文件
     */
    //通过require加载模块
    var example = require('./test.js');
    //调用模块中的变量和函数
    console.log(example.x);       // 5
    console.log(example.addX(1)); // 6
  • exports 与 module.exports区别

    为了方便我们可以直接在exports对象上添加方法,表示对外输出的接口,如同在module.exports上添加的一样。注意:不能直接将exports变量指向一个值,因为这样等于切段了exports与module.exports的联系

    错误写法

    1
    export='将exports变量指向该值'

    正确写法(car.js)

    • 导出变量

      1
      2
      //导出color变量
      export.carColor='red'
    • 导出函数

      1
      2
      3
      4
      //导出setCarColor函数
      export.setCarColor=(color)=>{
        console.log('color:' + color);
      }
    • 导出对象

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      /**
       *导出Car对象包含如下属性和方法
       *@attribute:[brand,color,price]
       *@method:[setCarColor,]
       */
      export.Car={
        brand:'',    //品牌
        color:'',    //颜色
        price:20000, //价格
       
        //设置品牌
        setBrand:(brand)=>{
          this.brand = brand;
        },
       
        //设置颜色
        setCarColor:(color)=>{
          this.color = color;
        },

        //设置价格
        setPrice:(price)=>{
          this.price=price;
        },
       
        //获取汽车信息
        getCarInfo:()=>{
          return '这是一辆'+this.price+this.color+this.brand+'汽车';
        },
      }

    在JS(index.js)中使用Node.js

    1
    2
    3
    4
    5
    6
    7
    8
    //加载car.js 模块
    let carNodeJs = require('./car');
    _printLog=()=>{
      custom.Car.setBrand('兰博基尼');
      custom.Car.setColor('红色');
      custom.Car.setPrice(2000000);
      alert(custom.Car.getCarInfo());
    }

9. ES6与NodeJS模块导入导出区别

详细参见该链接

NodeJs
  • 在Node模块中,采用的是commonjs规范,也就是使用**require方式引入模块,而使用module.exports**导出接口

  • 如何检测Node.js对ES6的支持

    1. 命令行全局安装es-checker
    2. 执行 es-checker
    3. 红色表示暂不支持的

    在这里插入图片描述

ES6
  • Es6模块中并没有采用node中require导入模块的方式,导入(import),导出(export)

10. ES6 入门教程