How to call back from java to javascript in cordova
Motivation
I wanted to notify changes of play state from the native java plugin to javascript in my project. I struggled the mission and I finally solved it. Let me share the solution.
The first implementation
First I tried to store the CallbackContext object which is passed as a parameter of APIs like below.
public class MyOwnPlugin extends CordovaPlugin { private CallbackContext callback = null; // ... public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException { // ... } else if("setCallback".equals(action)) { callback = callbackContext; return true; } // ... } // ... // This method will be fired later. public void onEvent(AnEvent event) { if(callback != null) { try { JSONObject parameter = new JSONObject(); parameter.put("state", event.getState()); parameter.put("index", event.getIndex()); callback.success(parameter); } catch (JSONException e) { Log.e(TAG, e.toString()); } } } }
Next I implemented javascript like below.
var myOwnPlugin = cordova.require('cordova/plugin/my_own_plugin'); myOwnPlugin.setCallback(myCallback); // ... function myCallback() { console.log("My callback has been fired."); }
Finally I modified my_own_plugin.js.
cordova.define('cordova/plugin/my_own_plugin', function(require, exports, module) { // ... MyOwnPlugin.prototype.setCallback = function(onChanged) { exec(onChanged, function(err) { console.log(err); }, 'MyOwnPlugin', 'setCallback', []); } // ... }
However logcat showed below and the callback method was not fired at all after the first call.
Attempted to send a second callback for ID: MyOwnPlugIn392702509 Result was: {"state":1,"index":0}
Final implementation
I googled about the problem for a while and tested several times. Finally I found the solution. I changed MyOwnPlugin.java like below.
public class MyOwnPlugin extends CordovaPlugin { // This method will be fired later. public void onEvent(AnEvent event) { if(callback != null) { try { JSONObject parameter = new JSONObject(); parameter.put("param1", event.getParam1()); parameter.put("param2", event.getParam2()); // callback.success(parameter); PluginResult result = new PluginResult(PluginResult.Status.OK, parameter); result.setKeepCallback(true); callback.sendPluginResult(result); } catch (JSONException e) { Log.e(TAG, e.toString()); } } } }
This time logcat did not report any problem.
Conclusion
When you want to call a method of javascript back from a native java plugin, implement like below in java.
- Store a CallbackContext object
- Execute the CallbackContext object several times later like below
PluginResult result = new PluginResult(PluginResult.Status.OK, parameter); result.setKeepCallback(true); callback.sendPluginResult(result);