in my app, when user click on a button in webview, a phonegap plugin will be called to trigger an asynctask to download file from internet. Now i want to send a signal back
I also asked this question in Phonegap Google Group, here is response of Simon Mac Donald. It works perfectly for me:
You can handle this situation by using the Plugin API quite easily. It is implemented in the core API items Connection and Battery. What you need to do is:
1) In your execute() method of your plugin save the callbackId you get.
2) Return a NO_RESULT plugin result and set keep callback id to true.
PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
pluginResult.setKeepCallback(true);
return pluginResult;
3) When you async java method finishes return another plugin result like this:
PluginResult result = new PluginResult(PluginResult.Status.OK, data);
result.setKeepCallback(false);
this.success(result, this.myCallbackId);
As I said, you can look at the code in GitHub to see how we are using this for Connection and Battery.
Here is a detailed example:
Lets create some interface that should be called when AsyncTask
will finish the stuff, a.e when onPostExecute
called.
In my case we fetch some JSONArray
data
MyTaskListenerItf.java
public interface GroupTaskListenerItf {
public void onTaskDone(JSONArray groupArray);
}
The AsyncTask
template of looks like:
MyBuildTask.java
public class MyBuildTask extends AsyncTask<Void, Void, SomeData>{
private MyTaskListenerItf mTl = null;
public MyBuildTask(Context context, MyTaskListenerItf tl) {
super();
this.mContext = context;
this.mTl = tl;
}
@Override
protected SomeData doInBackground(Void... params) {
/* ... */
}
@Override
protected void onPostExecute(WmTransferItem transferItem) {
// ...
if(this.mTl != null){
JSONArray data = new JSONArray("");
this.mTl.onTaskDone(data);
}
// ..
}
}
So now our CordovaPlugin
class should look like:
MyCordovaPlugin.java
public class MyCordovaPlugin extends CordovaPlugin implements GroupTaskListenerItf {
// we need this callback when Task will finish
private CallbackContext mMyCallbackContext = null;
@Override
public boolean execute(String action, JSONArray args,CallbackContext callbackContext) throws JSONException {
if("runMe".equals(action)){
final GroupTaskListenerItf gt = this;
mMyCallbackContext = callbackContext;
// pass our 'GroupTaskListenerItf' interface to async class
MyBuildTask task = new MyBuildTask(cordova.getActivity(), gt);
task.execute();
PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);
}
else{
this.cordova.getThreadPool().execute( new Runnable() {
public void run() {
// BTW, here you might run something else out of UI Thread
}
});
}
}
/* ... */
@Override
public void onTaskDone(JSONArray data) {
if (this.mGroupCallbackContext != null) {
PluginResult result = new PluginResult(PluginResult.Status.OK, data);
result.setKeepCallback(false);
this.mMyCallbackContext.sendPluginResult(result);
}
}
That's all.
Hope it will help to someone.
This is how I solve problems like your.
1) Create and associate a JavascriptInterface to your WebView. A JavascriptInterface is simply a class inside which you can declare some Java method you want to use from JS.
public class JSInterface() {
private final CountDownLatch latch = new CountDownLatch(1);
public void waitForProceed() {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void canProceed() {
latch.countDown();
}
}
2) In your AsyncTask, at the end of onPostExecute()
method, you have to call the canProceed()
method to notify to JSInterface that it can exit from waitForProceed()
method.
public class MyAsyncTask extends AsyncTask<.......> {
private JSInterface jsi;
... // other class property
public MyAsyncTask(JSInterface jsi) {
...
//do what you want with other class property
this.jsi = jsi;
}
@Override
public ... doInBackground(...) {
...
//do something
}
@Override
public void onPostExecute(...) {
...
//do something
jsi.canProceed();
}
}
3) In your Activity you have to associate the JSInterface object to your WebView:
WebView mWebView;
...
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JSInterface(), "JSIface");
4) Finally, in JS, you can call AsyncTask (I don't know how you call it, but I guess you use somthing like a JSInterface) and after call waitForProceed()
method:
startAsyncTask(); //somehow
JSIface.waitForProceed();
I hope it solves your problem ;)