Export contacs to XML file (Android)

187 views
Skip to first unread message

bobz7

unread,
Jun 13, 2013, 4:09:23 AM6/13/13
to phon...@googlegroups.com
Hello,
I'm new to Phonegap and Android development as a whole and just started working a couple of weeks ago on a basic app for a class project using the Phongap API (2.7.0) and JQuery Mobile for themes.
The basic concept of my app is to allow the user to backup (and restore) all their phone contacts to a file and store it locally (in memory card) and as an additional feature, upload it to a remote server (MySQL database?), for future access.
I have gone through the official Phonegap documentation, especially regarding the contacts API, and while it's quite comprehensive, I'm having trouble figuring out how to extract all the contacts from the phone and export them to a file (I'm thinking XML is a good choice). I would be very grateful if someone could show me how this can be done, some sample code would be great too. I'm a noob when it comes to advanced programming. My coding skills are basic at best. In a nutshell -- I need to know how to export the contacts off a phone and write them to an XML file (or any other format, if it's more preferable).

bobz7

unread,
Jun 14, 2013, 2:21:53 PM6/14/13
to phon...@googlegroups.com
bump! Someone help me out!

Simon MacDonald

unread,
Jun 17, 2013, 11:02:03 PM6/17/13
to phonegap
I think you would get a better response if you showed that you tried.
When I read your message it kinda sounds like you are asking the list
to do your class project for you. I'm not saying that is what it is
but that's what it sounds like.

Here is the broad strokes of what you need to do:

1) Get all the contacts.

// find all contacts with 'Bob' in any name field
var options = new ContactFindOptions();
options.filter="";
options.multiple=true;
var fields = ["*"];
navigator.contacts.find(fields, onSuccess, onError, options);

The above code should get all the contacts with all the fields populated.

2) Don't use XML, the contacts data is returned as JSON data so stick with JSON.

3) In the success method of contacts.find write the data out to a file
using a FileWriter.

http://docs.phonegap.com/en/2.8.0/cordova_file_file.md.html#FileWriter

Simon Mac Donald
http://hi.im/simonmacdonald


On Fri, Jun 14, 2013 at 2:21 PM, bobz7 <g96...@gmail.com> wrote:
> bump! Someone help me out!
>
> --
> -- You received this message because you are subscribed to the Google
> Groups "phonegap" group.
> To post to this group, send email to phon...@googlegroups.com
> To unsubscribe from this group, send email to
> phonegap+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/phonegap?hl=en?hl=en
>
> For more info on PhoneGap or to download the code go to www.phonegap.com
>
> To compile in the cloud, check out build.phonegap.com
> ---
> You received this message because you are subscribed to the Google Groups
> "phonegap" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to phonegap+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

bobz7

unread,
Jun 18, 2013, 3:24:12 PM6/18/13
to phon...@googlegroups.com



Thanks a lot for the reply. It helped me move in the right direction. And yes, I have indeed written the code for the app.

I'll be posting the a snippet of the code below. Bsically, I have written two major functions that do the main work of finding the contacts and writing them to a file. These are namely -- createBackup() and writeBackupFile().

The code --

  function createBackup()
        {

            var options = new ContactFindOptions();
            options.filter="";
            options.multiple=true;
            var fields = ["displayName", "phoneNumbers"];
            navigator.contacts.find(fields, onContactSuccess, onContactError, options);
        }
        function onContactSuccess(contacts)
        {
            console.log("Contacts found: " + contacts.length);
            alert("Contacts found: " + contacts.length);
            for(var i=0;i<contacts.length;i++)
            {
            
            //find phone numbers
            for(var j=0;j<contacts[i].phoneNumbers.length;j++)
            {

                name = contacts[i].displayName;
                number = contacts[i].phoneNumbers[j].value;
                console.log("Name: " + name);
                console.log("Number: " + number);
               
                //push name and phone numbers into global arrays
                arN.push(name);
                arNum.push(number);
                console.log("Name in array: " + arN[i] + "\nNumber in array: " + arNum[j]);

               
                writeBackupFile();
            }
            }
           
        }
       
        function onContactError(contacts)
        {
            alert('OnError!');
        }
       
        function writeBackupFile()
        {
           window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
          
           function gotFS(fileSystem)
           {
            fileSystem.root.getFile("backup.txt", {create: true, exclusive: false}, gotFileEntry, fail);
           }
           function gotFileEntry(fileEntry)
           {
            fileEntry.createWriter(gotFileWriter, fail);
           }
           function gotFileWriter(writer)
           {
             writer.onwrite = function(evt)
             {
                  console.log("write success");
             };
            
             alert("length of arN: " + arN.length + "\n Length of arNum: " + arNum.length);
             for(var i=0;i<arN.length;i++)
             {
                 for (var j=0;j<arNum.length;j++)
                 {
                   
                    writer.seek(writer.length);
                    writer.write('{\n"name": ' + '"' + arN[i] + '"' + "\n" + '"number": ' + '"' + arNum[j]+ '"' + "\n}");
                    alert("writer wrote:\n " + '{\n    "name": ' + '"' + arN[i] + '"' + "\n" + '"number": ' + '"' + arNum[j]+ '"' + "\n}");
                   
                             
                 }
                             
             }
           };

           
            var fail = function(evt) {
            console.log(error.code);
            };
        }



Now, the problems --

1. While the number of contacts appears correct in the alert message (alert("Contacts found: " + contacts.length);), and I get all the results from the blue highlighted part of the code as expected on the emulator (it has 4 contacts), it does not seem to work the same on a real device. On a real phone (Huawei Ascend Y300), the first alert message reports the correct no. of contacts, however, I get only one contact as output from the highlighted code (it has 816 contacts, as reported by the first alert message). What could be the issue here? Any help would be greatly appreciated. You're also most welcome to correct any mistakes in the above code.

2. In the writeBackupFile method, I have specified the name of the file as "backup.txt". Do i need to make it "backup.json"? (The official PhoneGap example only had a txt as example, so I was not sure)

3. How do I specify a location for saving the backup file? And how do I view it on the emulated phone? On my real phone I have a file manager through which I can see the file created in the root directory. I would like to save it in the memory card.

4. As you can probably make out from the code, I'm appending the file with each entry. Is there a way to clear the file before writing to it, every time I call the
writeBackupFile method?


Thanks for any help.

Simon MacDonald

unread,
Jun 18, 2013, 5:17:06 PM6/18/13
to phonegap
Hmmm....I wouldn't accomplish the task in this manner.

1) Probably because you are creating a new writer on each iteration of
the loop so the length is probably still 0. Calling async code in a
loop is a bad idea.

2) No the extension does not matter.

3) "path/to/my/backup.txt"

4) Delete the file before you do a backup would clear it. Better idea,
move the backup copy to backup.001 in case something goes wrong with
your current backup as you already have a good one.

Instead of doing all this the "onContactSuccess" method is called with
an array of contacts. You can just do:

var contactsString = JSON.stringify(contacts);

to get a text representation of all the contacts as text. Then write
that to your back up file in one shot. No looping required.

Then you can read the text file and do a
JSON.parse(contentsOfTextFile) and you've got your array of contacts
back. Each object in that array can be sent to
navigator.contacts.create(contacts[i]) to create a new contact object
for your to save back on the device.

Simon Mac Donald
http://hi.im/simonmacdonald


bobz7

unread,
Jun 20, 2013, 3:04:19 AM6/20/13
to phon...@googlegroups.com
Brilliant! The writeBackupFIle function now works perfectly :) I'm getting all the contacts on the text file at once. Thanks a lot for the help.
However, could you elaborate a bit on the restoring part a bit? I'm slightly confused about how to parse the backup file and turn it into an object to restore (import) the contacts from the file.

Here's what I have so far, I have a restore function, and setup an FileReader inside it  (this mostly just off the sample code) --


function restore()
    {

        window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
   

        function gotFS(fileSystem) {
        fileSystem.root.getFile("backup.txt", null, gotFileEntry, fail);
        }

        function gotFileEntry(fileEntry) {
        fileEntry.file(gotFile, fail);
        }

        function gotFile(file){
       
        readAsText(file);
        }

        function readAsText(file) {
        var reader = new FileReader();
        reader.onloadend = function(evt) {
        console.log("Read as text");
        console.log(evt.target.result);
        };
        reader.readAsText(file);
        }
       
       
       
        function fail(evt) {
        console.log(evt.target.error.code);
        }
       
       
    }



How do I put all the data from the text file into the JSON.parse() function? Do I have to make a new array and pass the result of the reader.readAsText(file)function to it? Please elaborate a bit on this. Sorry if I'm asking silly questions, like i said, I'm a noob when it comes to moderate\advanced programming.












On Thursday, June 13, 2013 1:39:23 PM UTC+5:30, bobz7 wrote:

Simon MacDonald

unread,
Jun 20, 2013, 10:53:51 AM6/20/13
to phonegap
In your onloadend method you can parse the text you just read:

reader.onloadend = function(evt) {
console.log("Read as text");
console.log(evt.target.result);
var contacts = JSON.parse(evt.target.result);
// do something with contacts.
};

So the "contacts" at that point would be exactly the same as the JS
object that is returned from navigator.contacts.find().


Simon Mac Donald
http://hi.im/simonmacdonald


bobz7

unread,
Jun 22, 2013, 9:00:05 AM6/22/13
to phon...@googlegroups.com
Do I need to make a loop for creating new contacts in the restore function? I have written some messed up code, from my understanding of the logic. It doesn't seem to be working. Please take a look --

//new code
        var contacts = JSON.parse(evt.target.result);
       
        //loop to create and save contact
        console.log(contacts.length);
        alert(contacts.length);

        for(var i=0;i<contacts.length;i++){
            var resContact = navigator.create.contact({"displayName": contacts[i].displayName});
            //phone number loop
            for (var j=0;j<contacts[i].phoneNumbers.length;j++)
            {
                var phoneNumbers = [];
                phoneNumbers[j] = new ContactField(contacts[i].phoneNumbers[j].type, contacts[i].phoneNumbers[j].type, contacts[i].phoneNumbers[j].pref);

            }
            resContact.save();
        }


Thanks again for your help.












On Thursday, June 13, 2013 1:39:23 PM UTC+5:30, bobz7 wrote:

Simon MacDonald

unread,
Jun 24, 2013, 1:34:14 PM6/24/13
to phonegap
Look at this gist:

https://gist.github.com/macdonst/5695503

Basically all you'd need to do would be:

var contacts = JSON.parse(evt.target.result);
saveAllTheContacts(contacts);

Boom, done. You don't need to look at all the property fields in the
contact. BTW, the code you wrote will have a problem with contacts
that have no phone number. The check contacts[i].phoneNumbers.length
could throw an error if contacts[i].phoneNumbers is null.

Simon Mac Donald
http://hi.im/simonmacdonald


bobz7

unread,
Jun 27, 2013, 10:50:29 AM6/27/13
to phon...@googlegroups.com
Getting this on Logcat

06-27 20:14:45.940: D/ContactsAccessor(807): Could not get name
06-27 20:14:45.940: D/ContactsAccessor(807): Could not get phone numbers
06-27 20:14:45.940: D/ContactsAccessor(807): Could not get emails
06-27 20:14:45.940: D/ContactsAccessor(807): Could not get addresses
06-27 20:14:45.940: D/ContactsAccessor(807): Could not get organizations
06-27 20:14:45.940: D/ContactsAccessor(807): Could not get emails
06-27 20:14:45.940: D/ContactsAccessor(807): note is string called 'null'
06-27 20:14:45.940: D/ContactsAccessor(807): nickname is string called 'null'
06-27 20:14:45.940: D/ContactsAccessor(807): Could not get websites
06-27 20:14:45.940: D/ContactsAccessor(807): birthday is string called 'null'
06-27 20:14:45.950: D/ContactsAccessor(807): Could not get photos


Saw the comments on the gist, but didn't quite understand your response there.
Why can't the method find the values? Isn't it getting them from the contacts array? That's what the contacts.pop() function was for, right?














On Thursday, June 13, 2013 1:39:23 PM UTC+5:30, bobz7 wrote:

Simon MacDonald

unread,
Jun 27, 2013, 11:06:10 AM6/27/13
to phonegap
You can ignore those logs as not all contacts will have all their fields filled in. Those logs are informational only. 

--

bobz7

unread,
Jun 27, 2013, 11:48:01 AM6/27/13
to phon...@googlegroups.com
Something's not right. Contacts aren't being created from the function. Not sure what's wrong, everything else seems ok. Also, take a look at this code --

//new code
        var contacts = JSON.parse(evt.target.result);

        console.log("JSON Data parsed");
        saveAllTheContacts(contacts);
        console.log("saveAllTheContacts function invoked");
        };
       
        reader.readAsText(file);

       
        alert("Successful!\n Contacts after restore: " /*+ contacts.length*/);
        console.log("alert trigger");

   
        }
        function fail(evt) {
        console.log(evt.target.error.code);
        }   
    } 

The pink highlighted code works fine, with all the console messages and everything. But the code highlighted in blue doesn't seem to work unless I remove the "contacts.length" bit. I get no alert or console message. It works fine otherwise. Strange. 











On Thursday, June 13, 2013 1:39:23 PM UTC+5:30, bobz7 wrote:

Charles Carver

unread,
Jun 27, 2013, 4:08:47 PM6/27/13
to phon...@googlegroups.com
Probably because there is no contacts.length.

bobz7

unread,
Jun 29, 2013, 11:16:44 AM6/29/13
to phon...@googlegroups.com
Didn't quite answer my question. The saveAllTheContacts function isn't working like it should. No contacts are being created.














On Thursday, June 13, 2013 1:39:23 PM UTC+5:30, bobz7 wrote:

bobz7

unread,
Jul 3, 2013, 5:49:57 AM7/3/13
to phon...@googlegroups.com
Anything? Anyone?









On Thursday, June 13, 2013 1:39:23 PM UTC+5:30, bobz7 wrote:

Simon MacDonald

unread,
Jul 3, 2013, 9:15:24 AM7/3/13
to phonegap

bobz7

unread,
Jul 3, 2013, 1:31:49 PM7/3/13
to phon...@googlegroups.com
Excellent. It's working perfectly now. Setting the Id and rawId as null seems to have solved the issue. However, is there a way to keep\update the existing contacts, without deleting the entire database every time? In case I want to implement a sort of incremental restore functionality. You know, creating\saving only contacts that don't already exist. Thanks a lot for your help again, you're a lifesaver!











On Thursday, June 13, 2013 1:39:23 PM UTC+5:30, bobz7 wrote:

Simon MacDonald

unread,
Jul 8, 2013, 1:52:58 PM7/8/13
to phonegap
If you leave the id and rawId attributes in it will do an update.

--
Reply all
Reply to author
Forward
0 new messages