Phonegap/Cordova app– Reading and Listing phone contacts

This blog post is for explaining how we can list all the phone contacts in our android phonegap app. For details regarding phonegap phone-contacts API you can refer to npmjs page of plugin which list almost all the API’s you can use to extract out information from the device on which app is installed. I will try to cover some of the points which I wasn’t able to figure out from their help docs and had to debug my app in chrome using emulator.

In this sample app the targeted max Android SDK version is 23 and Cordova version to compile app is 6.1.1. With SDK version 23 and above it seems you have to prompt device user every time you want to fetch some information from his device. (If I will get some more information on that I will post how we can achieve that.)

Sample app for this app can be found here https://github.com/lakhanpalv/phone-contact-app. Assumption in this post are that you are already aware how to configure phonegap/Cordova app on windows machine with everything setup like android-sdk and Java sdk. (it’s possible the same code will work on iOS devices but never tried). Some of the 3rd party APIs I have used in my sample app which are not required for fetching contacts from android devices, such as Handlebar and jQuery. They are purely used for display and ease of manipulating markup or JavaScript objects you can do that with pure plain JavaScript.

Here are some learning:  You have to wait for deviceReady event being fired by app on launch and it is being handled by Cordova API. As I am using sample-phonegap app to start my project index.js file which comes with sample project already has that thing handled. You should initialize your application code only after deviceReady event is fired successfully. As there can be some plugins, and phonegap APIs which you want to use in your app code and if you don’t initialize your code after deviceReady event it’s possible that you will see some error and spend hours to figure out why it’s happening. Below is the listing code from index.js and I am initializing my application code in last line of function.

receivedEvent: function(id) {
        var parentElement = document.getElementById('get-phone-contacts');
        //var listeningElement = parentElement.querySelector('.listening');
        //var receivedElement = parentElement.querySelector('.received');

        //listeningElement.setAttribute('style', 'display:none;');
        parentElement.setAttribute('style', 'display:block;');

        console.log('Received Event: ' + id);
        MySampleApp.init(window, document, window.jQuery, Handlebars);
    }

 

code snippet of my sample application modular code. To make sure it doesn’t bleed any variable or method to global scope, and also this way it’s easier to initialize all of my application code when I want to, not when it get’s loaded in app in sequence.

var MySampleApp = {
    init: function (window, document, $, Handlebars) {

    }
};

Coming to real problem:

Phone contacts are stored under navigator object and you can supply some options parameters using ContactFindOptions() and supplying filter and other options as for example if you don’t want to fetch contacts which doesn’t have any number stored against them you can supply .hasPhoneNumber=true;(it seems to work only in Android, find detailed here) it will filter only contacts with number. You can limit extracted information for a contact by supplying information you you want to pick from contact for a user like in below snippet I am just trying to extract displayname, phonenumbers and emails of contact. You have to supply success callback and error callback methods in .find() method along with filter and options object.

var options = new ContactFindOptions();
      options.filter = "";
      options.multiple = true;
      //options.hasPhoneNumber = true;
      var filter = ["displayName", "phoneNumbers", "emails"];
      navigator.contacts.find(filter, onContactsFetchSuccess, onContactsFetchError, options);

Below is the code listing of success callback method, will explain it below code snippet:

var onContactsFetchSuccess = function(contacts) {
            for (var i = 0; i < contacts.length; i++) {
                if(contacts[i].displayName !== null){
                    if(contacts[i].phoneNumbers !== null){
                        for(var j=0; j<contacts[i].phoneNumbers.length;j++){
                            //select number only if it's mobile number
                            if(contacts[i].phoneNumbers[j].type === 'mobile'){
                                if(contacts[i].emails !== null){
                                    for(var k=0; k < contacts[i].emails.length; k++){
                                        phoneContactsData.push({'name' : contacts[i].displayName, 'number': contacts[i].phoneNumbers[j].value, 'email':contacts[i].emails[k].value});
                                        break;
                                    }
                                } else {
                                    phoneContactsData.push({'name' : contacts[i].displayName, 'number': contacts[i].phoneNumbers[j].value});
                                }
                                break;
                            }
                        }
                    }else{
                        if(contacts[i].emails !== null){
                            for(var k=0; k < contacts[i].emails.length; k++){
                                phoneContactsData.push({'name' : contacts[i].displayName, 'number': '', 'email':contacts[i].emails[k].value});
                                break;
                            }
                        }
                    }
                }
            }           
         };
var onContactsFetchSuccess = function(contacts) {
            for (var i = 0; i < contacts.length; i++) {
                if(contacts[i].displayName !== null){
                    if(contacts[i].phoneNumbers !== null){
                        for(var j=0; j<contacts[i].phoneNumbers.length;j++){
                            //select number only if it's mobile number
                            if(contacts[i].phoneNumbers[j].type === 'mobile'){
                                if(contacts[i].emails !== null){
                                    for(var k=0; k < contacts[i].emails.length; k++){
                                        phoneContactsData.push({'name' : contacts[i].displayName, 'number': contacts[i].phoneNumbers[j].value, 'email':contacts[i].emails[k].value});
                                        break;
                                    }
                                } else {
                                    phoneContactsData.push({'name' : contacts[i].displayName, 'number': contacts[i].phoneNumbers[j].value});
                                }
                                break;
                            }
                        }
                    }else{
                        if(contacts[i].emails !== null){
                            for(var k=0; k < contacts[i].emails.length; k++){
                                phoneContactsData.push({'name' : contacts[i].displayName, 'number': '', 'email':contacts[i].emails[k].value});
                                break;
                            }
                        }
                    }
                }
            }           
         };

 

Phone contacts and emails are stored as an array of objects in returned object, when you call contacts.find().

In my use case I am interested in getting all contacts who has either their emailid or mobile phone number and name as must.  Name of user is stored as “displayName” so I have started filtering the looped object at top with if name exist and then moved to phone number which is stored as “phoneNumbers” array of phone number objects. phone number object has “type” attribute which store information if number is ‘mobile’ or not. Similarly “emails” are also stored as array of email objects. I just restricted my information to one email so stopping my loop as soon as I get first email. Just ignore the phoneContactsData.push() line if you are not interested in storing and displaying the information as it’s specific to my use case i.e. not related to contacts extraction from device.

some of other lessons learned during this sample project creation and not related to phone contacts information extraction:

  • I was trying to limit plugin inclusion in config.xml for this sample project only to phone-contacts, but found some interesting conversation on the phonegap Google group (Removing unneeded features/plugins doesn’t have any effect on app performance https://groups.google.com/forum/?fromgroups=#!topic/phonegap/VBsWphi8ydA) not sure how authentic this information is though.
  • Create your application JavaScript code as a separate modular code so that you can initialize it when you receive onDeviceReady event and doesn’t bleed your code to global scope as well at the same time.
  • Best way to debug your phonegap/Cordova is to use android emulator and launch chrome://inspect/#devices in chrome browser where your launched emulator app will appear as soon as you compile your project and run it in emulator.
  • Using above way you can debug through your application code by stepping through each line and use console.log or all other features which you will normally use with your web app in chrome way better then weinre in which you simply can just put console.log() message to trace out the outputs at different steps, can’t really step through your code with that.

I hope this post is of some help in if not for phone contact listing, there are some other options I have explored in the code listed at github. Where I have tried to display the contacts as you can see in your Contacts options in phone with filter contact information option. I have used Handlebar to loop through my contacts object and then I have used jQuery/JavaScript to filter contacts and update contacts display accordingly.

 

Advertisements

One thought on “Phonegap/Cordova app– Reading and Listing phone contacts

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s