8 (phonegap源碼分析)JS與本地代碼交互(exec )

        這裏採用的是較早版本的phonegap框架中exec模塊的實現,代碼比較直觀易懂,後來的版本爲了提升代碼的健壯性,增加了很多選擇性代碼。爲了測試方便,直接使用簡單版本的exec模塊。更高版本的phonegap庫也是在這個基礎之上擴展的,可對比學習。

define("myphonegap/exec", function(require, exports, module) {
		 /**
		  * 執行cordova命令
		  * 同步:返回一個JSON字符串;異步:返回空字符串"",這個時候可以根據處理結果調用回調函數
		  * 參數:(1)success:命令執行成功回調函數
		  *       (2)fail:命令執行失敗回調函數
		  *       (3)service:使用的服務名稱
		  *       (4)action:在cordova中運行的命令
		  *       (5)args:0或多個參數組成的數組
		  */
		var myphonegap= require('myphonegap');

		module.exports = function(success, fail, service, action, args) {
			try {
				var callbackId = service + cordova.callbackId++;//內部回調id
				if (success || fail) {//至少傳入了其中一個
					myphonegap.callbacks[callbackId] = {success:success, fail:fail};
				}

			  //將參數轉化爲JSON字符串去執行
				var r = prompt(JSON.stringify(args), "gap:"+JSON.stringify([service, action, callbackId, true]));
				
				if (r.length > 0) {
					var v = JSON.parse(r);//將返回結果解析成對象
					if (v.status === myphonegap.callbackStatus.OK) {
						if (success) {//調用成功回調函數
							try {
								success(v.message);
							} catch (e) {
								console.log("Error in success callback: " + callbackId  + " = " + e);
							}

							// 清除回調函數
							if (!v.keepCallback) {
								delete myphonegap.callbacks[callbackId];
							}
						}
						return v.message;
					}
					else if (v.status === myphonegap.callbackStatus.NO_RESULT) {
						// 清除回調函數
						if (!v.keepCallback) {
							delete myphonegap.callbacks[callbackId];
						}
					}
					else {// 錯誤
						console.log("Error: Status="+v.status+" Message="+v.message);

						// 調用失敗回調函數
						if (fail) {
							try {
								fail(v.message);
							}
							catch (e1) {
								console.log("Error in error callback: "+callbackId+" = "+e1);
							}

							//清除回調函數
							if (!v.keepCallback) {
								delete myphonegap.callbacks[callbackId];
							}
						}
						return null;
					}
				}
			} catch (e2) {
				console.log("Error: "+e2);
			}
		};

	});

        這裏最重要的一個函數是window提供的prompt這個函數,它實際上就是用來與android的交互的。當js調用prompt之後,本地代碼WebChromeClient實例會回調一個onJsPrompt函數,在這個回調函數中接受js發送過來的參數信息,調用相應的serviceaction,同步的話直接返回結果,用result.confirm提交。異步調用,在調用結果返回之後,以回調ID和返回數據爲參數,調用myphonegap.callbackSuccess或myphonegap.callbackError

        下面測試測試本地代碼和JS代碼的交互,由本地代碼調用exec模塊,給本地代碼發送消息,本地代碼解析消息調用對應的方法,返回結果後。

        Js端添加測試代碼,先請求exec模塊。第一個請求執行的本地方法,類名爲Math,方法名爲plus,參數爲15,成功後打印輸出結果。第二個請求執行的本地方法,類名爲Math,方法名爲multiply,參數爲15

//測試exec模塊
	
var exec = require("myphonegap/exec");
	exec(function(ret){console.info("plus exec success!");console.info("15+15=" + ret)}, 
				function(){console.info("multiply exec failed!")}, 'Math', 'plus',15);
				
	exec(function(ret){console.info("multiply exec success!");console.info("15*15=" + ret)}, 
			function(){console.info("multiply exec failed!")}, 'Math', 'multiply',15);

Js執行prompt方法後,androidWebChromeClientonJsPrompt被調用,爲了測試簡單這裏只用了action區分調用的本地方法沒有使用service區分調用哪個類,plus操作爲同步方法,直接返回,multiply模擬爲異步方法,通過回調js裏面的方法返回結果。

private class MyWebChromeClient extends WebChromeClient{
		@Override
		public boolean onJsPrompt(WebView view, String url, String message,
				String defaultValue, JsPromptResult result) {
		
try {
              //array的解析與js端的封裝有關,字串過濾了”gap:”4個字符
		        JSONArray array = new JSONArray(defaultValue.substring(4));
		        String service = array.getString(0);
		        String action = array.getString(1);
		        String callbackId = array.getString(2);
		        
		        if(action.equals("plus")){
		        	int a = Integer.parseInt(message);
		        	int ret = plus(a,a);
		        	String str = "{\"status\":1,\"message\":" ;
		        	    str += ret;
		        		str += "}";
		        			
		        	result.confirm(str);
		        }else if(action.equals("multiply")){
		        	int a = Integer.parseInt(message);
		        	int ret = multiply(a,a);
		        	String str = "{\"status\":1,\"message\":" ;
		        	    str += ret;
		        		str += "}";
		        			
		        	result.confirm("");
		        	//此處採用異步模式,不使用result.confirm直接返回結果了。
		            	mWebView.loadUrl("javascript:myphonegap.callbackSuccess(\""+callbackId+"\","+str+")");
		        }
		       
		      } catch (JSONException e) {
		        e.printStackTrace();
		      }
						return true;
		}

本次測試採用了android真機測試。測試結果:



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