Did you know if there is a missing bit of functionality in PhoneGap you don't need to wait for the core development team to get around to it? You can take matters into your own hands since PhoneGap is an open source project.
Let's say you have a bit of functionality that is only required on one platform, well the best thing to do in that case is to write a plugin. If you want to share your plugin with the world then let us know by submitting a pull request on the PhoneGap Plugins repository. Submitting to this repository only requires for you to have a GitHub account. There is no need to sign any contributor license agreement. We love to get new plugins.
However, let's say you've identified an area of the API that is lacking. Until PhoneGap 1.3.0 there was no download function for the FileTransfer class. Well developer Alexander Heinrich decided to fill that niche by submitting pull requests that added the functionality to iOS and Android. That was a huge help and the BB developers were able to step in an fill in the functionality in their repository. Up until that point Alexander was not a member of the core PhoneGap developers but after he signed the Apache ICLA and we reviewed his code he was in. It's as simple as that.
So to all of you my challenge is for you to be the next Alexander Heinrich! Create a plugin, fix a bug add new functionality.
Showing posts with label 12 days. Show all posts
Showing posts with label 12 days. Show all posts
Thursday, January 5, 2012
Wednesday, January 4, 2012
On the Eleventh Day of PhoneGapping: Configuration Defaults
As much as we'd like to make PhoneGap 100% cross platform there are some differences between platforms that sometimes need to be smoothed over. Two items that I can think of off the top of my head are:
1) Android's persistent file system defaults to the SD Card which everyone can read from while in iOS it defaults to a directory that only the app can read.
2) In order to play a Media file the path to a file in the www directory is different for Android and iOS.
So to smooth these difference over you can create a .json file that is included in your www directory which will hold platform specific configuration details and load it via XHR. Here's how to do it:
Your .json file on Android could look like:
and on iOS it would look like;
So now you can replace clunky if statements like:
1) Android's persistent file system defaults to the SD Card which everyone can read from while in iOS it defaults to a directory that only the app can read.
2) In order to play a Media file the path to a file in the www directory is different for Android and iOS.
So to smooth these difference over you can create a .json file that is included in your www directory which will hold platform specific configuration details and load it via XHR. Here's how to do it:
Your .json file on Android could look like:
{
"mediaPath": "/android_asset/www/"
}
and on iOS it would look like;
{
"mediaPath": ""
}
So now you can replace clunky if statements like:
if (device.platform == "Android") { var my_media = new Media("/android_asset/www/test.mp3"); } else { var my_media = new Media("test.mp3"); }with:
var my_media = new Media(Config.mediaPath + "test.mp3");and continue to access everything in a cross platform way.
Tuesday, January 3, 2012
On the Tenth Day of PhoneGapping: Searching Contacts
As I've mentioned before some of the W3C specifications that we base the PhoneGap API on are the difficult to understand. The Contacts API is definetly one of the hard to understand ones. Here is an example of searching the phones contacts and handling the gotchas that may arrise.
First here is the method signature used when searching contacts:
contactSuccess [Required]: is the success callback which is invoked with an array of contacts.
contactError [Optional]: an optional error callback which is invoked if something goes wrong with the find command. The only parameter to the function is a ContactError object.
contactFindOptions [Optional]: is an optional ContactFindOptions object which controls a couple of options in the find command. The two parameters in the contactFindOptions are
filter: specify what you want to match against.
multiple: set to true if you want more than one contact returned in the success callback.
by default filter is set to the wildcard (match everything) and multiple is set to true.
Find Examples
1) Find all the names and email addresses of contacts with Ottawa area phone numbers.
1) Slow search results.
As I mentioned earlier the more items you specify in contactFields the longer your search will take as the filter will have to be applied against it to see if the contact matches the filter. Please try and limit the contactFields array to only the parameters that you absolutely need.
2) Null values
Frequently people end up running into errors in their success callbacks as they don't guard against null values properly. According to the W3C spec if there are no results for array values like emails, phoneNumbers, addresses, etc. the code should return a null for theses values and not an empty array. So when folks try to loop through all the returned emails it will error out as you can't access the fields of a null value. So when you try to access one of these values guard agains the null.
First here is the method signature used when searching contacts:
navigator.contacts.find( contactFields, contactSuccess, contactError, contactFindOptions);contactFields [Required]: is an array of strings that represent the fields from the Contact object you want returned as part of the search results. For example if you wanted to get the contacts display name and email addresses you would specify:
["displayName", "emails"]if you would like to get each an every field populated in the returned array of Contacts you would specify, what I call, the fire hose option.
["*"]However, be careful not to specify too many un-needed properties in the contactFields array. The array does double duty in the find command as the filter you specify in contactFindOptions is applied against each and every field in the contactFields array but we'll talk about that more later.
contactSuccess [Required]: is the success callback which is invoked with an array of contacts.
contactError [Optional]: an optional error callback which is invoked if something goes wrong with the find command. The only parameter to the function is a ContactError object.
contactFindOptions [Optional]: is an optional ContactFindOptions object which controls a couple of options in the find command. The two parameters in the contactFindOptions are
filter: specify what you want to match against.
multiple: set to true if you want more than one contact returned in the success callback.
by default filter is set to the wildcard (match everything) and multiple is set to true.
Find Examples
1) Find all the names and email addresses of contacts with Ottawa area phone numbers.
navigator.contacts.find( ["displayName", "name", "emails", "phoneNumbers"], contactSuccess, contactError, {filter: "613", multiple: true});2) Get all the contacts on the device.
navigator.contacts.find( ["*"], contactSuccess, contactError);3) Find all contacts named "Bob" and where they work.
navigator.contacts.find( ["displayName", "name", "organizations"], contactSuccess, contactError, {filter: "Bob", multiple: true});Gotcha's
1) Slow search results.
As I mentioned earlier the more items you specify in contactFields the longer your search will take as the filter will have to be applied against it to see if the contact matches the filter. Please try and limit the contactFields array to only the parameters that you absolutely need.
2) Null values
Frequently people end up running into errors in their success callbacks as they don't guard against null values properly. According to the W3C spec if there are no results for array values like emails, phoneNumbers, addresses, etc. the code should return a null for theses values and not an empty array. So when folks try to loop through all the returned emails it will error out as you can't access the fields of a null value. So when you try to access one of these values guard agains the null.
if (contacts[i].phoneNumbers != null) { for (j=0; j < contacts[i].phonenumbers.length; j++) { // Do stuff } }
Monday, January 2, 2012
On the Ninth Day of PhoneGapping: Getting Help
Besides being an excellent JavaScript toolkit PhoneGap is also a kick ass community of developers. The best place I know of to get help, and where I hang out answering a buch of questions is the PhoneGap Google Group. As well there is an IRC channel at irc.freenode.net, port 6667, with a room name of phonegap obviously.
In order to improve your chances of getting a quick and informative answer I'd suggest that you follow this process when asking a question on the Google group or on IRC.
First search the archives
Your question may have already been answered. Make sure you search at least PhoneGap Google group archives before you ask your question. Go to the PhoneGap Google group and use the search field in the top right of the page.
Provide details
Give as many details as possible. Incomplete questions won't likely be answered.
Include the following at a minimum:
Select a concise, informative subject for the post. For example, include:
You may also want to include:
If the code or logs are huge, let's say over 20 lines please think about using a web service like Gist or Pastebin.com. Alternatively if you have a Dropbox account put the file in your public folder. Then share the link in the email rather than mailing around a bunch of large files.
An example of question
Wrong:
PhoneGap does not work for me!
Right:
I get a security error on PhoneGap 0.9.4 when I try to open a database using the Android 3.0 emulator. You can see the code I used here: https://gist.github.com/937307 and the logs I collected here: https://gist.github.com/937315. I have looked at the archives and the commits but did not find any solution. Does anyone know what could be the issue and whether this has been fixed?
An example of subject
Wrong:
Urgent. Need help with my problem.
Right:
Android / PhoneGap 1.2.0 : deviceready event not firing
In order to improve your chances of getting a quick and informative answer I'd suggest that you follow this process when asking a question on the Google group or on IRC.
First search the archives
Your question may have already been answered. Make sure you search at least PhoneGap Google group archives before you ask your question. Go to the PhoneGap Google group and use the search field in the top right of the page.
Provide details
Give as many details as possible. Incomplete questions won't likely be answered.
Include the following at a minimum:
- what version number of PhoneGap are you using?
- which platform and version you are testing on? iOS 4.0, Android 2.2, BlackBerry 6.0, etc.
- a detailed description of your problem.
- is this happening in the emulator only, phone only or both?
Select a concise, informative subject for the post. For example, include:
- Platform, if issue is specific to Android, iOS, etc
- Keyword examples: version, jar file, phonegap plugin, deviceready event, build
- Short phrase summarizing the problem
You may also want to include:
- some sample code that illustrates the problem.
- logs taken while the problem was reproduced.
If the code or logs are huge, let's say over 20 lines please think about using a web service like Gist or Pastebin.com. Alternatively if you have a Dropbox account put the file in your public folder. Then share the link in the email rather than mailing around a bunch of large files.
An example of question
Wrong:
PhoneGap does not work for me!
Right:
I get a security error on PhoneGap 0.9.4 when I try to open a database using the Android 3.0 emulator. You can see the code I used here: https://gist.github.com/937307 and the logs I collected here: https://gist.github.com/937315. I have looked at the archives and the commits but did not find any solution. Does anyone know what could be the issue and whether this has been fixed?
An example of subject
Wrong:
Urgent. Need help with my problem.
Right:
Android / PhoneGap 1.2.0 : deviceready event not firing
Sunday, January 1, 2012
On the Eight Day of PhoneGapping: Multiple Screen Sizes
This is another question that comes up on the mailing list frequently, how do you support multiple screen sizes (portrait, landscape, phone, tablet)? Luckily there is a pretty good technique in web development that can be used in your PhoneGap application. It is called responsive web design and there is a book by Ethan Marcotte coincidentally called Responsive Web Design that I've recommended so often that I feel like I should be getting a kick back from the author (Full disclosure, I don't get a kick back). The book is only $9 and after you are done reading this post you should just go buy it.
In a nutshell, responsive web design uses CSS media queries to determine the width of your display and deliver different layouts based upon screen size. This would allow you to show a single column interface to portrait based phone users of your application but a multi-column approach to landscape table users. Let's run through a quick example.
For our phone users we'll setup our CSS so that our navigation sidebar shows up at the top and the main area of our application is underneath it. That would require some CSS that looks like this:
Now for the tablet version of the app you have a lot more screen real estate to work with so you want to have two columns. The left column will be the sidebar for navigation and the right column will be the main content area. Your CSS will look like:
So that is all well and good but how does our app choose which version of the CSS to use depending on if it is running on a phone or tablet. Well that is the magic of CSS media queries. We'll wrap up our CSS with:
Here is a full HTML file for you to test out.
Interestingly enough for Android 3.2 and greater they've adopted a similar technique to responsive web design to handle multiple screen sizes on Android.
In a nutshell, responsive web design uses CSS media queries to determine the width of your display and deliver different layouts based upon screen size. This would allow you to show a single column interface to portrait based phone users of your application but a multi-column approach to landscape table users. Let's run through a quick example.
For our phone users we'll setup our CSS so that our navigation sidebar shows up at the top and the main area of our application is underneath it. That would require some CSS that looks like this:
#wrapper { width: 90%; min-width: 0; } #main { margin-left: 0; } #sidebar { width: auto; float: none; }We'll set our wrapper div to have a width of 90% because we don't want any text going right up against the screen as it make it hard to read. We'll give our main content a left margin of 0px so it is left justified against the wrapper div. For our sidebar we'll make the width auto so all the text will fit. So you app will look like this:
Now for the tablet version of the app you have a lot more screen real estate to work with so you want to have two columns. The left column will be the sidebar for navigation and the right column will be the main content area. Your CSS will look like:
#wrapper { width: 80%; margin: auto; } #main { margin-left: 40%; } #sidebar { width: 40%; float: left; }The first thing you will notice in the CSS is that the wrapper div width is now 80% as we have more screen to work with so we can pad the sides a bit more. The main div is going to float over to 40% of the width of the wrapper div and the sidebar will be 40% of the wrapper div floating to the left side. And your app would look like this:
So that is all well and good but how does our app choose which version of the CSS to use depending on if it is running on a phone or tablet. Well that is the magic of CSS media queries. We'll wrap up our CSS with:
@media all and (max-width: 800px) { ... }for the phone version of the CSS and:
@media all and (min-width: 801px) { ... }for the tablet version. Simply screens up to 800px will get the phone version of the CSS and any screen over 800px wide will get the tablet version.
Here is a full HTML file for you to test out.
Interestingly enough for Android 3.2 and greater they've adopted a similar technique to responsive web design to handle multiple screen sizes on Android.
Saturday, December 31, 2011
On the Seventh Day of PhoneGapping: Debugging
One of the truly horrible things about doing web application development on mobile phones is the lack of web development tools that you'd see in modern desktop web browsers. Luckily for us a couple of folks have made it a lot easier to do web dev with tools like weinre by Patrick Mueller and iWebInspector by Maximiliano Firtman. I'm going to spend my time talking about weinre not because iWebInspector isn't as good but because I spend most of my time in Android land so I'm much more familiar with weinre.
The description from the home page:
The description from the home page:
"weinre is a debugger for web pages, like FireBug (for FireFox) and Web Inspector (for WebKit-based browsers), except it's designed to work remotely, and in particular, to allow you debug web pages on a mobile device such as a phone."
Isn't that great? You can have the developer tools you are used to back in your greedy little hands again.
The weinre home page has detailed instructions on how to setup your own server, which is not that difficult, but if you are like me (i.e. lazy) there is already a server setup for you at debug.phonegap.com where getting started is only three steps away.
Friday, December 30, 2011
On the Sixth Day of PhoneGapping: Downloading a File
Did you know that the FileTransfer object got a new download method in PhoneGap 1.3.0? You didn't, well thanks to Alexander Heinrich for spurring it's development and getting it checked in for Android and iOS (download is also available to you BlackBerry users). Finally PhoneGap developers have a convenient way to download binary files.
The method signature is:
source: The URL you want to download
destination: The full file path you want the file stored at
successCallback: called with a FileEntry object that represents the new file
errorCallback: called when something goes wrong
So say we want to download a PNG image and store it on the SD card. Well you'd write some code that looks like this:
The method signature is:
download(source, destination, successCallback, errorCallback);Where the parameters are:
source: The URL you want to download
destination: The full file path you want the file stored at
successCallback: called with a FileEntry object that represents the new file
errorCallback: called when something goes wrong
So say we want to download a PNG image and store it on the SD card. Well you'd write some code that looks like this:
Thursday, December 29, 2011
On the Fifth Day of PhoneGapping: Five Two Minute Tutorials
Another re-blog but there are some gems here as the folks at Mobile Development Solutions have put together 5 two minute tutorials using PhoneGap Android.
They've put together tutorials on:
1) Media Player
2) Getting your app market ready
3) Barcode Scanning
4) Google Maps
5) Twitter and OAuth
They've put together tutorials on:
1) Media Player
2) Getting your app market ready
3) Barcode Scanning
4) Google Maps
5) Twitter and OAuth
Thanks to Libby and Paul for everything they do to support the PhoneGap community.
Wednesday, December 28, 2011
On the Fourth Day of PhoneGapping: Creating a Database from a SQL Dump
On a slightly different track than Day 2 we are going to create a SQLiteDB from scratch using only JavaScript on startup of our application. In order to do this we are going to use the handy JavaScript library HTML5SQL.js by Ken Corbett Jr.
First we'll do a check to see if we've already created our database. If we haven't we'll do a XHR to get the SQL dump file containing all the statements we need to create and populate our tables. Finally, upon success we'll set a flag so this doesn't run every time we start our application.
and here is our sql file:
The html5sql.js lib makes working with the Web SQL specification much easier than hard coding it yourself. You owe it to yourself to look into this library as it will save you some time and hair.
First we'll do a check to see if we've already created our database. If we haven't we'll do a XHR to get the SQL dump file containing all the statements we need to create and populate our tables. Finally, upon success we'll set a flag so this doesn't run every time we start our application.
and here is our sql file:
The html5sql.js lib makes working with the Web SQL specification much easier than hard coding it yourself. You owe it to yourself to look into this library as it will save you some time and hair.
Tuesday, December 27, 2011
On the Third Day of PhoneGapping: Getting Data from a Server
Well your application would be pretty useless if you couldn't get data from a remote server now wouldn't it? Luckily since your PhoneGap application is running off of the file:// protocol it isn't limited by the same origin policy. This means we can request data using XmlHttpRequest from any domain.
I'm going to give you an example of searching for all tweets that mention PhoneGap that demonstrates this ability without the use of any extra JavaScript library like jQuery or Dojo.
So that is the example in a nutshell. It isn't very different from your normal XHR call except for one line that I need to bring to your attention:
Much of the rest of this code is just building up a HTML string I can do an insert into a div I've set aside for displaying the tweets. Just wanted to show everyone how easy it is to communicate with a remote server.
I'm going to give you an example of searching for all tweets that mention PhoneGap that demonstrates this ability without the use of any extra JavaScript library like jQuery or Dojo.
So that is the example in a nutshell. It isn't very different from your normal XHR call except for one line that I need to bring to your attention:
if (request.status == 200 || request.status == 0) {Most of the time you are just looking for the 200 status code you also need to accept the status code of 0 as also OK. Sometimes when you are requesting data via XHR from the file:// protocol you will get a 0 status code. As I said that is perfectly normal and you should treat it as a 200 and move on with your application.
Much of the rest of this code is just building up a HTML string I can do an insert into a div I've set aside for displaying the tweets. Just wanted to show everyone how easy it is to communicate with a remote server.
Monday, December 26, 2011
On the Second Day of PhoneGapping: Copying a native database
The topic of creating a large SQLiteDB to persist data on the device comes up a lot on the Google Group. Sadly, most of the modern web browsers limit you to a maximum database size of 5 megabytes. If you really need a database bigger than that you'll need to jump through a few hoops.
Luckily a developer by the name of Gaurav S Tomar has already gone through the process of explaining how to do this in his excellent blog post:
Prepopulate SQLite DataBase in PhoneGap Application
So go check it out!
What you say? Here we are on the second day and he's already pointing us to other people's blog posts. Well I never said I was going to write the all just want to make you aware of some tricks you can use in your PhoneGap applications.
Luckily a developer by the name of Gaurav S Tomar has already gone through the process of explaining how to do this in his excellent blog post:
Prepopulate SQLite DataBase in PhoneGap Application
So go check it out!
What you say? Here we are on the second day and he's already pointing us to other people's blog posts. Well I never said I was going to write the all just want to make you aware of some tricks you can use in your PhoneGap applications.
Sunday, December 25, 2011
On the First Day of PhoneGapping: Get to deviceready faster on Android
This tip is courtesy of a question that Pamela Fox posted up over on the PhoneGap Google Group as she was wondering why it sometimes takes longer for the PhoneGap deviceready event to fire.
As all good PhoneGappers know you need to wait until you receive the deviceready event before you can call any of the PhoneGap API's. But, what has to happen before the deviceready event fires? Well here is breakdown of events that fire before deviceready:
As all good PhoneGappers know you need to wait until you receive the deviceready event before you can call any of the PhoneGap API's. But, what has to happen before the deviceready event fires? Well here is breakdown of events that fire before deviceready:
- onDOMContentLoaded Internal event that is received when the web page is loaded and parsed.
- window.onload Body onload event.
- onNativeReady Internal event that indicates the PhoneGap native side is ready.
- onPhoneGapInit Internal event that kicks off creation of all PhoneGap JavaScript objects (runs constructors).
- onPhoneGapReady Internal event fired when all PhoneGap JavaScript objects have been created
- onPhoneGapInfoReady Internal event fired when device properties are available
- onPhoneGapConnectionReady Internal event fired when the connection property has been set.
- onDeviceReady User event fired to indicate that PhoneGap is ready
That may seem like a lot but you don't have to worry about it as you can't speed up the process any. That is, except in one area. The onNativeReady event does not fire until the the onPageFinished method gets called on the Android WebViewClient.
So anything you do that increases the amount of time before the web view understands the page is completely loaded will keep you from getting to deviceready. For instance if you are doing a lot of things in the window.onload method it will delay deviceready. In Pamela's particular instance she was doing an XmlHttpRequest in the onload method which delayed things.
The fix and the tip in this case is to move as many things from your onload event handler to your deviceready event handler.
So anything you do that increases the amount of time before the web view understands the page is completely loaded will keep you from getting to deviceready. For instance if you are doing a lot of things in the window.onload method it will delay deviceready. In Pamela's particular instance she was doing an XmlHttpRequest in the onload method which delayed things.
The fix and the tip in this case is to move as many things from your onload event handler to your deviceready event handler.
Friday, December 23, 2011
Twelve Days of PhoneGapping!
Starting on Christmas Day, December 25th, I'll be posting one PhoneGap tip per day for 12 days in what I'm grandiosely calling The Twelve Days of PhoneGap. Some of these tips you'll already know and some you won't but hopefully we'll all learn something.
For most of those days I'll actually be on vacation so it may take a bit for me to respond to any comments left on the post. Here's hoping everyone has a great holiday season!
For most of those days I'll actually be on vacation so it may take a bit for me to respond to any comments left on the post. Here's hoping everyone has a great holiday season!
Subscribe to:
Posts (Atom)