Sunday, June 2, 2013

Why Don't My Plugins Work in PhoneGap Android 2.7?

Well it's pretty simple, the Plugin class which has been deprecated for awhile has been removed from the package and should be replaced with CordovaPlugin.

I'm going to go through the steps needed to upgrade your old style plugins to the new style. For this example I'm going to use the Google Analytics plugin.

The first thing you will notice in 2.7.0+ is that the GoogleAnalyticsTracker class now has 4 errors in Eclipse. To get rid of them you would change:


import org.apache.cordova.api.Plugin;

into:

import org.apache.cordova.api.CordovaPlugin;

and:

public class GoogleAnalyticsTracker extends Plugin {

to:

public class GoogleAnalyticsTracker extends CordovaPlugin {

and now you'll notice you only have one error left in the file and that has to do with the execute method. You'll need to change the method signature from:

public PluginResult execute(String action, JSONArray data, String callbackId) {

to:

public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {

then you need to add a new import line at the top of the Java file:


import org.apache.cordova.api.CallbackContext;

and we still have one error which is now the line in which we are returning the PluginResult. That's because the method now expect a boolean to be the return value. To fix this issue you would replace:

return result;

with:

callbackContext.sendPluginResult(result);
return true;

Finally our Java code is free of error messages. Whew, were done but what's with the change to the execute method? Well let's just say there have been improvements in the way the Plugins are handled internally. What you need to know is that when you want to send a result back to the JavaScript side you now have a choice of three methods:

1) callbackContext.sendPluginResult(...)

Use this if you have constructed your own PluginResult and you want to send it to the JavaScript side.

2) callbackContext.error(int | String | JSONObject) 

Skip creating a PluginResult and just invoke the error callback on the JavaScript side sending back an int, a String or a JSONObject as the method payload.

3) callbackContext.success(empty | int | String | JSONObject | JSONArray)

Again, just skip creating the PluginResult and invoke the success callback on the JavaScript side sending back an int, a String, JSONObject or JSONArray as the method payload. If you don't provide any payload the method on the JS side will be executed with no payload.

So that should get you unstuck if you have a Plugin that no longer works for you as of PhoneGap 2.7.0. You should also check out my posts on the GalleryPlugin as shows how to write a Plugin using the new API for JS and Java.

IMPORTANT UPDATE!!!

We've heard your screams of pain and we are putting the Plugin class back for PhoneGap 2.8.1. Go read Joe Bowser's post. The class is back in 2.8.1 and will be in 2.9.0 then gone for good in the 3.0.0 stream!





24 comments:

Lucas Burnet said...

hello simon,
Sorry to contact you here, but I did not find any other way to contact you.
I follow your website for a long time and it has helped me.
I have 18 years and I'm french so sorry for my bad English.
I'm stuck on a problem for a long time with my phonegap application.
I'm lost with ajax request and api phonegap file:
I have an external xml file data.xml.
I need to store this file locally.
if (lastModifiedTime of data.xml in local <7days)
     Directly i read the local file
else
     i do an ajax request, and i store the returned XML.
     i read the local refresh xml

I do not know what API use and how proceed.
Can you help me please?

Thanks you.

How can i contact you ?

Simon MacDonald said...

Salut @Lucas Burnet, I think your English is just fine. Much better than my Canadian French. If you want to check the last time a file was modified you would do something like this:

window.resolveLocalFileSystemURI("file:///example.txt", function(fileEntry) {
var now = new Date();
var newdate = new Date(date);
newdate.setDate(newdate.getDate() - 7);
if (fileEntry.lastModifiedDate > newdate) {
// read local file
} else {
// do ajax request
}
}, function() {
console.log("error");
});

I have not tested that code at all but it should get you going. Check out the File API at:

http://docs.phonegap.com/en/2.7.0/cordova_file_file.md.html

And the best way to contact me is via Twitter @macdonst or Google+ at https://plus.google.com/u/0/117228047921974802298/posts

Lucas Burnet said...

thank you simon
I tried something like this before but I had an error : Object [object DOMWindow] has no method 'resolveLocalFileSystemURI'

My condition with ajax request are good, read local and external file too. Now my problem is just for the lastModified time read from my news.xml ...

Simon MacDonald said...

@Lucas Burnet

Are you waiting for the deviceready event before you try to call window.resolveLocalFileSystemURI? If you don't wait for the event then the PG API may not be setup yet.

Michael SBCERA said...

Thanks so much Simon.

For ChildBrowser I still have an error with:
this.success(result, this.browserCallbackId);

Michael SBCERA said...

Actually this didn't seem to solve the GA plugin problem either.

I now have two errors:

The method execute(String, JSONArray, String) of type GoogleAnalyticsTracker must override or implement a supertype method

and

callbackContext cannot be resolved

Simon MacDonald said...

@Michael SBCERA

this.success(result, this.browserCallbackId);

should be:

this.callbackContext.sendPluginResult(result);

but you should just look for the updated ChildBrowser plugin or replace it with the InAppBrowser.

With regards to:

execute(String, JSONArray, String)

read my post again as it seems you missed the part where you need to change the execute method signature.

Simon MacDonald said...

@Michael SBCERA

I sit corrected, there was an error in my post which is now correct. Check the new proper method signature of the execute method.

Michael SBCERA said...

Neither of these worked either.

Childbrowser error is:
callbackContext cannot be resolved or is not a field

GA error is:
CallbackContext cannot be resolved to a type GoogleAnalyticsTracker.java

I don't see an updated ChildBrowser plugin. I see last update occurred 9 months ago. I continue to use CB because I can't get InApp to simply open all links. I've tried a variety of solutions.

Simon MacDonald said...

@Michael SBCERA

And you found another mistake in my post. Eclipse automatically added the import line for CallbackContext. I modified the post again to add this instruction.

Shazbut, you are right. No one has modified the old ChildBrowser. I'm not sure if I will have time to do it but you should be able to follow the same instructions to get it working.

tobin said...

Hey Simon,

Is there somewhere/someone we should send updates to or get help with this on? I'm updating the .java for the BarcodeScanner, but the version I got from plugman seems different from the github under phonegap/android/barcodescanner and I've got a few strange errors to begin with just downloading it from scratch.

Thanks

Simon MacDonald said...

@tobin

Let me know what command you are using for plugman and I'll try it and track it down.

Michael SBCERA said...

Still haven't gotten the CB plugin to work with 2.7. Lots of errors.

If you have a chance to look at it Simon it would be appreciated.

Rofand K said...

hello Simon,

Thank you for this post.

I tried phonegap2.5 and 2.8, and in both the clipboard plugin doesnt work.
the following code doest not executed

import android.text.ClipboardManager;
.
.
mClipboardManager = (ClipboardManager) cordova.getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
.
.
.
android.text.ClipboardManager is working fine but it is deprecated

any advice

Simon MacDonald said...

@Michael SBCERA

Untested but here is some code:

https://gist.github.com/macdonst/5746209

Michael SBCERA said...

This seems to have worked or at least the errors are gone.

Thank you very much.

Kushalpreet Kaur said...

Hi
Thanks for the tip.

Unfortunately even after making your changes, I still have errors in my Google Analytics. Since the date of your post is pretty new, I wanted to ask you while using Google analytics plugin for PhoneGap which jar file did you use?
did you use the libGoogleAnalytics.jar or libGoogleAnalytics2.jar?

As there are many classes in the newer jar file which the GA plugin for PhoneGap uses.

I get my error rigth at this line
private com.google.android.apps.analytics.Tracker tracker;

And the error is com.google.android.apps.analytics.Tracker cannot be resolved to type. I have already added that jar in my build path, but still I am getting this error.

Can you please help!

Thanks!

Simon MacDonald said...

@Kushalpreet Kaur

I was using libGoogleAnalytics.jar from the plugins repo. To be fair I did not test this Plugin in depth. I was just using it as an example to get rid of compilation errors brought on by 2.7.0.

Simon MacDonald said...

@Rofand K

Sorry, I didn't write the ClipboardPlugin. If you are using a deprecated API and it works but then you switch to the non-deprecated API it seems to point to that change being the problem and not the Plugin itself.

Kushalpreet Kaur said...

ok.
Never mind..
Thanks a lot for replying :)

Ankit Rawat said...

Hello Simon ,

I have started phonegap development one month ago. I followed many of your posts and I am doing well. I really want to thankyou for such beautiful posts, these have helped me a lot. I want to make a chat application in phonegap for android, can you please suggest me how to get started. Will there be differences in performance between native chat app and phonegap chat app.
Thankyou
Ankit Rawat

Simon MacDonald said...

@Ankit Rawat

Yeah, you could do a chat app with PhoneGap pretty easily. Check out this series of articles:

http://o2js.com/2011/05/24/creating-a-mobile-javascript-chat-part-3-going-mobile/

Flávio said...

Hi Simon,

This week I used the cordova command line and the plugman to build an app with the BarcodeScanner.

But the BarcodeScanner class in the BarcodeScanner.java appears not have been updated accordingly to work with the new version of cordova 3.0.0, and shows many errors that I can't correct.
That are things like
import org.apache.cordova.api.Plugin
where supposed to be
import org.apache.cordova.CordovaPlugin

And many others, that I can't fix.

So, the question is, is there any prevision of having the corrections commited to github, or is there some other older version that is knowed to be working, so I can move on with my project until a new fix version being released?

Best Regards,

Flavio

Simon MacDonald said...

@Flávio

Yeah, Ryan (Adobe) and I merged the code so they could have the canonical version going forward. You can find it at:

https://github.com/wildabeast/BarcodeScanner

but it is not yet updated to 3.0.0. In the meantime you can use:

https://github.com/Eccenux/BarcodeScanner

which works with 3.0.0. I sent a note to Ryan to pull in the changes.