NW.js開發環境搭建

NW.js開發環境搭建

簡介: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

對於國內用戶,如果下載連接下載速度太慢的話,可以考慮的可選項是:

或者進入官網下載根據自己需要下載對應的版(我這裏下載的是mac版本的v0.44.5,osx-x64,normal
v0.44.5,osx-x64,sdk

  • 下載後直接解壓,將nwjs.app拖到應用程序中(便於從桌面點擊圖標啓動)
    <img

  • 設置別名和環境變量(以便從命令行可直接啓動)

    #打開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.jsonJSON 格式格式的配置文件. main 屬性定義了應用首頁, 如本例的 "index.html". name則定義了應用名稱. 具體查看 配置文件章節.

    #創建項目目錄
    mkdir NWDemo
    #進入項目根目錄
    cd NWDemo
    #執行初始化生成package.json
    npm init
    

    package.json

    {
      "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文件. 該文件在應用啓動時默認不打開窗口並在後臺執行。 您可以稍後進行一些初始化並手動打開窗口。 例如:

    // 初始化你的應用程序之後 ...
    nw.Window.open('index.html', {}, function(win) {});
    
  • 創建入口頁面index.html

    <!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;
#進入項目根目錄
cd NWDemo
#運行
nw .

【注意】

Windows系統中 , 可拖拽包含 package.json的文件夾至 nw.exe直接運行應用。

5. 打包應用

可以使用以下工具自動完成打包NW.js應用進行發佈 .

或者可以使用以下步驟手動構建應用 ,具體步驟參考手動構建應用

這裏使用nwjs-builder-phoenix構建方式詳細使用參見github

6. APIs

詳細使用參見地址

擴展

1. 配置文件(package.json)

{
  "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來創建應用此單(當用戶鼠標右擊打開上下文菜單顯示)

<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:

3. 使用Node.js API(require

我們除了上述在DOM中直接使用NW.js的APIS之外,還可以在DOM中直接調用node.js代碼及模塊。這樣就可以通過NW.js輕鬆開發PC桌面應用了。

舉個🌰:利用Node.js的os模塊擦護心操作系統的信息

<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 瀏覽器環境
  • 加載腳本

    • <script>標籤
    • jQuery的$.getScript()
    • RequireJS
  • 全局對象

  • 創建新瀏覽器環境

    創建新的frame或者窗口時 , 將得到一個新的瀏覽器環境

  • 訪問Node.jsNW.js的API

    將Node環境對象拷貝到瀏覽器環境中 , 這樣運行在瀏覽器環境的腳本能夠訪問Node.js對象

    • nw – 所有NW對象 NW.js APIs
    • global – NW環境全局對象; 等同nw.global
    • require – 加載Node.js模塊的方法; 等同 nw.require(), 但不支持通過 require('nw.gui')加載NW.js模塊.
    • process – Node.js模塊中process模塊; 等同nw.process
    • Buffer – Node.js模塊中Buffer類
5.1.2 Node環境
  • 加載腳本

    • 通過Node.js的API中的require()加載腳本;
    • 通過配置文件中node-main加載腳本;
  • 全局對象

    • js內建對象
    • Node.js全局對象(如 __dirname, process, Buffer等)

    【注意】Node環境不能使用Web APIs,下面會介紹訪問瀏覽器環境和NW.js的API

  • 創建新的Node環境

    • 通過Window.open()創建新窗口,並且參數new_instance設置爲true時;
    • 命令行啓動NW.js時,參數增加--mixed-context進入混合環境模式;
  • 訪問瀏覽器環境和NW.js的API

    Node環境中,沒有瀏覽器或NW.js APIS,如 alert()document.*new.Clipboard等,想訪問瀏覽器APIs**必須傳遞相應的對象**,如window

    舉個🌰

    Node腳本(test.js

    //node環境中訪問瀏覽器的API需要瀏覽器環境傳入對應的el對象
    exports.setText = (el) => {
        el.innerHTML = 'hello';
    };
    

    瀏覽器(index.html)

    <html>
      <head>
        ...
      </head>
      <body>
        <div id="el"></div>
        <script>
           //加載 test.js Node模塊
           var myscript = require('./test.js');
           //調用Node模塊setText方法將`el`元素傳入Node函數
           myscript.setText(document.getElementbyId('el'));
           // "hello"將顯示在`el`標籤中
        </script>
      </body>
    </html>
    
    
    
5.2 混合環境模式

當使用--mixed-context命令行參數運行NW.js時 , 當瀏覽器環境被創建的同時創建了Node環境 .

  • 混合模式中加載腳本

    NW.js可以通過兩種方式使用混合環境模式 , 一是使用--mixed-context命令行參數 , 二是在配置文件中添加chromium-args屬性.

    package.json

    {
        "name": "test-context",
        "main": "index.html",
        "chromium-args": "--mixed-context"   //chromium-args屬性指定使用混合模式
    }
    

    頁面或Node.js中使用require()方式加載腳本運行在同樣的環境中 .

  • 全局對象

    混合環境模式 , 您可以在Node模塊中使用所有瀏覽器和NW.js API,反之亦然

    node.js文件(test.js)

    //導出showAlert函數
    exports.showAlert = function() {
      //因爲開啓了混合環境摸模式,可以在Node中直接使用瀏覽器的alert API
        alert("我正在Node模塊中運行!");
    };
    

    Index.html

    <html>
      ...
      <body>
      <script>
        //加載 test node模塊
         var test = require('./test');
         //調用模塊的showAlert方法
         myscript.showAlert(); // 我正在Node模塊中運行!
      </script>
      </body>
    </html>
    
    
5.3 混合環境模式和獨立環境模式對比

獨立環境模式的優勢是不會出現類型檢查問題 .

混合環境模式的缺點是不能輕易的分享變量 . 環境間分享變量 , 需要將變量放入其他環境能夠訪問的通用環境中 . 或者可以使用window.postMessage() API在環境之間發送和接收信息 .

6. JavaScript源碼保護

  • 源碼保護目的

    應用中的javascript源代碼能夠編譯爲本地二進制代碼進行保護,NW.js能夠加載編譯之後的代碼,應用作爲產品發佈時可以將代碼進行編譯!

  • 如何編譯和加載

    • 編譯

      JS源碼編譯爲本地二進制代碼需要使用nwjc工具,同時需要提供SDK構建方式的NW.

      nwjc source.js binary.bin
      

      *.bin文件需要發佈到應用中,可以任意命名bin文件。

    • 加載

      NW.js 加載已編譯的JS文件

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

      Win.evalNWBin()方法中的參數與Window.eal()方法相同,第一個參數爲目標frame(null爲主frame),第二個參數爲已編譯的bin文件

    • 加載遠程已編譯的JS文件

      NW.js可以從遠程(例如AJAX)獲取已編譯的JavaScropt,並且即時執行。

      //創建請求實例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屬性。

    舉個🌰

    /**
     *創建一個名爲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(加載模塊)

    /**
     *創建名爲 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的聯繫

    錯誤寫法

    export='將exports變量指向該值'
    

    正確寫法(car.js)

    • 導出變量

      //導出color變量
      export.carColor='red'
      
    • 導出函數

      //導出setCarColor函數
      export.setCarColor=(color)=>{
        console.log('color:' + color);
      }
      
    • 導出對象

      /**
       *導出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

    //加載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

10. ES6 入門教程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章