PhoneGap的js回調有幾種實現方式。其中一種是ajax。java
咱們先來看一下js端相關代碼:android
// file: lib/android/plugin/android/callback.js define("cordova/plugin/android/callback", function(require, exports, module) { var port = null, token = null, xmlhttp; function startXhr() { // cordova/exec depends on this module, so we can't require cordova/exec on the module level. var exec = require('cordova/exec'), xmlhttp = new XMLHttpRequest(); // Callback function when XMLHttpRequest is ready xmlhttp.onreadystatechange=function(){ if (!xmlhttp) { return; } if (xmlhttp.readyState === 4){ // If callback has JavaScript statement to execute if (xmlhttp.status === 200) { // Need to url decode the response var msg = decodeURIComponent(xmlhttp.responseText); setTimeout(startXhr, 1); exec.processMessages(msg); } // If callback ping (used to keep XHR request from timing out) else if (xmlhttp.status === 404) { setTimeout(startXhr, 10); } // 0 == Page is unloading. // 400 == Bad request. // 403 == invalid token. // 503 == server stopped. else { console.log("JSCallback Error: Request failed with status " + xmlhttp.status); exec.setNativeToJsBridgeMode(exec.nativeToJsModes.POLLING); } } }; if (port === null) { port = prompt("getPort", "gap_callbackServer:"); } if (token === null) { token = prompt("getToken", "gap_callbackServer:"); } xmlhttp.open("GET", "http://127.0.0.1:"+port+"/"+token , true); xmlhttp.send(); } module.exports = { start: function() { startXhr(); }, stop: function() { if (xmlhttp) { var tmp = xmlhttp; xmlhttp = null; tmp.abort(); } }, isAvailable: function() { return ("true" != prompt("usePolling", "gap_callbackServer:")); } }; });
主要的處理是startXhr函數。它向java的server端發起了ajax請求,在onreadystatechange這個回調函數中等待server端返回結果。若是server端返回的結果正確,則再經過setTimeout(startXhr, 1)函數,1豪秒後再從新向server端發起ajax請求。若是從server返回的結果狀態是404,則每隔10豪秒,從新向server端發起ajax請求。ajax
接下來看看server端是如何處理的。server端的處理代碼是CallbackServer.java中的run()方法中。app
先看server端的源碼:dom
它經過serverSocket來模擬http的server端。其中,jsMessageQueue中是從java端發送的js消息,serverSocket在接收到客戶端(js端)的請求後,會將jsMessageQueue中的js代碼發送到客戶端(js端)。socket
/** * Start running the server. * This is called automatically when the server thread is started. */ public void run() { // Start server try { this.active = true; String request; waitSocket = new ServerSocket(0); this.port = waitSocket.getLocalPort(); //Log.d(LOG_TAG, "CallbackServer -- using port " +this.port); this.token = java.util.UUID.randomUUID().toString(); //Log.d(LOG_TAG, "CallbackServer -- using token "+this.token); while (this.active) { //Log.d(LOG_TAG, "CallbackServer: Waiting for data on socket"); Socket connection = waitSocket.accept(); BufferedReader xhrReader = new BufferedReader(new InputStreamReader(connection.getInputStream()), 40); DataOutputStream output = new DataOutputStream(connection.getOutputStream()); request = xhrReader.readLine(); String response = ""; //Log.d(LOG_TAG, "CallbackServerRequest="+request); if (this.active && (request != null)) { if (request.contains("GET")) { // Get requested file String[] requestParts = request.split(" "); // Must have security token if ((requestParts.length == 3) && (requestParts[1].substring(1).equals(this.token))) { //Log.d(LOG_TAG, "CallbackServer -- Processing GET request"); String payload = null; // Wait until there is some data to send, or send empty data every 10 sec // to prevent XHR timeout on the client while (this.active) { if (jsMessageQueue != null) { payload = jsMessageQueue.popAndEncode(); if (payload != null) { break; } } synchronized (this) { try { this.wait(10000); // prevent timeout from happening //Log.d(LOG_TAG, "CallbackServer>>> break <<<"); break; } catch (Exception e) { } } } // If server is still running if (this.active) { // If no data, then send 404 back to client before it times out if (payload == null) { //Log.d(LOG_TAG, "CallbackServer -- sending data 0"); response = "HTTP/1.1 404 NO DATA\r\n\r\n "; // need to send content otherwise some Android devices fail, so send space } else { //Log.d(LOG_TAG, "CallbackServer -- sending item"); response = "HTTP/1.1 200 OK\r\n\r\n"; response += encode(payload, "UTF-8"); } } else { response = "HTTP/1.1 503 Service Unavailable\r\n\r\n "; } } else { response = "HTTP/1.1 403 Forbidden\r\n\r\n "; } } else { response = "HTTP/1.1 400 Bad Request\r\n\r\n "; } //Log.d(LOG_TAG, "CallbackServer: response="+response); //Log.d(LOG_TAG, "CallbackServer: closing output"); output.writeBytes(response); output.flush(); } output.close(); xhrReader.close(); } } catch (IOException e) { e.printStackTrace(); } this.active = false; //Log.d(LOG_TAG, "CallbackServer.startServer() - EXIT"); }