native.js是什么且如何使用
一、總結
一句話總結:Native.js技術,簡稱NJS,是一種將手機操作系統的原生對象轉義,映射為JS對象,在JS里編寫原生代碼的技術。Native.js不是一個js庫,不需要下載引入到頁面的script中,也不像nodejs那樣有單獨的運行環境,Native.js的運行環境是集成在5+runtime里的,使用HBuilder打包的app或流應用都可以直接使用Native.js。
二、Native.js使用入門
1、概述
Native.js技術,簡稱NJS,是一種將手機操作系統的原生對象轉義,映射為JS對象,在JS里編寫原生代碼的技術。如果說Node.js把js擴展到服務器世界,那么Native.js則把js擴展到手機App的原生世界。HTML/JS/Css全部語法只有7萬多,而原生語法有幾十萬,Native.js大幅提升了HTML5的能力。NJS突破了瀏覽器的功能限制,也不再需要像Hybrid那樣由原生語言開發插件才能補足瀏覽器欠缺的功能。NJS編寫的代碼,最終需要在HBuilder里打包發行為App安裝包,或者在支持Native.js技術的瀏覽器里運行。目前Native.js技術不能在普通手機瀏覽器里直接運行。
- NJS大幅擴展了HTML5的能力范圍,原本只有原生或Hybrid App的原生插件才能實現的功能如今可以使用JS實現。
- NJS大幅提升了App開發效率,將iOS、Android、Web的3個工程師組隊才能完成的App,變為1個web工程師就搞定。
- NJS不再需要配置原生開發和編譯環境,調試、打包均在HBuilder里進行。沒有mac和xcode一樣可以開發iOS應用。
- 如果不熟悉原生API也沒關系,我們匯總了很多NJS的代碼示例,復制粘貼就可以用。http://ask.dcloud.net.cn/article/114
再次強調,Native.js不是一個js庫,不需要下載引入到頁面的script中,也不像nodejs那樣有單獨的運行環境,Native.js的運行環境是集成在5+runtime里的,使用HBuilder打包的app或流應用都可以直接使用Native.js。
技術要求
由於NJS是直接調用Native API,需要對Native API有一定了解,知道所需要的功能調用了哪些原生API,能看懂原生代碼並參考原生代碼修改為JS代碼。否則只能直接copy別人寫好的NJS代碼。
2、開始使用
2.1、判斷平台
Native API具有平台依賴性,所以需要通過以下方式判斷當前的運行平台:
- function judgePlatform(){
- switch ( plus.os.name ) {
- case "Android":
- // Android平台: plus.android.*
- break;
- case "iOS":
- // iOS平台: plus.ios.*
- break;
- default:
- // 其它平台
- break;
- }
- }
2.2、類型轉換
在NJS中調用Native API或從Native API返回數據到NJS時會自動轉換數據類型。
類型轉換表
類型 | Objective-C | Java | JavaScript |
---|---|---|---|
基本數據 | byte/short/int/long/float/double/... | byte/short/int/long/float/double/... | Number |
字符 | char | char | String |
字符串 | NSString/@"" | String/"" | String |
數組 | @[1,2,3]/NSArray | new XXX[] | InstanceObject |
類 | @interface | class | ClassObject |
對象(實例) | * | * | InstanceObject |
空對象 | nil | null | null |
其它 | Protocol | Interface | Object(JSON) |
2.3、其他轉換
- Android原生應用的主Activity對象 轉為plus.android.runtimeMainActivity()
Android的主Activity對象是啟動應用時自動創建的,不是代碼創建,此時通過plus.android.runtimeMainActivity()方法獲取該Activity對象 - Objective-C方法冒號剔除
[pos setPositionX:(int)x Y:(int)y;] 轉為 pos.setPositionXY(x,y);
OC語法中方法的定義格式為:
“(返回值類型) 函數名: (參數1類型) 形參1 參數2名稱: (參數2類型) 形參2”
方法的完整名稱為: “函數名:參數2名稱:”。
如:“(void)setPositionX:(int)x Y:(int)y;”,方法的完整名稱為“setPositionX:Y:”,調用時語法為:“[pos setPositionX:x Y:y];”。
在JS語法中函數名稱不能包含“:”字符,所以OC對象的方法名映射成NJS對象方法名時將其中的“:”字符自動刪除,上面方法名映射為“setPositionXY”,在NJS調用的語法為:“pos.setPositionXY(x,y);”。 - 文件路徑轉換
Web開發里使用的image/1.png是該web工程的相對路徑,而原生API中經常需要使用絕對路徑,比如/sdcard/apptest/image/1.png,此時使用這個擴展方法來完成轉換:plus.io.convertLocalFileSystemURL("image/1.png")
2.4、概念
2.4.1、類對象
由於JavaScript中本身沒有類的概念,為了使用Native API層的類,在NJS中引入了類對象(ClassObject)的概念,用於對Native中的類進行操作,如創建類的實例對象、訪問類的靜態屬性、調用類的靜態方法等。其原型如下:
- Interface ClassObject {
- function Object plusGetAttribute( String name );
- function void plusSetAttribute( String name, Object value );
- }
2.4.2、獲取類對象
在iOS平台我們可以通過plus.ios.importClass(name)方法導入類對象,參數name為類的名稱;在Android平台我們可以通過plus.android.importClass(name)方法導入類對象,其參數name為類的名稱,必須包含完整的命名空間。
示例:
- // iOS平台導入NSNotificationCenter類
- var NSNotificationCenter = plus.ios.importClass("NSNotificationCenter");
- // Android平台導入Intent類
- var Intent = plus.android.importClass("android.content.Intent");
獲取類對象后,可以通過類對象“.”操作符獲取類的靜態常量屬性、調用類的靜態方法,類的靜態非常量屬性需通過plusGetAttribute、plusSetAttribute方法操作。
實例對象
在JavaScript中,所有對象都是Object,為了操作Native層類的實例對象,在NJS中引入了實例對象(InstanceObject)的概念,用於對Native中的對象進行操作,如操作對象的屬性、調用對象的方法等。其原型如下:
- Interface InstanceObject {
- function Object plusGetAttribute( String name );
- function void plusSetAttribute( String name, Object value );
- }
2.4.3、獲取實例對象
有兩種方式獲取類的實例對象,一種是調用Native API返回值獲取,另一種是通過new操作符來創建導入的類對象的實例,如下:
- // iOS平台導入NSDictionary類
- var NSDictionary = plus.ios.importClass("NSDictionary");
- // 創建NSDictionary的實例對象
- var ns = new NSDictionary();
- // Android平台導入Intent類
- var Intent = plus.android.importClass("android.content.Intent");
- // 創建Intent的實例對象
- var intent = new Intent();
獲取實例對象后,可以通過實例對象“.”操作符獲取對象的常量屬性、調用對象的成員方法,實例對象的非常量屬性則需通過plusGetAttribute、plusSetAttribute方法操作。
操作對象的屬性方法
-
常量屬性
獲取對象后就可以通過“.”操作符獲取對象的常量屬性,如果是類對象則獲取的是類的靜態常量屬性,如果是實例對象則獲取的是對象的成員常量屬性。 -
非常量屬性
如果Native層對象的屬性值在原生環境下被更改,此時使用“.”操作符獲取到對應NJS對象的屬性值就可能不是實時的屬性值,而是該Native層對象被映射為NJS對象那一刻的屬性值。
為獲取獲取Native層對象的實時屬性值,需調用NJS對象的plusGetAttribute(name)方法,參數name為屬性的名稱,返回值為屬性的值。調用NJS對象的plusSetAttribute(name,value)方法設置Native層對象的非常量屬性值,參數name為屬性的名稱,value為要設置新的屬性值。注意:使用plusGetAttribute(name)方法也可以獲取Native層對象的常量屬性值,但不如直接使用“.”操作符來獲取性能高。
-
方法
獲取對象后可以通過“.”操作符直接調用Native層方法,如果是類對象調用的是Native層類的靜態方法,如果是實例對象調用的是Native層對象的成員方法。注意:在iOS平台由於JS語法的原因,Objective-C方法名稱中的“:”字符轉成NJS對象的方法名稱后將會被忽略,因此在NJS中調用的方法名需去掉所有“:”字符。
-
類的繼承
Objective-C和Java中類如果存在繼承自基類,在NJS中對應的對象會根據繼承關系遞歸將所有基類的公有方法一一換成NJS對象的方法,所有基類的公有屬性也可以通過其plusGetAttribute、plusSetAttribute方法訪問。
3、開始寫NJS
使用NJS調用Native API非常簡單,基本步驟如下:
a. 導入要使用到的類;
b. 創建類的實例對象(或者調用類的靜態方法創建);
c. 調用實例對象的方法;
以下例子使用NJS調用iOS和Android的原生彈出提示框(類似但不同於js的alert)。
Android
以下代碼在Android平台展示調用Native API顯示系統提示框。
首先是Android原生 Java代碼,用於比對參考:
- import android.app.AlertDialog;
- //...
- // 創建提示框構造對象,Builder是AlertDialog的內部類。參數this指代Android的主Activity對象,該對象啟動應用時自動生成
- AlertDialog.Builder dlg = new AlertDialog.Builder(this);
- // 設置提示框標題
- dlg.setTitle("自定義標題");
- // 設置提示框內容
- dlg.setMessage("使用NJS的原生彈出框,可自定義彈出框的標題、按鈕");
- // 設置提示框按鈕
- dlg.setPositiveButton("確定(或者其他字符)", null);
- // 顯示提示框
- dlg.show();
- //...
Native.js代碼:
- /**
- * 在Android平台通過NJS顯示系統提示框
- */
- function njsAlertForAndroid(){
- // 導入AlertDialog類
- var AlertDialog = plus.android.importClass("android.app.AlertDialog");
- // 創建提示框構造對象,構造函數需要提供程序全局環境對象,通過plus.android.runtimeMainActivity()方法獲取
- var dlg = new AlertDialog.Builder(plus.android.runtimeMainActivity());
- // 設置提示框標題
- dlg.setTitle("自定義標題");
- // 設置提示框內容
- dlg.setMessage("使用NJS的原生彈出框,可自定義彈出框的標題、按鈕");
- // 設置提示框按鈕
- dlg.setPositiveButton("確定(或者其他字符)",null);
- // 顯示提示框
- dlg.show();
- }
- //...
注意:NJS代碼中創建提示框構造對象要求傳入程序全局環境對象,可通過plus.android.runtimeMainActivity()方法獲取應用的主Activity對象,它是Html5+應用運行期自動創建的程序全局環境對象。
Android設備上運行效果圖:
`注意:其實HTML5+規范已經封裝過原生提示框消息API:plus.ui.alert( message, alertCB, title, buttonCapture)。此處NJS的示例僅為了開發者方便理解,實際使用時調用plus.ui.alert更簡單,性能也更高。**
iOS
以下代碼在iOS平台展示調用Native API顯示系統提示對話框。
iOS原生Objective-C代碼,用於比對參考:
- #import <UIKit/UIKit.h>
- //...
- // 創建UIAlertView類的實例對象
- UIAlertView *view = [UIAlertView alloc];
- // 設置提示對話上的內容
- [view initWithTitle:@"自定義標題" // 提示框標題
- message:@"使用NJS的原生彈出框,可自定義彈出框的標題、按鈕" // 提示框上顯示的內容
- delegate:nil // 點擊提示框后的通知代理對象,nil類似js的null,意為不設置
- cancelButtonTitle:@"確定(或者其他字符)" // 提示框上取消按鈕的文字
- otherButtonTitles:nil]; // 提示框上其它按鈕的文字,設置為nil表示不顯示
- // 調用show方法顯示提示對話框,在OC中使用[]語法調用對象的方法
- [view show];
- //...
Native.js代碼:
- /**
- * 在iOS平台通過NJS顯示系統提示框
- */
- function njsAlertForiOS(){
- // 導入UIAlertView類
- var UIAlertView = plus.ios.importClass("UIAlertView");
- // 創建UIAlertView類的實例對象
- var view = new UIAlertView();
- // 設置提示對話上的內容
- view.initWithTitlemessagedelegatecancelButtonTitleotherButtonTitles("自定義標題" // 提示框標題
- , "使用NJS的原生彈出框,可自定義彈出框的標題、按鈕" // 提示框上顯示的內容
- , null // 操作提示框后的通知代理對象,暫不設置
- , "確定(或者其他字符)" // 提示框上取消按鈕的文字
- , null ); // 提示框上其它按鈕的文字,設置為null表示不顯示
- // 調用show方法顯示提示對話框,在JS中使用()語法調用對象的方法
- view.show();
- }
- //...
注意:在OC語法中方法的定義格式為:
“(返回值類型) 函數名: (參數1類型) 形參1 參數2名稱: (參數2類型) 形參2”
方法的完整名稱為: “函數名:參數2名稱:”。
如:“(void)setPositionX:(int)x Y:(int)y;”,方法的完整名稱為“setPositionX:Y:”
調用時語法為:“[pos setPositionX:x Y:y];”。
在JS語法中函數名稱不能包含“:”字符,所以OC對象的方法名映射成NJS對象方法名時將其中的“:”字符自動刪除,上面方法名映射為“setPositionXY”,在NJS調用的語法為:“pos.setPositionXY(x,y);”。
iOS設備上運行效果圖:
`注意:其實HTML5+規范已經封裝過原生提示框消息API:plus.ui.alert( message, alertCB, title, buttonCapture)。此處NJS的示例僅為了開發者方便理解,實際使用時調用plus.ui.alert更簡單、性能也更高。
在HBuilder自帶的Hello H5+模板應用中“Native.JS”(plus/njs.html)頁面有完整的源代碼,可真機運行查看效果。
------------------
轉載 :http://blog.csdn.net/qq_27626333/article/details/51853039
三、Native.js示例匯總
Native.js雖然強大和開放,但很多web開發者因為不熟悉原生API而難以獨立完成。
這篇帖子的目的就是匯總各種寫好的NJS代碼,方便web開發者。
眾人拾柴火焰高,有能力的開發者多多提交NJS代碼,大家都會給你點贊的,我們也會為每位共享NJS代碼的朋友送上200積分。
Android平台
調用Android本地分享
http://ask.dcloud.net.cn/article/134
直接撥打電話
http://ask.dcloud.net.cn/question/4035
將程序切換到后台
http://ask.dcloud.net.cn/question/2484
強制彈出軟鍵盤
http://ask.dcloud.net.cn/question/2324
獲取安卓設備device.uuid
http://ask.dcloud.net.cn/question/3510
獲取內存及CPU信息
http://ask.dcloud.net.cn/question/2202
開啟關閉藍牙
http://ask.dcloud.net.cn/question/4720
監聽藍牙開關狀態
http://ask.dcloud.net.cn/article/274
獲取藍牙設備列表
http://ask.dcloud.net.cn/question/8265
藍牙連接票據打印機完整代碼
http://ask.dcloud.net.cn/article/643
NFC數據讀取
http://ask.dcloud.net.cn/question/6726
截屏
http://ask.dcloud.net.cn/question/5344
獲取MAC地址
http://ask.dcloud.net.cn/question/1511
獲取設備當前網速
http://ask.dcloud.net.cn/article/773
打開網絡設置
http://ask.dcloud.net.cn/question/1475
打開各種系統設置界面
http://ask.dcloud.net.cn/question/14732
獲取WIFI列表
http://ask.dcloud.net.cn/question/12113
調用系統控件播放視頻
http://ask.dcloud.net.cn/question/614
調用os通訊錄選擇控件
http://ask.dcloud.net.cn/question/5783
原生日歷提醒插入
http://ask.dcloud.net.cn/article/215
調用系統控件裁剪圖片
http://ask.dcloud.net.cn/question/8314
復制內容到系統粘貼板
http://ask.dcloud.net.cn/question/2034
調用訊飛的文字轉語音功能(TTS)
http://ask.dcloud.net.cn/question/6473
調用其它Activity后通過startActivityForResult獲取返回結果
http://ask.dcloud.net.cn/question/5783
接收系統廣播消息,如監聽安裝卸載apk的事件
http://ask.dcloud.net.cn/article/222
判斷app是否安裝
http://ask.dcloud.net.cn/question/7604
以監聽手機飛行模式開關為例說明如何使用Native.js進行BroadcastReceiver廣播
http://ask.dcloud.net.cn/question/7661
常駐Android通知欄,不用個推實現本地消息推送(Local Notification)
http://ask.dcloud.net.cn/question/2464
調用原生的socket連接
http://ask.dcloud.net.cn/question/60
啟動一個原生service
http://ask.dcloud.net.cn/question/433
基於native.js的文件系統管理功能實現
http://ask.dcloud.net.cn/article/809
打開閃光燈
http://ask.dcloud.net.cn/question/19379
停止、開啟個推推送功能
var pushManager = plus.android.importClass("com.igexin.sdk.PushManager"); var context = plus.android.runtimeMainActivity(); function enable() { pushManager.getInstance().turnOnPush(context); } function disable() { pushManager.getInstance().turnOffPush(context); }
感謝yeahcheung分享
利用native.js獲取手機gps是否開啟
http://ask.dcloud.net.cn/question/11890
通過native.js設置系統牆紙
http://ask.dcloud.net.cn/article/651
監聽短信驗證碼
http://ask.dcloud.net.cn/article/676
限制手機錄像時間
http://ask.dcloud.net.cn/question/45756
iOS平台
獲取包名
var NSBundle = plus.ios.importClass('NSBundle'); var bundle = NSBundle.mainBundle(); console.log(bundle.bundleIdentifier()); plus.ios.deleteObject(bundle);
獲取設備名
http://ask.dcloud.net.cn/question/14691
測試是否安裝某應用
http://ask.dcloud.net.cn/question/14430
調用iOS打印API
http://ask.dcloud.net.cn/question/4226
通過native.js登入game center
見Hello H5+里Native.js部分演示及源碼。
或在這里搜索“game center”,http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/88
設置獲取內容到系統粘貼板
http://ask.dcloud.net.cn/question/3720
打開頁面默認彈出鍵盤
http://ask.dcloud.net.cn/question/2324
播放提示音
http://ask.dcloud.net.cn/question/3962
調用ios的文字轉語音(TTS)
http://ask.dcloud.net.cn/question/4175
把base64數據保存為圖片
http://ask.dcloud.net.cn/question/6190
設置webview滑動減速度
var webview = plus.ios.currentWebview(); var scrollView = webview.plusGetAttribute("scrollView"); scrollView.plusSetAttribute("decelerationRate:",0.99);
打開ios的Wifi設置頁面
http://ask.dcloud.net.cn/question/7797
判斷是否開啟消息通知
http://ask.dcloud.net.cn/question/4497
檢測iOS是否允許使用相機(感謝小鬧分享)
http://ask.dcloud.net.cn/article/188
ios獲取系統的時區id
var NSTimeZone = plus.ios.importClass("NSTimeZone"); var sys = NSTimeZone.systemTimeZone(); console.log(sys.plusGetAttribute("name"));
狀態欄顯示網絡請求雪花
var UIApplication = plus.ios.import("UIApplication"); var sharedApplication = UIApplication.sharedApplication(); sharedApplication.setNetworkActivityIndicatorVisible(true); plus.ios.deleteObject(sharedApplication);
獲取GPS授權狀態
var CLLocationManager = plus.ios.import("CLLocationManager"); var authorizationStatus = CLLocationManager.authorizationStatus(); switch(authorizationStatus) { case 0: /// User has not yet made a choice with regards to this application break; case 1: // This application is not authorized to use location services. Due // to active restrictions on location services, the user cannot change // this status, and may not have personally denied authorization break; case 2: // User has explicitly denied authorization for this application, or // location services are disabled in Settings. break; case 3: // User has granted authorization to use their location at any time, // including monitoring for regions, visits, or significant location changes. break; case 4: // User has granted authorization to use their location only when your app // is visible to them (it will be made visible to them if you continue to // receive location updates while in the background). Authorization to use // launch APIs has not been granted. break; case 5: // This value is deprecated, but was equivalent to the new -Always value. break; defalut: break; }
獲取手機存儲空間
var BundleClass = plus.ios.importClass("NSBundle"); var BundleObj = BundleClass.mainBundle(); var filenamagerobj = plus.ios.newObject("NSFileManager"); var FileAttr = plus.ios.invoke(filenamagerobj,"attributesOfFileSystemForPath:error:",BundleObj.bundlePath(),null); // NSFileSystemFreeSize 參數獲取剩余空間 // NSFileSystemSize 獲取手機總存儲空間 var freeSpace = plus.ios.invoke(FileAttr,"objectForKey:","NSFileSystemFreeSize"); var numberFormatterObj = plus.ios.newObject("NSNumberFormatter"); var FreeSpaceStr = plus.ios.invoke(numberFormatterObj,"stringFromNumber:",freeSpace); var freeSpace = FreeSpaceStr / 1024/1024/1024;
打開/關閉手機的閃光燈
function turnonLight(isOn) { if(plus.os.name == "iOS") { var avcaptClass = plus.ios.importClass("AVCaptureDevice"); if(avcaptClass) { var device = avcaptClass.defaultDeviceWithMediaType("vide"); plus.ios.invoke(device, "lockForConfiguration:", null); if(isOn) { plus.ios.invoke(device, "setTorchMode:", 1); plus.ios.invoke(device, "setFlashMode:", 1); } else { plus.ios.invoke(device, "setTorchMode:", 0); plus.ios.invoke(device, "setFlashMode:", 0); } plus.ios.invoke(device, "unlockForConfiguration"); } } };
顯示應用內的ViewController
// NewViewController為應用內創建的原生的ViewController類名,所調用頁面的內容需要在原生代碼中完成 var newVCobj = plus.ios.newObject("NewViewController"); var UIApplicationClass = plus.ios.importClass("UIApplication"); var UIAppObj = UIApplicationClass.sharedApplication(); var del = plus.ios.invoke(UIAppObj,"delegate"); // 如果當前應用delegate對象包含UIWindow對象並且變量名命名為“window”可以這么寫, // 否則需要根據實際代碼情況修改 // 應用的delegate對象也可以添加一個返回UIViewController的方法 var appWindowObj = plus.ios.invoke(del,"window"); var appRootController = plus.ios.invoke(appWindowObj,"rootViewController"); plus.ios.invoke(appRootController,"presentViewController:animated:completion:",newVCobj,"YES",null);
參考:Native.js示例匯總 - DCloud問答
http://ask.dcloud.net.cn/article/114