Sunday, May 19, 2024
 Popular · Latest · Hot · Upcoming
136
rated 0 times [  143] [ 7]  / answers: 1 / hits: 18543  / 11 Years ago, sat, april 6, 2013, 12:00:00

I have and application built with PhoneGap, and I'm trying to communicate with Javascript from native code.



in my DroidGap extending class:



@Override
public void onCreate(Bundle savedInstanceState) {
Logger.log(oncreate);
super.onCreate(savedInstanceState);
super.init();
super.appView.getSettings().setJavaScriptEnabled(true);
super.appView.getSettings().setSupportZoom(true);
super.appView.getSettings().setBuiltInZoomControls(true);
super.appView.getSettings().setDisplayZoomControls(false);
jsinterface = new CommunicationInterface(this, appView);
super.appView.addJavascriptInterface(jsinterface, communicationinterface);
}


the javascriptinterface:



public class CommunicationInterface {
private WebView mAppView;
private DroidGap mGap;

public CommunicationInterface(DroidGap gap, WebView view) {
mAppView = view;
mGap = gap;
}

public String getTestString() {
return teststring;
}

public void parse(Object o) {
Logger.log(o);
}
}


The Javacript is located in an external file (I create an HTML file which has this line in the header: <script type=text/javascript src=scripts.js></script>)



Scripts.js:



function sendToInterface() {
alert(alert);
var map = new Object();
(...)
window.communicationinterface.parse(map); //communication js -> android seems to work.
}


I read in other posts that it's possible to communicate between PhoneGap and Android, but thusfar I've not had any success. I did manage to create an alert, but that was with loadUrl(javascript:alert('Alert');), but I've also read that you shouldn't do because that's what sendJavascript() is for (and it causes leaks, reloads page, etc). I've tried to shoot a couple of Strings through the sendJavascript() method, but to no avail:




  • sendJavascript(javascript:alert('Alert');)

  • sendJavascript(javascript:sendToInterface();)

  • sendJavascript(sendToInterface();)

  • sendJavascript(window.sendToInterface();)



How to communicate from native -> PhoneGap (or what's wrong with what I already have)? Thusfar other posts and questions haven't helped me with this particular problem.



Read:





EDIT



I wrote a working project:



Java part



import org.apache.cordova.DroidGap;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.Bundle;
import android.util.Log;

public class App extends DroidGap {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.loadUrl(file:///sdcard/ds/index.html);
System.out.println(loading from sdcard);
Thread t = new Thread() {
public void run() {
try {
for (int i = 0; i < 3; i++) {
sleep(2000);
sendValue(value + i, another vlaue + i);
}
} catch (Exception e) {
e.printStackTrace();
}
};
};
t.start();
}

public void sendValue(String value1, String value2) {

System.out.println(sendvalue in app);
JSONObject data = new JSONObject();
try {
data.put(value1, value1);
data.put(value2, value2);
} catch (JSONException e) {
Log.e(CommTest, e.getMessage());
}
String js = String.format(window.plugins.appcomm.updateValues('%s');,
data.toString());
this.sendJavascript(js);
}
}

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

import android.util.Log;

public class AppComm extends Plugin{

private static AppComm instance;

public AppComm () {
instance = this;
}

public static AppComm getInstance() {
return instance;
}

@Override
public PluginResult execute(String action, JSONArray args, String callbackId) {
System.out.println(in execute from appcomm);


return null;
}

public void sendValue(String value1, String value2) {
System.out.println(sendvalue in appComm);
JSONObject data = new JSONObject();
try {
data.put(value1, value1);
data.put(value2, value2);
} catch (JSONException e) {
Log.e(CommTest, e.getMessage());
}
String js = String.format(
window.plugins.commtest.updateValues('%s');,
data.toString());
this.sendJavascript(js);
}
}


res/xml/plugins.xml



<plugins>
<plugin name=App value=org.apache.cordova.App/>
<plugin name=Geolocation value=org.apache.cordova.GeoBroker/>
<plugin name=Device value=org.apache.cordova.Device/>
<plugin name=Accelerometer value=org.apache.cordova.AccelListener/>
<plugin name=Compass value=org.apache.cordova.CompassListener/>
<plugin name=Media value=org.apache.cordova.AudioHandler/>
<plugin name=Camera value=org.apache.cordova.CameraLauncher/>
<plugin name=Contacts value=org.apache.cordova.ContactManager/>
<plugin name=File value=org.apache.cordova.FileUtils/>
<plugin name=NetworkStatus value=org.apache.cordova.NetworkManager/>
<plugin name=Notification value=org.apache.cordova.Notification/>
<plugin name=Storage value=org.apache.cordova.Storage/>
<plugin name=Temperature value=org.apache.cordova.TempListener/>
<plugin name=FileTransfer value=org.apache.cordova.FileTransfer/>
<plugin name=Capture value=org.apache.cordova.Capture/>
<plugin name=Battery value=org.apache.cordova.BatteryListener/>
<plugin name=SplashScreen value=org.apache.cordova.SplashScreen/>

<plugin name=AppComm value=com.example.plugin.AppComm/>
</plugins>


cordova.xml



<?xml version=1.0 encoding=utf-8?>
<cordova>
<access origin=.*/> <!-- allow local pages -->
<log level=DEBUG/>
<preference name=classicRender value=true />
</cordova>


Index.html header



<head>
<meta charset=utf-8 />
<meta name=viewport content=width=device-width, initial-scale=1, maximum-scale=1.0 />
<title>
</title>
<link rel=stylesheet href=http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.css />
<script src=http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js>
</script>
<script src=http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js>
</script>
<script type=text/javascript charset=utf-8 src=cordova.js></script>
<script type=text/javascript charset=utf-8>
var AppComm=function(){};

AppComm.prototype.updateValues=function(a){
var map = new Object();
map[X1] = hallo;
map[X2] = hi;
cordova.exec(null, null, null);
};

cordova.addConstructor(function(){cordova.addPlugin(appcomm,new AppComm)});
</script>
</head>


One of the problems was that javascript was in a separate file (I think that was one of the problems). If it isn't to much to ask, how can I properly call java back, and with what values? How to implement the execute method and how to call it (I'm really bad at JQuery)?


More From » android

 Answers
12

Firstly, you are using a Plugin subclass. Plugin has been deprecated and has been replaced with CordovaPlugin. If you're using an old version of PhoneGap, I would recommend that you upgrade.



Secondly, your exec call is wrong. The docs for plugin development clearly state that you have to pass 5 parameters, while you're passing 3 nulls. How do you expect that to be handled?



cordova.exec(function(winParam) {}, function(error) {}, service,
action, [firstArgument, secondArgument, 42,
false]);


Here, the service, action and the array of parameters determine what will happen in your Java code. The first two determine what will happen in JavaScript under certain conditions. So, while you can use null for the first two, you have to specify the last three.



I have a working example plugin that works with PhoneGap 2.3.0. See the code below:



public class ExampleJSCommunicator extends CordovaPlugin {

public boolean execute (final String action, final JSONArray args, CallbackContext callbackContext) throws JSONException {
PluginResult.Status status = PluginResult.Status.OK;
String result = ;

cordova.getActivity ().runOnUiThread (new Runnable () {
@Override
public void run() {
try {
String displayText = ;
if (action.equals (buttonClicked)) {
displayText = args.getString(0) + was clicked;
}

else if (action.equals (animationRunning)) {
displayText = args.getBoolean(0) ? Animation started running : Animation stopped running;
}

TextView label = (TextView) cordova.getActivity().findViewById (R.id.textView);
label.setText (displayText + and the Activity knows it!);
} catch (JSONException e) {
e.printStackTrace();
}
}
});

return true;
}
}


With the code above, you have your Java-side plugin capable of handling two custom actions - buttonClicked and animationRunning. These actions serve my purposes, but you could name them otherwise.



Now, you still need to register your plugin, so that Cordova will know about it. This is done in the xml/config.xml file. Under plugins, you have to add the following:



<plugin name=ExampleJSCommunicator value=com.example.phonegap.ExampleJSCommunicator/>


Then you can pass data (or actions) from JavaScript as follows. Note that the parameters (which.id and animationRunning are passed in an array):



cordova.exec (null, null, ExampleJSCommunicator, buttonClicked, [which.id]);  // my first action
cordova.exec (null, null, ExampleJSCommunicator, animationRunning, [animationRunning]); // my second action


These two exec calls will trigger the execute method in the ExampleJSCommunicator class and will get handled in the respective if blocks. It doesn't matter where you call exec, as long as you declare your JavaScript code after you include the cordova.js file. My JavaScript is contained within a separate main.js file and it works just fine:



<script type=text/javascript charset=utf-8 src=cordova.js></script>
<script type=text/javascript charset=utf-8 src=main.js></script>

[#79082] Friday, April 5, 2013, 11 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
albert

Total Points: 652
Total Questions: 105
Total Answers: 108

Location: Pitcairn Islands
Member since Fri, Oct 15, 2021
3 Years ago
;