文章來源:小青年原創
發佈時間:2016-08-01
關鍵詞:mui,nativejs,android
轉載需標註本文原始地址: http://zhaomenghuan.github.io...javascript
這段時間以來一直有人問5+ sdk怎麼在原生中集成,每次給了文檔和沒給沒啥大區別,這部分人之因此不能根據文檔寫出想要的結果,無非有兩種狀況,一種對於原生徹底懵逼,畢竟基於mui作APP畢竟前端仍是佔多數,而前端中熟悉原生的人畢竟是少數,不少人聲稱會原生哪裏還會用h5,這話只能呵呵?就大趨勢而言,應用web化是如今的潮流所向,如今即便有資金和技術實力的大廠也在作混合式開發和H5的APP,否則dcloud官方也不會花大力氣在流應用上。近來愈來愈多的原生開發者朋友和我交流h5,他們不少是被逼着轉前端,這些人懂原生,可是不懂h5,因此這些朋友從原生轉mui過程當中可能仍是不可以理解若是用5+ sdk,中間的交互怎麼解決,這就是第二種人的困境?css
正是基於這種現實窘境,我打算把本身只知其一;不知其二的android開發經驗從新拿起來,試着去寫點什麼,拋磚引玉,僅此而已。本文做爲混合式開發的第一篇,暫時不會介紹離線打包集成5+ sdk的相關內容,先用nativejs練練手。html
在開始集成5+sdk以前,咱們先來用native.js寫一個文件管理的功能,以此熟悉native.js的相關API。先來預覽一下效果:
前端
常常有人問使用5+怎麼系統文件,其實用nativejs就能夠實現,有人又要問nativejs怎麼引用。每次遇到這種問題,真的要噴血而出。html5
nativejs是集成在5+ app中,默認不須要引入就能夠直接引用。nativejs是經過js調用系統原生方法,從而實現5+標準中沒有說起的方法,因此說白了你仍是要會原生,或者有人用nativejs將原生的方法轉成了js,這樣你只須要在頁面中調用js的方法就能夠實現調用原生。nativejs在這裏充當一個「語法糖」的做用。java
對於這樣一個遍歷文件系統的功能,用原生方法寫,咱們會這樣寫:android
<!-- 容許程序寫入外部存儲,如SD卡上寫文件 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
5+ APP中這一步默認設置了,咱們不要管。git
import android.os.Environment;
Native.js中使用plus.android.importClass方法:github
var environment = plus.android.importClass("android.os.Environment");
Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)
nativejs這樣寫:web
environment.getExternalStorageState() === environment.MEDIA_MOUNTED
File skRoot = Environment.getExternalStorageDirectory();
nativejs這樣寫:
var sdRoot = environment.getExternalStorageDirectory();
File[] files = sdRoot.listFiles();
nativejs中使plus.android.invoke調用對象(類對象/實例對象)的方法:
var files = plus.android.invoke(sdRoot,"listFiles");
import java.io.File; import java.io.FileFilter; FileFilter ff = new FileFilter() { public boolean accept(File pathname) { return !pathname.isHidden();//過濾隱藏文件 } }; File[] files = sdRoot.listFiles(ff);
nativejs中能夠這樣寫:
// 遍歷sd卡根目錄下的全部文件和文件夾 var files = plus.android.invoke(sdRoot,"listFiles"); var len = files.length; for(var i=0; i<len; i++){ var file = files[i]; // 過濾隱藏文件 if(!plus.android.invoke(file,"isHidden")){ // 非隱藏文件執行操做 } }
上面的預覽效果能夠看出咱們對文件夾和文件進行了不一樣的操做,接着須要在遍歷中判斷。
for(File file : files){ if(file.isDirectory()){ // 文件夾 }else{ // 文件 } }
nativejs寫法:
for(var i=0;i<len;i++){ if(plus.android.invoke(file,"isDirectory")){ // 文件夾 }else{ // 文件 } }
// 讀文件大小 var FileInputStream = plus.android.importClass("java.io.FileInputStream"); var fileSize = new FileInputStream(file); var size = fileSize.available(); // 單位轉換 var fileSizeString; if(size == 0){ fileSizeString = "0B"; }else if(size < 1024){ fileSizeString = size + "B"; }else if(size < 1048576){ fileSizeString = (size/1024).toFixed(2) + "KB"; }else if (size < 1073741824){ fileSizeString = (size/1048576).toFixed(2) + "MB"; }else{ fileSizeString = (size/1073741824).toFixed(2) + "GB"; }
/** * 建立文件夾 * @param {Object} path */ function creatFolder(path){ var File = plus.android.importClass("java.io.File"); var fd = new File(path); if(!fd.exists()){ fd.mkdirs(); plus.nativeUI.toast("建立成功"); } } /** * 刪除文件(文件夾) * @param {Object} path */ function deleteFile(path){ var File = plus.android.importClass("java.io.File"); var fd = new File(path); if (fd != null && fd.exists()){ fd.delete(); plus.nativeUI.toast("刪除成功"); } }
咱們在打開目錄的時候,會遍歷該目錄下的文件夾和文件,實現方法同上面,打開文件咱們可使用5+ runtime openFile調用第三方程序打開指定的文件。
void plus.runtime.openFile( filepath, options, errorCB );
參數:
filepath: ( String ) 必選 打開文件的路徑
字符串類型,文件路徑必須是本地路徑,不然會致使打開文件失敗。
options: ( OpenFileOptions ) 可選 打開文件參數
errorCB: ( OpenErrorCallback ) 必選 打開文件失敗的回調
打開文件操做失敗時回調,返回失敗信息。
本文完整代碼:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <title></title> <link rel="stylesheet" type="text/css" href="css/mui.min.css"/> <link rel="stylesheet" type="text/css" href="css/circles.css"/> <style type="text/css"> .loading { position: absolute; top: 50%; left: 50%; width: 200px; height: 200px; margin-top: -100px; margin-left: -100px; z-index: 9999; } .loading .card { display: table-cell; text-align: center; vertical-align: middle; width: 200px; height: 200px; } .mui-backdrop { background-color: #15b5e9; } </style> </head> <body> <div class="loading"> <div class="card"> <span class="circles-loader">Loading…</span> </div> </div> <header class="mui-bar mui-bar-nav"> <h1 class="mui-title">文件系統</h1> <a id="add" class="mui-icon mui-icon-plus mui-pull-right"></a> </header> <div class="mui-content"> <ul id="list" class="mui-table-view mui-table-view-chevron"></ul> </div> <script src="js/mui.min.js" type="text/javascript" charset="utf-8"></script> <script src="js/njs-io.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> mui.init({ gestureConfig:{ longtap: true //默認爲false } }); var mask; mui.ready(function () { mask = mui.createMask();//callback爲用戶點擊蒙版時自動執行的回調; mask.show();//顯示遮罩 }) var sdRoot = null; document.addEventListener("plusready", function(){ init(); }, false); // 渲染列表 function init(){ // 得到sd卡根目錄 sdRoot = getSDRoot(); // 遍歷sd卡根目錄下的全部文件和文件夾 var files = plus.android.invoke(sdRoot,"listFiles"); var len = files.length; var list = document.getElementById("list"); var fragmentFolder = document.createDocumentFragment(); var fragmentFile = document.createDocumentFragment(); var li; for(var i=0;i<len;i++){ var file = files[i]; // 過濾隱藏文件 if(!plus.android.invoke(file,"isHidden")){ var name = plus.android.invoke(file,"getName"); li= document.createElement('li'); li.className = 'mui-table-view-cell mui-media'; li.setAttribute('name',name); // 判斷是文件仍是文件夾 if(plus.android.invoke(file,"isDirectory")){ // 設置標誌爲文件夾,供後面使用 li.setAttribute('data-type', 'Folder'); // 讀取文件夾下子文件夾及子文件數目 var obj = readSonFilenum(file); li.innerHTML = '<a class="mui-navigate-right">'+ '<img class="mui-media-object mui-pull-left" src="img/folder.png">'+ '<div class="mui-media-body">'+ name + '<p class="mui-ellipsis">文件夾數量:'+ obj.subFolderNum + ' 文件數量:'+ obj.subFileNum +'</p></div></a>'; fragmentFolder.appendChild(li); }else{ li.setAttribute('data-type', 'File'); // 讀文件大小 var fileSizeString = readFileSize(file); li.innerHTML = '<a class="mui-navigate-right">'+ '<img class="mui-media-object mui-pull-left" src="img/file.png">'+ '<div class="mui-media-body mui-ellipsis">'+ name + '<p class="mui-ellipsis">'+ fileSizeString +'</p></div></a>'; fragmentFile.appendChild(li); } }; } list.appendChild(fragmentFolder); list.appendChild(fragmentFile); // 關閉遮罩 mask.close(); document.querySelector('.loading').style.display = 'none'; } // 點擊打開文件 mui('.mui-table-view').on('tap','li',function(){ var name = this.getAttribute('name'); var fileType = this.getAttribute('data-type'); var filepath = sdRoot + '/' + name; if(fileType === 'Folder'){ // 打開目錄詳細頁面 mui.openWindow({ url: 'sub.html', id: 'sub', extras:{ name: name, filepath: filepath } }) }else{ // 打開文件 plus.runtime.openFile(filepath); } }) // 建立文件夾 document.querySelector('#add').addEventListener('tap',function (e) { e.detail.gesture.preventDefault(); //修復iOS 8.x平臺存在的bug,使用plus.nativeUI.prompt會形成輸入法閃一下又沒了 var btnArray = ['取消', '肯定']; mui.prompt('請輸入要建立的文件夾名:', '文件夾名', '建立文件夾', btnArray, function(e) { if (e.index == 1) { creatFolder(sdRoot+"/"+e.value); } else { plus.nativeUI.toast('你點了取消按鈕'); } }) }) // 長按刪除文件 mui('.mui-table-view').on('longtap','li',function(){ var name = this.getAttribute('name'); var btnArray = ['取消', '肯定']; mui.confirm('你肯定要刪除這個文件夾?', '刪除文件夾', btnArray, function(e) { if (e.index == 1) { deleteFile(sdRoot+"/"+name); } else { plus.nativeUI.toast('你點了取消按鈕'); } }) }) </script> </body> </html>
Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED);
File skRoot = Environment.getExternalStorageDirectory();
File fileRoot = Context.getFilesDir()+"\";
得到文件或文件夾的絕對路徑和相對路徑。區別:
String path = File.getPath();//相對 String path = File.getAbsoultePath();//絕對
得到文件或文件夾的父目錄
String parentPath = File.getParent();
得到文件或文件夾的名稱:
String Name = File.getName();
File.mkDir(); //創建文件夾 File.createNewFile();//創建文件
File.isDirectory() File.isDirectory()
File[] files = File.listFiles();
File.renameTo(dest);
File.delete();
這裏列出原生的經常使用方法,你們能夠根據須要進行實現。
寫到這裏,本篇本應該繼續講講5+ sdk集成中的各類細節,可是想一想本篇做爲nativejs的開篇,先簡單介紹這個實例,讓你們根據須要本身實現或許更好,本文僅供參考。
文章最後仍是要放上文檔和本文詳細工程:
寫文章不容易,也許寫這些代碼就幾分鐘的事,寫一篇你們好接受的文章或許須要幾天的醞釀,而後加上幾天的碼字,累並快樂着。若是文章對您有幫助請我喝杯咖啡吧!
近期在segmentfault講堂開設了一場關於html5+ App開發工程化實踐之路的講座,會講到5+ 開發中高性能的優化方案以及使用如何結合Vue.js進行開發,歡迎前來圍觀:https://segmentfault.com/l/15...。