Communication between Android Java and Phonegap Javascript?
I finally made it work.
Create a class with methods you want to use:
public class MyClass {
private WebView mAppView;
private DroidGap mGap;
public MyClass(DroidGap gap, WebView view)
{
mAppView = view;
mGap = gap;
}
public String getTelephoneNumber(){
TelephonyManager tm =
(TelephonyManager) mGap.getSystemService(Context.TELEPHONY_SERVICE);
String number = tm.getLine1Number();
return number;
}
}In your main activity add a Javascript interface for this class:
public class Main extends DroidGap
{
private MyClass mc;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init();
mc = new MyClass(this, appView);
appView.addJavascriptInterface(mc, "MyCls");
super.loadUrl(getString(R.string.url));
}
}In Javascript call window.MyCls methods:
<script>
$(function(){
$("#phone").text("My telephone number is: " +
window.MyCls.getTelephoneNumber());
});
</script>
Note:
As mentioned in the comment, for Android version 4.2 and above, add @JavascriptInterface
to the method which you want to access from your HTML page. Reference.
Asynchronous communication between Javascript and Phonegap Plugin
You are almost there but you need to setKeepCallback to true on your PluginResult. If you don't the subsequent results from the Java side will not have a callback on the JavaScript side. The best example of this type of coding is the Network plugin in Cordova core. Here is a link to the source:
https://git-wip-us.apache.org/repos/asf?p=cordova-plugin-network-information.git;a=blob;f=src/android/NetworkManager.java;h=e2ac500ccc885db641d5df6dab8eae23026a5828;hb=HEAD
So you should update your code to:
public boolean execute(String action, final JSONArray args,
final CallbackContext callbackId) throws JSONException {
IntentFilter wifiFilter = new IntentFilter(
WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
cordova.getActivity().registerReceiver(wifiBroadcastReceiver,
wifiFilter);
this.callbackContext = callbackId;
PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
result.setKeepCallback(true);
this.callbackContext.sendPluginResult(result);
return true;
}
public class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
PluginResult result;
if (intent.getBooleanExtra(
WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
Toast.makeText(cordova.getActivity(), "Wifi Connected",
Toast.LENGTH_SHORT).show();
result = new PluginResult(PluginResult.Status.OK,
"Wifi Connected");
} else {
Toast.makeText(cordova.getActivity(), "Wifi Disconnected",
Toast.LENGTH_SHORT).show();
result = new PluginResult(PluginResult.Status.ERROR,
"Wifi Disconnected");
}
result.setKeepCallback(false);
if (callbackContext != null) {
callbackContext.sendPluginResult(result);
callbackContext = null;
}
}
}
}
Javascript calls from Android using PhoneGap
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>
Javascript-to-Java Communication in an Android Phonegap app
You can pass a javascript variable to the java while using the plugins as below.
cordova.exec(null, null, "service", "action", ["firstArgument", "secondArgument", 42]);
Here the first and second parameter to the exec method are the sucess and failure calllback.
service and action are the native class and method names respectively.
And the last parameter ["firstArgument", "secondArgument", 42] are the javascript variables which you can pass to the native method.
For more details please go through the following link.
http://docs.phonegap.com/en/2.8.0/guide_plugin-development_index.md.html
Phonegap - HTML/JS to Container Communication
I managed to find this useful link: Dissecting PhoneGap's Architecture. Of course, if that doesn't give you the level of detail you want, you can always check out Android's Exec function
how to send data or message from java application / plugin to javascript with cordova / phonegap
You can always execute javascript from java doing this:
String js = "alert('test')";
webView.loadUrlNow("javascript:" + js);
Or you can init the plugin and keep the callback doing this
PluginResult pgRes = new PluginResult(PluginResult.Status.OK, "message");
pgRes.setKeepCallback(true);
callbackContext.sendPluginResult(pgRes);
Added example provided by Sephy
private String myCbkId;
// Store callbackId from a call to execute
@Override public boolean execute(String action, JSONArray arr, CallbackContext cbkCtx) throws JSONException {
myCbkId = cbkCtx.getCallbackId();
JSONObject data = arr.getJSONObject(0);
String ack = data.getString("data"); // You can acknowledge to the callback for instance and keep it alive
Log.d(TAG, "ack".equals(ack) ? "ack !" : "not ack !");
// These lines can be reused anywhere in your app to send data to the javascript
PluginResult result = new PluginResult(PluginResult.Status.OK, ack);
result.setKeepCallback(true);//This is the important part that allows executing the callback more than once, change to false if you want the callbacks to stop firing
this.webView.sendPluginResult(result, this.myCbkId);
return true;
}
How to call an Android Activity from PhoneGap
Any Java Native code call be called without using any plugin as following.
Follow The following Steps.
Replace the following code with your existing DroidGap Activity.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.init(); // Calling this is necessary to make this work
appView.addJavascriptInterface(this, "MainActivity");
/* "this" points the to the object of the current activity. "MainActivity" is used to refer "this" object in JavaScript as in Step 3. */
super.loadUrl("file:///android_asset/www/index.html");
}Add the custom function in current (this) activity as following.
public void customFunctionCalled() {
Log.e("Custom Function Called", "Custom Function Called");
}Now call this function from your HTML/JavaScript code as following.
<script type="text/javascript">
function callNewActivity() {
window.MainActivity.customFunctionCalled();
}
</script>
This will call customFunctionCalled()
in MainActivity
.
Tested Environment
Eclipse - 3.7.2
Android 2.2 Emulator
PhoneGap - 2.0.0
Please provide your comments here to improve blogs post.
http://phonegapexplorers.blogspot.in/2012/08/call-native-java-code-phonegap-android.html
How to communicate between WebView & JavaScript?
You should add javascript interface to your webView like that:
webView.addJavascriptInterface(new JavascriptInterface(this), "AndroidFunction");
You should create interface class:
public class JavascriptInterface{
Context mContext;
JavascriptInterface(Context c) {
mContext = c;
}
public void save(String action){
// save to database
}
}
On the website you should call:
AndroidFunction.save("actionName");
Related Topics
Android Camera: Data Intent Returns Null
Why Are Nested Weights Bad For Performance? Alternatives
How to Add a Library Project to a Android Project
No Resource Found That Matches the Given Name '@Style/Theme.Appcompat.Light'
Inject CSS to a Site with Webview in Android
Android Chrome Ignoring -Webkit-Text-Size-Adjust:None Property. Text Is Being Scaled When Zoomed Out
API Key for Gcm Is Suddenly Invalid? Unauthorized (401) Error
How to Sort Firebase Records by Two Fields (Android)
How to Animate Recyclerview Items When They Appear
Error Type 3 Error: Activity Class {} Does Not Exist
Text Size and Different Android Screen Sizes
Android: How to Validate Edittext Input
How to Prevent Screen Capture in Android
How to Disable an Android Button
How to Make Surfaceview Transparent
How to Programmatically Tell If a Bluetooth Device Is Connected
Context.Startforegroundservice() Did Not Then Call Service.Startforeground()
How to Fire Onlistitemclick in Listactivity with Buttons in List