Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Acquire returned value from PhoneGap Plugin

I built a very simple PhoneGap Plugin to start testing the way I'm going to build some native actions on Android.

JavaScript:

 function callNativePlugin() {
            cordova.exec(nativePluginResultHandler, nativePluginErrorHandler, "Database", "saveAdvertencia", [ 1, "TesteAdv" ]);
        }

    function nativePluginResultHandler(result) {
        alert("SUCCESS: \r\n" + result);
    }

    function nativePluginErrorHandler(error) {
        alert("ERROR: \r\n" + error);
    }

Java:

@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
    if (action.equals("saveAdvertencia")) {
        advertenciaDS = new AdvertenciaDS(cordova.getActivity());
        callbackContext.sendPluginResult(new PluginResult(Status.OK, new JSONArray("test")));
        return true;
    }
    return false;
}

What I need is a way to retrieve the result from the action in the same method. It's very complicated to always deal with 3 methods(1 to execute the action. 1 to define what will be the success action. 1 to define what will be the error action.) when you don't really control when they are called, since PhoneGap calls them after the action is completed.

If I need to retrieve some data from the Android Native database:

  1. Call in JavaScript the "cordova.exec".
  2. PhoneGap will call your plugin.
  3. Your plugin will return 2 things: A boolean for the PhoneGap defining it everything worked as expected or not. The data that will be passed to the sucessfull methods.
  4. Here is the tricky part for me. If successfull or not, you have to create 2 methods that you dont have the controll of when they will be called, because PhoneGap will decide that. How do I change this?
like image 964
BBacon Avatar asked Mar 21 '13 13:03

BBacon


2 Answers

I use this pattern to have only one callback for the functions provided by the plugin:

function callNativePlugin(callback) {
   cordova.exec(function(result) {
       callback(null, result);
   }, function(result) {
       callback("myerror");
   }, "Database", "saveAdvertencia", [ 1, "TesteAdv" ])
};

This way you get node.js style callbacks in which the first argument is the error and second is the result:

//define the callback function
var callbackFunction = function(err, result) {
    if (err) {
        console.log("there was an error");
    } else {
        console.log("success", result);
    }
};

//call the plugin
callNativePlugin(callbackFunction);

You cannot avoid having two callbacks in your plugin, as this is mandated by the cordova API, but you don't have to expose that to your plugin users.

like image 96
Vlad Stirbu Avatar answered Nov 19 '22 02:11

Vlad Stirbu


If you're asking for a way to turn cordova.exec() from an asynchronous call into a synchronous call that returns a value, the short answer is that you can't. (The long answer is you can fake it using a loop or timeout but you shouldn't.)

As Vlad explains, you can create your own interface so you only have one function to call, but I use something like this simpler version (in http://htmlpresenter.com/api.html):

var Database = {
  saveAdvertencia: function(args, callback) {
    cordova.exec(callback,
      function(error) { console.log("Error calling Database.saveAdvertencia: " + error); },
      "Database", "saveAdvertencia", args)
  }
}

Then call it like this providing the callback inline if you need the result:

Database.Advertencia([1, "TesteAdv"], function(result) { alert(result); });

Of course if (as seems to be the case) you don't need the result at all, you can just use this version:

function saveAdvertencia() {
  log = function(message) { console.log(message) };
  cordova.exec(log, log, "Database", "saveAdvertencia", arguments);
}

saveAdvertencia(1, "TesteAdv");

(Edit:) Also, this challenge may be related to this, better question:

  • Call An Asynchronous Javascript Function Synchronously
like image 38
Dave Burt Avatar answered Nov 19 '22 04:11

Dave Burt