Web Storm 2018.1
(1) 除了IOS一塊,其餘均建議閱讀並操作
(2) 將webStorm-APICloud加入到項目中
(3) 安裝好需要的插件
具體創建應用操作步驟:https://docs.apicloud.com/APICloud/creating-first-app
(1) 採用SVN下載代碼,然後導入到Web Storm
(2) 採用Subversion
(1) 新建一個底部導航應用
(2) 啓動Wifi真機測試
具體API:https://docs.apicloud.com/Client-API/
API.js文檔:https://docs.apicloud.com/Front-end-Framework/framework-dev-guide#37
api.addEventListener({ name: 'keyback' }, function (ret, err) { api.confirm({ title: '提示', msg: "確認退出應用?", buttons: ['確定', '取消'] }, function (ret, err) { var index = ret.buttonIndex; if (index == 1) { api.closeWin(); } return; }); });
api.call({ type: 'tel', // 直接撥打,無任何提示 number: '10086' // 電話號碼 });
參數說明:https://docs.apicloud.com/Client-API/api#7
execScript:在指定 window 或者 frame 中執行腳本,對於 frameGroup 裏面的 frame 也有效,若 name 和 frameName 都未指定,則在當前 window 中執行腳本,具體執行邏輯見補充說明。
execScript({params})
<?xml version="1.0" encoding="UTF-8"?><widget id="A6080528176396" version="0.0.1"> <name>demo1_nav</name> <!--app的名稱--> <description> Example For APICloud. </description> <author email="[email protected]" href="http://www.apicloud.com"> Developer </author> <content src="grid.html"/> <!--默認app進入的主頁地址--> <preference name="appBackground" value="rgba(0,0,0,0)"/> <preference name="windowBackground" value="rgba(0,0,0,0)"/> <preference name="frameBackgroundColor" value="rgba(0,0,0,0)"/> <preference name="autoLaunch" value="true"/> <preference name="autoUpdate" value="true"/> <preference name="smartUpdate" value="false"/> <preference name="debug" value="false"/> <preference name="statusBarAppearance" value="true"/> <permission name="location"/> <permission name="internet"/> <access origin="*"/> </widget>
https://github.com/lihongxun945/jquery-weui/releases
如果頁面條目過多,需要進行分頁顯示,用戶上滑數據加載下一頁數據,具體實現如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>demo-header</title> <!--標準mui.css--> <link rel="stylesheet" href="../../css/mui.min.css"> <!--App自定義的css--> <link rel="stylesheet" type="text/css" href="../../css/app.css"/> <link rel="stylesheet" type="text/css" href="../../css/my.css"/> </head> <body> <header class="mui-bar mui-bar-nav" id="topbar"> <a class=" mui-icon mui-icon-left-nav mui-pull-left" href="#" onclick="goBeforePage()"></a> <h1 class="mui-title" id="title">示例</h1> </header> <div class="mui-content"> <ul class="mui-table-view mui-table-view-chevron" id="showResult"> </ul> </div> <script src="../../js/mui.js"></script> <script type="text/javascript" src="../../script/api.js"></script> <script type="text/javascript" src="../../js/request.js"></script> <script type="text/javascript" src="../../js/dot.min.js"></script> <script type="text/javascript" src="../../js/toastUtils.js"></script> <script type="text/javascript" src="../../js/error.js"></script> <script type="text/javascript"> apiready = function () { var header = $api.byId('topbar'); //適配iOS7+,Android4.4+狀態欄沉浸式效果,詳見config文檔statusBarAppearance字段 // $api.fixStatusBar(header); //動態計算header的高度,因iOS7+和Android4.4+上支持沉浸式效果, //因此header的實際高度可能爲css樣式中聲明的44px加上設備狀態欄高度 //其中,IOS狀態欄高度爲20px,Android爲25px var headerH = $api.offset(header).h; //frame的高度爲當前window高度減去header和footer的高度 var frameH = api.winHeight - headerH; api.openFrame({ name: 'detection-search-result-list', url: './detection-search-result-list.html', rect: { x: 0, y: headerH, w: api.winWidth, h: frameH }, pageParam: { itemsId: api.pageParam.itemsName, itemsId: api.pageParam.itemsId }, bounces: true, bgColor: 'rgba(0,0,0,0)', vScrollBarEnabled: true, hScrollBarEnabled: true }); $api.dom('#title').innerHTML = api.pageParam.itemsName; }; // 返回上一個頁面 function goBeforePage() { api.closeWin(); } </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>檢測-檢測記錄</title> <!--標準mui.css--> <link rel="stylesheet" href="../../css/mui.min.css"> <!--App自定義的css--> <link rel="stylesheet" type="text/css" href="../../css/app.css"/> <link rel="stylesheet" type="text/css" href="../../css/my.css"/> </head> <body> <div class="mui-content"> <ul class="mui-table-view mui-table-view-chevron" id="showResult"> </ul> </div> <script src="../../js/mui.js"></script> <script type="text/javascript" src="../../script/api.js"></script> <script type="text/javascript" src="../../js/request.js"></script> <script type="text/javascript" src="../../js/dot.min.js"></script> <script id="searchResultTemp" type="text/x-dot-template"> {{ for(var x in it) { }} <li class="mui-table-view-cell mui-collapse"> <a class="mui-navigate-right" href="#">{{=it[x].date}}</a> <ul class="mui-table-view mui-table-view-chevron"> {{ for(var t in it[x].result) { }} <li class="mui-table-view-cell"><a href="#"> {{? it[x].result[t].userName!==null }} {{=it[x].result[t].userName}} {{?? it[x].result[t].userName==null}} ---- {{??}} {{?}} {{=it[x].result[t].detectionResult}} {{=it[x].result[t].detectionAnalysis}} {{? it[x].result[t].age!==null }} {{=it[x].result[t].age}}歲 {{?? it[x].result[t].age==null}} ---- {{??}} {{?}} {{? it[x].result[t].sex === "0" }} 女 {{?? it[x].result[t].sex === "1"}} 男 {{??}} {{?}} </a> </li> {{ } }} </ul> </li> {{ } }} </script> <script type="text/javascript" src="../../js/toastUtils.js"></script> <script type="text/javascript" src="../../js/error.js"></script> <script type="text/javascript"> var pageIndex = 0; var pageSize = 15; var userId = ""; var itemsId = ""; apiready = function () { api.addEventListener({name: 'scrolltobottom'}, function (ret, err) { toDoRequest(); }); userId = $api.getStorage(CURRENT_USER)["id"]; itemsId = api.pageParam.itemsId; toDoRequest(); }; // 刷新 初始化加載 function toDoRequest() { showProgress('加載中', '加載數據中.....'); API.detection.getDetectionByItems(userId, itemsId, pageIndex, pageSize, function (ret, err) { api.refreshHeaderLoadDone(); //復位下拉刷新 api.hideProgress(); if (!globalException(err)) { return; } pageIndex++; if(ret["data"]==null||ret["data"].length==0){ showToast('無更多數據加載',1000); return ; } var evaluation = doT.template($api.dom('#searchResultTemp').innerHTML); $api.dom('#showResult').innerHTML += evaluation(ret["data"]); }); } </script> </body> </html>
$api.get('http://192.168.2.66:8081/app/index', function (ret) { alert($api.jsonToStr(ret)); }, 'json');
api.ajax({ url: 'http://192.168.2.66:8081/app/index', method: 'get', },function(e){ alert($api.jsonToStr(e)); });
當使用web方式顯示數據列表時,使用js模板可以有效提高開發效率。使用方式如下:
https://github.com/olado/doT
<script type="text/javascript" src="../../script/api.js"></script> <script type="text/javascript" src="../../js/dot.min.js"></script>
<ul class="mui-table-view mui-grid-view mui-grid-12"> <div id="itemsDataDiv"></div> <script id="itemsDataTemp" type="text/x-dot-template"> {{ for(var x in it) { }} <li class="mui-table-view-cell mui-media mui-col-xs-3 mui-col-sm-3"> <a href="#" onclick="goToItems(3)" tapmode> <img src="../../image/cbd.jpg" class="indeximg"/> <div class="mui-media-body">{{=it[x].itemsName}}</div> </a> </li> {{ } }} </script> </ul>
apiready = function () { doFindAllItems(); }; // 查詢所有的檢測項目 function doFindAllItems(){ //TODO: var data = [ {itemsName:"A",itemsIcon:"../../image/cbd.jpg",}, {itemsName:"B",itemsIcon:"../../image/cbd.jpg",}, {itemsName:"C",itemsIcon:"../../image/cbd.jpg",}, {itemsName:"D",itemsIcon:"../../image/cbd.jpg",}, ]; // var evaluation = doT.template($api.dom('#itemsDataTemp').innerHTML); $api.dom('#itemsDataDiv').innerHTML = evaluation(data); }
- 在APICloud中創建新的項目
- 在git中創建repository,命名爲demoApp
- 編寫項目,即widget
1 在與widget同級的情況下,運行git bash,然後輸入
$ git init
2 與遠程庫(demoApp)關聯
git remote add origin https://github.com/xx/demoApp.git
3 推送代碼到遠程庫
$ git add . $ git commit -m "commit message" $ git push -u origin master
當做完以上操作後,之後進行雲編譯,然後下載App.
在本機安裝shadowsockets 然後設置本機ip端口爲1081 ,最後file->setting->System Settings-> Http Proxy
配置完畢後,進行測試
開發之前,下載【模塊開發SDK】,地址:https://docs.apicloud.com/Download/download
在用Android Studio打包模塊並測試,發現so文件並不能加載,具體原因因爲調試環境限制,暫時不明確(AS可以開發不需要so文件的模塊,調用無問題)。故採用Eclipse開發模塊。具體步驟如下:
1、下載SDK模塊開發項目,並導入到Eclipse工作空間
2、創建 apiDigital 模塊,並加入代碼
3、加入需要的依賴,並build path
4、加入需要的libXXX.so庫
5、映射
package com.apicloud.apiDigital; import com.uzmap.pkg.uzcore.UZWebView; import com.uzmap.pkg.uzcore.uzmodule.UZModule; import com.uzmap.pkg.uzcore.uzmodule.UZModuleContext; import com.xmgh.digitalreader.proxy.DigitalReaderProxy; /** * 該類映射至Javascript中apiDigital對象<br> * <br> * <strong>Js Example:</strong><br> * var module = api.require('apiDigital');<br> * module.xxx(); * * @author fangping */ public class APIDigitalModule extends UZModule {// 需要繼承UZModule private static DigitalReaderProxy digitalReaderProxy = null; public APIDigitalModule(UZWebView webView) { super(webView); } /** * <strong>函數</strong><br> * <br> * 該函數映射至Javascript中moduleDemo對象的showAlert函數<br> * <br> * <strong>JS Example:</strong><br> * moduleDemo.showValue(argument); * * @param moduleContext * (Required) */ public void jsmethod_showValue(final UZModuleContext moduleContext) throws JSONException { JSONObject ret = new JSONObject(); ret.put("msg", "Hello"); moduleContext.success(ret, false); } }
6、導出jar,只導出該模塊的代碼即可
然後點擊【Finish】即可。
7、資源修改
8、頁面調用
9、打包的項目結構,新建一個與模塊名一致的文件夾
文件夾說明:
res_apiDigital
(可選目錄):
1)、該目錄命名規範必須爲「res_」開頭,後面跟模塊名。例如「res_apiDigital」。
2)、res_apiDigital目錄中內容審覈: res_apiDigital的根路徑下最多僅允許包含res子目錄和AndroidManifest.xml文件,如圖:
這兩個文件對應項目中的:
sources
: source目錄爲必須目錄。
1)、該目錄爲模塊的代碼導出的JAR文件及其依賴的JAR所在目錄,可存放多個JAR文件。
2)、該目錄下均存放的.jar後綴名的文件,如apiDigital.jar、digitalreaderproxylibrary.jar.jar、tencent.jar。
4)、該目錄下不允許存放名爲android-support-v4.jar的文件。
5)、該目錄下不允許存放名類似爲apiEngine v1.1.0.jar的文件。
截圖如下:
target:
該目錄爲可選目錄。
實際複製模塊項目中的:
1)、該目錄爲模塊用到的so庫其依賴的so庫所在目錄,可存放多個so文件。
2)、該目錄允許包含子目錄,如armeabi-v7a、arm64、x86、mips等,這些子目錄均爲可選。
10、新建module.json,添加內容如下
{ name:'apiDigital', class:'com.apicloud.apiDigital.APIDigitalModule' }
11、壓縮打包成zip即可
12、加入自定義模塊,並添加到項目中.頁面調用模塊,不再累述
13、注意
res中需要去掉以下配置,以防衝突導致app編譯失敗
<resources> <string name="app_name">apiDigital</string> </resources>
AndroidManifest.xml只加入對應的權限以及其他Activity,多餘的去掉
加入so庫,不需要加入libsec.so
14、參考
代碼:
package com.apicloud.apiDigital; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.UUID; import org.json.JSONException; import org.json.JSONObject; import com.uzmap.pkg.uzcore.uzmodule.UZModuleContext; public class UploadUtil { private static final int TIME_OUT = 180 * 1000; // 超時時間 private static final String CHARSET = "utf-8"; // 設置編碼 /** * android上傳文件到服務器 * * @param file * 需要上傳的文件 * @param RequestURL * 請求的rul * @param userId * @param itemsId * @param batchCode * @param moduleContext * @return 返回響應的內容 */ public static String uploadFile(File file, String RequestURL, String itemsId, String userId, String batchCode, UZModuleContext moduleContext) { String result = null; String BOUNDARY = UUID.randomUUID().toString(); // 邊界標識 隨機生成 String PREFIX = "--", LINE_END = "\r\n"; String CONTENT_TYPE = "multipart/form-data"; // 內容類型 DataOutputStream dos = null; InputStream is = null; try { URL url = new URL(RequestURL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(TIME_OUT); conn.setConnectTimeout(TIME_OUT); conn.setDoInput(true); // 允許輸入流 conn.setDoOutput(true); // 允許輸出流 conn.setUseCaches(false); // 不允許使用緩存 conn.setRequestMethod("POST"); // 請求方式 conn.setRequestProperty("Charset", CHARSET); // 設置編碼 conn.setRequestProperty("connection", "keep-alive"); conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY); conn.connect(); if (file != null) { /** * 當文件不爲空,把文件包裝並且上傳 */ dos = new DataOutputStream(conn.getOutputStream()); // StringBuffer sb = new StringBuffer(); sb.append(PREFIX); sb.append(BOUNDARY); sb.append(LINE_END); sb.append("Content-Disposition: form-data;name=\"itemsId\""); sb.append(LINE_END); sb.append(LINE_END); sb.append(itemsId); sb.append(LINE_END); dos.write(sb.toString().getBytes()); // 用戶 sb = new StringBuffer(); sb.append(PREFIX); sb.append(BOUNDARY); sb.append(LINE_END); sb.append("Content-Disposition: form-data;name=\"userId\""); sb.append(LINE_END); sb.append(LINE_END); sb.append(userId); sb.append(LINE_END); dos.write(sb.toString().getBytes()); // sb = new StringBuffer(); sb.append(PREFIX); sb.append(BOUNDARY); sb.append(LINE_END); sb.append("Content-Disposition: form-data;name=\"batchCode\""); sb.append(LINE_END); sb.append(LINE_END); sb.append(batchCode); sb.append(LINE_END); dos.write(sb.toString().getBytes()); sb = new StringBuffer(); sb.append(PREFIX); sb.append(BOUNDARY); sb.append(LINE_END); /** * 這裏重點注意: name裏面的值爲服務器端需要key 只有這個key 纔可以得到對應的文件 * filename是文件的名字,包含後綴名的 比如:abc.png */ sb.append("Content-Disposition: form-data; name=\"Fdata\"; filename=\"" + file.getName() + "\"" + LINE_END); sb.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINE_END); sb.append(LINE_END); dos.write(sb.toString().getBytes()); is = new FileInputStream(file); byte[] bytes = new byte[1024]; int len = 0; while ((len = is.read(bytes)) != -1) { dos.write(bytes, 0, len); } is.close(); dos.write(LINE_END.getBytes()); byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END) .getBytes(); dos.write(end_data); dos.flush(); /** * 獲取響應碼 200=成功 當響應成功,獲取響應的流 */ int res = conn.getResponseCode(); if (res == 200) { // is = conn.getInputStream(); BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8")); StringBuffer sb1 = new StringBuffer(); int ss; while ((ss = in.read()) != -1) { sb1.append((char) ss); } result = sb1.toString(); JSONObject ret = new JSONObject(); ret.put("msg", result); ret.put("identity", 1); file.delete();// 刪除上傳 moduleContext.success(ret, true); }else{ JSONObject ret = new JSONObject(); ret.put("msg", "請求失敗,請聯繫後臺管理員"); ret.put("identity", -1); moduleContext.success(ret, true); } } } catch (MalformedURLException e) { JSONObject ret = new JSONObject(); try { ret.put("msg", e.getMessage()); ret.put("identity", -1); } catch (JSONException e1) { e1.printStackTrace(); } moduleContext.success(ret, true); e.printStackTrace(); } catch (Exception e) { JSONObject ret = new JSONObject(); try { ret.put("msg", e.getMessage()); ret.put("identity", -1); } catch (JSONException e1) { e1.printStackTrace(); } moduleContext.success(ret, true); e.printStackTrace(); } finally { try { if (dos != null) { dos.close(); } if (is != null) { is.close(); } } catch (Exception e) { e.printStackTrace(); } } return result; } }
1 效果如下:
2 步驟如下
自定義模板scanner.html頁面
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="maximum-scale=1.0, minimum-scale=1.0, user-scalable=0, initial-scale=1.0, width=device-width" /> <meta name="format-detection" content="telephone=no, email=no, date=no, address=no"> <title>Hello APP</title> <link rel="stylesheet" type="text/css" href="../css/api.css" /> <style> html,body { padding-top: 80px; background-color: transparent; padding-left: 0%; } /*.box{width: 18%;height: 80px;margin: 0 auto;background: #fff;}*/ .box{width: 400px;height: 100px;margin: 0 auto; border: 2px dotted #f3f3f7; margin-left:-15%; /*旋轉90度*/ -webkit-transform: rotate(90deg); /* Safari and Chrome */ -moz-transform: rotate(90deg); /* Firefox */ -moz-transform: rotate(90deg); /* Firefox */ -ms-transform: rotate(90deg); /* IE 9 */ -o-transform: rotate(90deg); /* Opera */ transform: rotate(90deg);} .linebox { width: 173px; float: left; margin-left: 25%; margin-top: 16px; } .line{display: block; width:5px;height:30px;float: left; margin:25PX 25PX;border: 2px dotted #f3f3f7; } .Rightbox { float: left; margin-left: 70px; margin-top: 32px; } .circle{display: block; width:40px;height:30px;border-radius:40%; border: 2px dotted #f3f3f7; } /**f3f3f7**/ </style> </head> <body> <!--<a class="button" tapmode="active" onclick="fnTakePhoto()">拍照 </a>--> <div class="box"> <span class="linebox" id="lineBox"> <span class="line"></span> <span class="line"></span> </span> <div class="Rightbox"> <span class="circle"></span> </div> </div> </body> <script type="text/javascript" src="../../../script/api.js"></script> </html>
頁面調用js
// 切換手機拍照 function doChangePhoto() { var header = $api.dom('header'); // 獲取 header 標籤元素 var headerH = $api.fixStatusBar(header); var FNPhotograph = api.require('FNPhotograph'); var curdate = new Date(); var photoPath = 'fs://FNPhotograph/' + curdate.getTime() + '.jpg'; exitFlag = false; FNPhotograph.open({ path: photoPath, album: true, quality: 'high', qualityValue:100 }, function (ret) { if (ret.eventType == 'show') { api.openFrame({ name: 'scanner', url: './photo/scanner.html', bounces: true, rect: { // 推薦使用Margin佈局,用於適配屏幕的動態變化 x: 30, // main頁面距離win頂部的高度 y: 80, // main頁面距離win底部的高度 // w: 'auto' // main頁面的寬度 自適應屏幕寬度 w: 'auto', h: '430px', }, bounces: false, }); } else if (ret.eventType == 'takePhoto') { console.log(JSON.stringify(ret)); var imagePath = ret.imagePath; if (imagePath != null) { api.openWin({ name: 'detection-takephoto-submit', url: './photo/detection-takephoto-submit.html', rect: { api.openFrame({ name: 'scanner', url: './photo/scanner.html', bounces: true, rect: { // 推薦使用Margin佈局,用於適配屏幕的動態變化 x: 30, // main頁面距離win頂部的高度 y: 80, // main頁面距離win底部的高度 // w: 'auto' // main頁面的寬度 自適應屏幕寬度 w: 'auto', h: '430px', }, bounces: false, }); } else if (ret.eventType == 'takePhoto') { console.log(JSON.stringify(ret)); var imagePath = ret.imagePath; if (imagePath != null) { api.openWin({ name: 'detection-takephoto-submit', url: './photo/detection-takephoto-submit.html', rect: { w: api.winWidth, h: api.winWidth }, pageParam: {imagePath: imagePath} }); } } else if (ret.eventType == 'close') { // document.getElementById('abc').src = ret.imagePath; // api.closeFrame({ // name: 'scanner' goToBeforePage(); } }); }
首先下載安裝Fiddler,運行後選擇菜單Tools->Fiddler Options。
選中"Decrpt HTTPS traffic",Fiddler就可以截獲HTTPS請求:
選中"Allow remote computers to connect",是允許別的機器把HTTP/HTTPS請求發送到Fiddler上來:
配置完成後重啓Fiddler。
1.獲取當前電腦的IP地址,例如我這裏是:192.168.2.65
2.在iPhone中打開safari並訪問地址http://192.168.2.65:8888,點"FiddlerRoot certificate"然後安裝證書:
在iPhone上打開設置->無線局域網,點擊當前WIFI後面的i圖標查看當前連接信息,滾動到底部的HTTP代理,切換爲「手動」:
使用中彈出:
creation of the root certificate was not successful
解決如下:
cd d:\Program Files\Fiddler makecert.exe -r -ss my -n "CN=DO_NOT_TRUST_FiddlerRoot, O=DO_NOT_TRUST, OU=Created by http://www.fiddler2.com" -sky signature -eku 1.3.6.1.5.5.7.3.1 -h 1 -cy authority -a sha1 -m 120 -b 09/05/2012
再安裝證書
現在apicloud官方不提供測試版本的IOS證書, 所以這裏使用一個工具去生成IOS證書。
1.創建免費的蘋果開發者賬號的過程
2.申請ios證書步驟說明,這一步主要弄證書以及描述文件即可
3.打包ios的步驟說明
4.apicloud官方說明一些問題
5.博客說明ios證書
地址:https://blog.csdn.net/xxw888/article/details/76083152
6.注意
蘋果端安裝ipa,採用第三方去安裝。掃描二維碼以及ipa安裝,會報安裝失敗等錯誤。
1.app加入極光模塊
2.極光官網綁定app
3.修改config.xml,在配置文件中,加入以下配置
<feature name="ajpush"> <param name="channel" value="developer-danqiusheng" /> <param name="app_key" value="93458e2fe2c88736b455b743" /> <!--上面的AppKey--> </feature>
4.推送