Monday, April 30, 2012

PhoneGap Android SplashScreen Just Got Better

One PhoneGap 1.7.0 is released in the next day or so doing a splash screen on PhoneGap Android is going to get a lot better. First off the long standing issue of using 9-patch images has been fixed. Really and truly it has this time. I've tested the fix on three different screen sizes.

Secondly, when you setup a splash screen you do the following:



super.setIntegerProperty("splashscreen", R.drawable.splash);
super.loadUrl("file:///android_asset/www/index.html", 10000);
This would show your splash screen 10 seconds then your index.html page would be loaded. Notice I said then. Yup, that's right showing the splash screen is a blocking call. While the splash screen is being displayed your .html/.js/.css is not being loaded in the background. Well, that is all changing so that your splash screen is shown on one thread while your application loads underneath the splash screen in another thread. The best thing is you don't need to make any changes to your code. Just keep calling the splash screen like you normally would.

But wait, I'm anticipating your next question "What if I want the splash screen to go away once my application is loaded before the timeout value is reached?" Okay, I've got good news it's coming. The official way to do this on iOS and Android once the 1.8.0 release is out will be to call:
navigator.splashscreen.hide();
but that call isn't ready yet. However, if you want to be on the bleeding edge you should be able to call:
cordova.exec(null, null, "SplashScreen", "hide", []);
but you are wait out on the edge there so don't blame me if it doesn't work. Then you'll be able to tell the splash screen to go away once you have "deviceready".
document.addEventListener("deviceready", onDeviceReady, false);

function onDeviceReady() {
    console.log("We got device ready");
    cordova.exec(null, null, "SplashScreen", "hide", []);
    // Soon to be
    // navigator.splashscreen.hide();
}
That's all for now.

Friday, April 20, 2012

Migrating your PhoneGap Plugins to Version 1.5+

One of the pain points when we had to rename PhoneGap to Apache Cordova was that it kinda/sorta broke the plugins. Wherever possible we tried to put a shim in to keep plugins from breaking but some restructuring of the code made it impossible for this transition to be totally seamless.

So let's take a look at a new plugin I just created that gets you the IMEI of your Android phone. First here is the 1.4.1 version of the code:

and now the 1.5+ version:
As you can see the code is very different. Really the only changes are that PhoneGap has been replaced with cordova. There is actually a shim in place so that you can still use the PhoneGap object but that is going away for the 2.0 release so we might as well get on that train now. As well the addConstructor/addPlugin methods won't really be needed come 2.0 but lets leave them in for now.

Alright, so the JavaScript code wasn't much different so let's dive into the Java code now. First the 1.4.1 version:

and now the 1.5+ version: again not too many changes. Simply changing the imports from:
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
to:
import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult;
This shouldn't be necessary for your plugin as I added code in the cordova.jar file so that every class in the org.apache.cordova.api package has a sub-class in com.phonegap.api. Once again this will be going away in the 2.0 release so we should go ahead and make the change now. Easy right?

Well kinda, but I'm being a bit disingenuous as my example does not address a key change between versions 1.4.1 and 1.5.0. In PhoneGap 1.4.1 the member variable this.ctx was of type PhonegapActivity. If you walked up PhonegapActivity's inheritance chain you'd see that android.content.Context is one of it's super classes. This was particularly useful in a number of Plugins.

In Cordova 1.5+ the member variable this.ctx is a CordavaInterface. So plugins that are passing this.ctx into methods that are expecting a Context will complain. The fix for this in your Java code is to replace:
this.ctx
with:
this.ctx.getContext()
or
this.ctx.getIntent()
with:
((DroidGap)this.ctx).getIntent()
wherever required. These changes were predicated by refactoring of the code in order to enable Cordova to be an embeddable component. That is, at some point in the future you will be able to create an Android application that can embed the Cordova component. This will allow you to mix native and hybrid development more easily.

Update 2012/04/23: Paul Beusterien pointed out that I forgot to mention a couple of steps to get the IMEI plugin working. First add the following line to res/xml/plugins.xml:
<plugin name="imei" value="com.simonmacdonald.imei.IMEIPlugin"/>
and make sure you have the proper permissions setup in your AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Wednesday, April 18, 2012

FileTransfer.download on PhoneGap/Apache Cordova 1.5.0

Sorry for being gone so long, vacation put me off my posting stride but hopefully this week will get things back on track.

Today I'd like to talk about using the FileTransfer.download() command with PhoneGap. In PhoneGap 1.5.0 we introduced common JavaScript. This is a sub project which has each platform that PhoneGap supports pulling it's JS from a common source. One of the changes introduced because of this is that all FileEntry.fullPath's would start with the "file://" protocol.

Unfortunately the native FileTransfer.download() code was not updated to take care of the new input. I've raised CB-539: FileTransfer.download fails when target starts with "file://" to track this issue. I've already got a fix for this checked into the source repository and it'll be in the 1.7.0 release of PhoneGap.

In the meantime you'll need to strip the "file://' from the target path you pass into FileTransfer.download().  Something like this:
var localPath = fileEntry.fullPath;
if (device.platform === "Android" &&
  localPath.indexOf("file://") === 0) {
    localPath = localPath.substring(7);
}
Here is a full example and don't forget to whitelist "http://i3.kym-cdn.com":

Monday, April 2, 2012

Updates to my PhoneGap Plugins

If you've updated to PhoneGap 1.5.0 which is part of our move to the Apache Cordova name and the next step in becoming an official Apache project you've probably noticed a number of plugins have broken. The biggest problem is that a lot of Plugins used this.ctx as an Android Context. Unfortunately due to some internal code changes this.ctx is no longer a Context. Now you have to call this.ctx.getContext(). So I spent sometime updating the ChildBrowser, FtpClient, TTS and VideoPlayer plugins so they would work smoothly with PhoneGap/Cordova 1.5.0.

Also, thanks to some code submitted by Stephanie Sherriff (ssherriff on GitHub) the VideoPlayer plugin can now play files from your Android assets folder. The syntax is pretty simple as well.
window.plugins.videoPlayer.play("file:///android_asset/www/path/to/my/video.mp4");