Installing Plugins with PhoneGap's Command-Line Interface
A few weeks ago I wrote about PhoneGap's Node.js command-line interface. A reader stopped by to check out the article and asked how to use the command-line interface to install plugins, which of course I had conveniently glossed over.
Well, PhoneGap 3.0 was released, and one of the big changes in version 3.0 was that a lot of the device functionality that used to ship with PhoneGap has been extracted to individual plugins. Having recently written about using InAppBrowser to build an OAuth login I figured I would update my OAuth example project for PhoneGap 3.0 and see how plugins work with the command-line interface.
OAuth with PhoneGap's InAppBrowser: Expiration and Revocation
A few weeks ago I wrote about how to implement an OAuth login with PhoneGap's InAppBrowser. Well, it seems like a lot of people are looking for information about PhoneGap and OAuth, so I figured I’d write a follow up article.
At the end of the last article we had a way to launch the consent page in PhoneGap’s InAppBrowser, retrieve the authorization code, and exchange it for an access token. That’s great, but for a release-quality application we need to take things a bit further.
There are two more conditions we need to consider: access tokens can expire and access tokens can be revoked.
Conditional Dependency Injection with AngularJS
The excitement level around AngularJS got high enough that I thought I should give it a shot, so I took it for a spin in a PhoneGap application I am working on.
My application defines an OAuth service that handles authentication and authorization. I want to inject different implementations of the OAuth service depending on the environment the application is running in. In a web browser the OAuth service simply wraps the Google API JavaScript client. In the PhoneGap web view the OAuth service uses a custom implementation that relies on InAppBrowser.
I think conditional dependency injection will be a common need for most PhoneGap developers, especially developers that hope to reuse some, or all, of their code in a web application.
Unfortunately, it is not immediately obvious how to do this…
Debugging iOS PhoneGap Apps with Safari's Web Inspector
At some point, something will go wrong in your PhoneGap application, and you’ll want to know why. Ideally, you’ll be able to reproduce the problem in a desktop web browser, fix it, and move on. Inevitably, however, you’ll run into a problem that is only reproducible on a device. If this happens to you on iOS, and you are targetting iOS 6 or higher, you’re in luck… well, aside from that nasty defect you just found, but hey, it happens!
With Safari 6 and higher (OS X only, sorry Windows) you can use Safari’s developer tools to remotely debug web pages in mobile Safari on an iOS device.
But wait, there’s more!
Not only can you remotely debug web pages in mobile Safari, you can remotely debug any web page in any plain old UIWebView, which just happens to include that UIWebView hosting your PhoneGap application. Note that you can only inspect UIWebView content in apps that were transferred to a device from XCode. Sorry, no inspecting apps downloaded from the App Store!
Here’s how to set up for debugging PhoneGap apps with Safari’s web inspector.
Google API OAuth with PhoneGap's InAppBrowser
If your PhoneGap project requires access to one of Google’s APIs, the first challenge you’ll likely run into is how to handle the OAuth dance in a PhoneGap application.
Google’s OAuth documentation seems to indicate OAuth 2.0 for installed applications fits the bill for a mobile application.
The idea is to use an embedded web browser to show the OAuth consent page. If the user grants access, we can get the authorization code out of the embedded browser’s title property. We PhoneGap developers have InAppBrowser for embedded browsing, so this should be a piece of cake!
The Node.js Command-line Interface for PhoneGap
PhoneGap ships with a simple set of scripts that you can use to create a new project from the command-line. Newly created projects include scripts to build, emulate, and deploy your app.
There is another command-line interface for PhoneGap written in JavaScript for node.js that the PhoneGap/Cordova documentation does not mention. I don’t know why this is. Maybe it will be documented in future releases. Hopefully I am not stealing the PhoneGap team’s thunder by writing about it!
What I really like about this package is that it bundles the PhoneGap/Cordova release. So by installing the package, you have effectively installed PhoneGap. It also provides some fantastic guidance about how to structure a multi-platform PhoneGap application.
Font Smoothing and CSS Transitions
On iOS devices and Safari, when you combine 3D transforms with elements containing text, you may notice some strange things happening with font rendering under certain conditions.
Text will appear thinner when an element with text is 3D transformed, or an element with text is composited with another 3D transformed element. When the 3D transform is removed, the text will become thicker again.
The resulting flickering text effect is not desirable.
The font-thinning behavior is most noticeable in high contrast color schemes, like white text on a dark background, though the problem is still present in more traditional black on white color schemes. Below is a screenshot showing normal text on the left and 3D transformed text on the right, or you can see it for yourself.
Nitro JavaScript Engine in iOS PhoneGap Apps
One advantage to building PhoneGap applications is that you can test your application on a physical device before registering with a developer program. Just host all of your source files on a web server and and point the device’s web browser at the server.
$100 per year to enroll in a developer program isn’t the end of the world, but I’d rather keep it until I know I have something to release!
Of course, with this testing method your application will not have access to device functionality exposed through the PhoneGap API, but it is still a good way to rapidly prototype your application’s user interface.
On iOS, there is another caveat to this testing method. Mobile Safari executes JavaScript faster than PhoneGap’s UIWebView.
Force Hardware Acceleration with translate3d... Sometimes
The last PhoneGap application that I developed had a feature that allowed you to drag an image around the screen so you could drop it in a folder or a trash can… you get the idea. The images were relatively large. Each image took up most of the display area of an iPad. The dragging animation worked by dynamically updating the -webkit-transform
property with a translate3d
value that followed a touch around the screen.
While testing the application I noticed that the image appeared to “stick” when a drag operation started. I could drag a short distance from the starting point of the pan gesture before the image snapped to the right location. When I dropped the image and started dragging again, I experienced the same stickiness. This was most noticeable on a first generation iPad (remember, always test on old hardware).
I found that by applying an identity translate3d
to the image element in CSS, there was no delay at the start of a drag operation. For example:
.draggable-image {
-webkit-transform: translate3d(0px,0px,0px);
}
Why does this work? And what are the performance implications?
Image Replacement Without Flickering 3D Transforms
Image replacement techniques improve a web page’s accessibility by allowing you to write nice semantic HTML and progressively enhance it with CSS. If you are writing a PhoneGap application, you may not care about the accessibility and “semanticness” of your HTML, but if you do, read on!
The idea behind image replacement is to use CSS to hide the text of an HTML element and instead show a background image. This improves accessibility by keeping the text available to screen readers, while also rendering pretty pictures in web browsers.
A standard technique for image replacement that is still quite prevalent works by setting a large, negative text-indent
. For example suppose you have this anchor tag in your HTML: