Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android PhoneGap 1.7 calling a javascript function

Ok so I need to give a bit of background. First I am using jquery-mobile with PhoneGap 1.7. I have coded a very simple Java server that uses the ServerSocket object. On the Android phone, I connect to the server, and upon doing so the server sends data over the socket. This part is working.

The part I am stuck with is that I intend on sending data over that socket that will require the jquery mobile UI to be updated upon reception of data.


Answer: Simon was a massive help and I figured it out with his help and following this tutorial

The part that really hit me was having the thread spawned in the PhoneGap plugin itself. Once I realized that, everything fell into place. However, for anyone interested here is the code. Keep in mind, I took a lot from the tutorial. I also included the very simple Java server I created to test these concept. I figured maybe this would help someone in the future. Just remember, this is basically a proof of concept.

I need to revamp this plugin to suit my actual needs:

Android Activity: import org.apache.cordova.DroidGap;

import android.os.Bundle;

public class ISSAndroidActivity extends DroidGap {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.loadUrl("file:///android_asset/www/index.html");
    }
}

PhoneGap Plugin:

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;

import org.apache.cordova.api.*;
import org.apache.cordova.api.PluginResult;
import org.apache.cordova.api.PluginResult.Status;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

public class InvokeJavaScriptPlugin extends Plugin {
    public static String PLUGIN_TAG = "InvokeJavaScriptPlugin";
    public static String PROCESS_DATA_ACTION = "processData";
    private String callBackId = "";

    @Override
    public PluginResult execute(String action, JSONArray args, String callbackId) {
        PluginResult pluginResult = null;
        Log.d(PLUGIN_TAG, "Invoking Javascript w\\ NO_RESULT");

        if (action.equals(PROCESS_DATA_ACTION)) {
            this.callBackId = callbackId;
            startProcessingData();
            pluginResult = new PluginResult(Status.NO_RESULT);
            pluginResult.setKeepCallback(true);
        } else {
            pluginResult = new PluginResult(Status.INVALID_ACTION);
            Log.e(PLUGIN_TAG, "Invalid action : " + action);
        }
        return pluginResult;
    }

    /**
     * Spawns a thread that connects to a server, and receives data from it
     */
    private void startProcessingData() {
        new Thread() {
            @Override
            public void run() {

                // Socket Testing
                ObjectOutputStream out;
                ObjectInputStream in;
                Socket requestSocket = new Socket();
                Object inboundObject;

                SocketAddress ipAddr = new InetSocketAddress("192.168.1.2",
                        2012);
                try {
                    requestSocket.connect(ipAddr);

                    out = new ObjectOutputStream(
                            requestSocket.getOutputStream());
                    out.flush();
                    in = new ObjectInputStream(requestSocket.getInputStream());

                    do {
                        inboundObject = in.readObject(); // Data is received
                                                         // here
                        int processedData = ((Number) inboundObject).intValue();
                        onProcessDataReadSuccess(processedData);

                    } while (requestSocket.isConnected());

                } catch (SocketException ex) {
                    Log.d(PLUGIN_TAG, "Connection to Server lost");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }.start();
    }

    /**
     * Callback method for startProcessingData(). Sends the result up to
     * javascript layer via Plugin.success()<br>
     * This method is automatically called asynchronously when processing is
     * finished.
     * 
     * @param processedData
     *            the result of data processing which will be passed back to
     *            javascript.
     */
    private void onProcessDataReadSuccess(int processedData) {
        Log.d(PLUGIN_TAG, "Processing data: " + processedData);
        PluginResult result;
        try {
            JSONObject resultJSON = new JSONObject();
            resultJSON.put("processedData", processedData);
            result = new PluginResult(Status.OK, resultJSON);
        } catch (JSONException jsonEx) {
            Log.e(PLUGIN_TAG, "Got JSON Exception " + jsonEx.getMessage());
            jsonEx.printStackTrace();
            result = new PluginResult(Status.JSON_EXCEPTION);
        }

        result.setKeepCallback(true);
        this.success(result, this.callBackId);
    }
}

index.html:

<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<link type="text/css" href="css/jquery.mobile-1.1.0.min.css"
    rel="stylesheet" />
</head>
<script type="text/javascript" charset="utf-8"
    src="scripts/cordova-1.7.0.js"></script>
<script type="text/javascript" src="scripts/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="scripts/jquery.mobile-1.1.0.min.js"></script>
<script type="text/javascript" src="scripts/InvokeJavaScript.js"></script>
<script type="text/javascript" charset="utf-8">
    document.addEventListener('deviceready', function() {
        window.plugins.InvokeJavaScript.processData(function(result) {
            displayProcessedData(result)
        }, function(error) {
            console.log(error)
        });
    }, true);

    function displayProcessedData(result) {
        document.getElementById("processedData").innerHTML = result.processedData;
    }
</script>

<body>
    <div data-role="page">
        <div data-role="header" data-position="fixed">
            <h1>Demo</h1>
        </div>
        <div data-role="content">
            Result:
            <div id="processedData"></div>
        </div>
        <div data-role="footer" data-position="fixed">
            <div data-role="navbar"></div>
        </div>
    </div>
</body>
</html>

Server.java

import java.io.BufferedReader;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ISSServer {

    private static Socket androidSocket;
    private static ServerSocket serverSocket;
    static ObjectOutputStream out;
    static BufferedReader in;

    public static void main(String[] args) {
        System.out.println("Listen Thread: Waiting for connection");
        int port_number = 2012; // The default port

        try {
            serverSocket = new ServerSocket(port_number);
            androidSocket = serverSocket.accept();

            System.out.println("Connection established");

            out = new ObjectOutputStream(androidSocket.getOutputStream());
            out.flush();
            // in = new BufferedReader(new
            // InputStreamReader(androidSocket.getInputStream()));

            out.writeObject(1337);
            out.flush();
            out.reset();
            System.out.println("1337 sent");
            Thread.sleep(2000);

            out.writeObject(9999);
            out.flush();
            out.reset();
            System.out.println("9999 sent");
            Thread.sleep(2000);

            out.writeObject(1234);
            out.flush();
            out.reset();
            System.out.println("1234 sent");
            Thread.sleep(2000);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
like image 663
Jeff Avatar asked May 26 '12 18:05

Jeff


1 Answers

You are making this way to hard on yourself. If you use a PhoneGap Plugin you will be able to save the callback ID of the initial JavaScript call then send back a PluginResult which you call result.setKeepCallback(true) and where the status PluginResult.Status.NO_RESULT.

Then whenever you get and update on the Java side you create a new PluginResult. Set the status to OK, the data to whatever you want to send and of course before you return it setKeepCallback(true). Then call this.success(callbackId, result) and your JS side will get continuous updates.

like image 151
Simon MacDonald Avatar answered Nov 17 '22 08:11

Simon MacDonald