Wednesday, 16 November 2011

Android Phonegap :active CSS pseudo class doesn't work. A workaround..

If you're building a cross-platform Phonegap app, you may well run in to the issue that your CSS :active pseudo-classes simply don't work when running on Android. They may work on your a (link) elements, but not on div or others.

Luckily there's a simple workaround. This workaround will continue using the fast, native, JavaScript-free :active class on iOS, and drops back to using the JavaScript on Android.

  • First, in your CSS, find every instance of the :active class. Add another rule that maps a class called fake-active to the same style.
E.g.

.my-button:active {
 background-color: blue;
}

Becomes:

my-button:active, .my-button.fake-active {
 background-color: blue;
}
  • Now, in your document ready event, when running on Android only, attach event handlers for touchstart and touchend to all the classes that have used :active. Make these add and remove the fake-active class.
if (navigator.userAgent.toLowerCase().indexOf("android") > -1) {
    $(".my-button")
    .bind("touchstart", function () {
        $(this).addClass("fake-active");
    })
   .bind("touchend", function() {
        $(this).removeClass("fake-active");
    });
    .bind("touchcancel", function() {
        // sometimes Android fires a touchcancel event rather than a touchend. Handle this too.
        $(this).removeClass("fake-active");
    });
}

Note that you can use the $(".my-button, .my-other-element, .even-more-elements") jQuery syntax to bind the events to other classes too.

Thursday, 10 November 2011

Edit AndroidManifest.xml in Android Phonegap Build App

Phonegap build is an awesome service that allows you to convert a bunch of HTML files into actual mobile apps for iPhone, Android, Blackberry, and more. It's great, so great in fact that Adobe recently bought the company behind it (Nitobi).

You can read more about the details at their site, I won't repeat it all here.

I've been playing around with the Android version of this for a client project I've been working on, and came up with a bit of a problem.  There's a file called AndroidManifest.xml that every Android app includes that sets up loads of important stuff such as the intent filters and the permissions needed to run the app.

Phonegap build allows you to change some of these settings using it's config.xml system.  But for other settings you are, it seems, stuck.  I needed to change the intent filter for one of my activities, and there was no way that the config.xml could do this. I posted on their forums and the very helpful guy said they may add the feature in a future release.

In the meantime though, I found another way.

It's possible to decompile the apk file that you download from Phonegap Build, change the AndroidManifest.xml file, re-compile, re-sign, and install it onto your device.

Getting the tools we need
I'm assuming that you have the Android SDK installed, if not install it and follow the instructions to put the build tools into your path.
First you need to download apktool.  This great tool allows you to decode and re-encode apk files. Download it and follow the instructions to install for your platform.
We're also going to use:

  • jarsigner - part of the Java JVN (I have a binary at /usr/bin/jarsigner) 
  • adb - part of the Android SDK installation (my binary is at ~/android/android-sdk-mac_x86/platform-tools/adb)
Extracting the APK file

  • Download the apk file for your app from Phonegap build.
  • Open up the terminal and type (substituting your folders for path/to and filenames where appropriate)
apktool d path/to/yourApp.apk path/to/output-folder
  • This will extract the contents of the app into the folder output-folder.
  • The AndroidManifest.xml file will be at the root of that folder.
Now you can make whatever changes to the AndroidManifest you need (setting intent filters etc).

Re-building the APK file

  • Once you've finished making your changes, you can rebuild the APK file from the contents of the output-folder
apktool b path/to/output-folder path/to/yourAppV2.apk 
Re-signing the APK
If you try to install the new apk file you'll find that it fails with an invalid certificate error.
This is because apktool doesn't re-sign the apk.  It's pretty easy to re-sign the APK with the development certificate (which is what Eclipse uses when making APKs for testing).

Here's how:
jarsigner -verbose -keystore ~/.android/debug.keystore path/to/yourAppV2.apk androiddebugkey
By default the development certificate is in the ~/.android folder. When you run this, it'll ask for a passphrase - use android.

Your APK is now ready for installation!
adb install path/to/yourAppV2.apk