[Android]PhoneGap源码分析——CallbackServer异步回调

本文详细介绍了PhoneGap中使用ajax实现JS回调的具体过程。通过分析JS端与Java端的源码,展示了如何建立并维持跨平台应用中的通信,包括JS端不断发起请求保持连接以及Java端如何响应这些请求。

    PhoneGap的js回调有几种实现方式。其中一种是ajax。

    我们先来看一下js端相关代码:

// 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请求。

    接下来看看server端是如何处理的。server端的处理代码是CallbackServer.java中的run()方法中。

    先看server端的源码:

    它通过serverSocket来模拟http的server端。其中,jsMessageQueue中是从java端发送的js消息,serverSocket在接收到客户端(js端)的请求后,会将jsMessageQueue中的js代码发送到客户端(js端)。

/**
     * 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");
    }

转载于:https://my.oschina.net/tingzi/blog/80038

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值