Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i render a list of all iPhone contacts with Cordova (phone gap)

I am trying to create a Application which lists all contacts from the iPhone address book with the following code (coffeescript)

listContacts: ->
    options = new ContactFindOptions()
    options.filter = '';
    options.multiple = true
    fields = ["id", "photos", "name", "phoneNumbers"]
    navigator.contacts.find(fields, @onSuccess, @onError, options)

onSuccess: (contacts) ->
    console.log contacts.length

onError: (error) ->
    console.log error

this seems to work nice for a bunch of contacts. but with 3000 the contacts will never return. the funny thing though this works perfectly on the iOsSimulator.

are there any limitations to the number of contacts which can be retrieved?

like image 635
reco Avatar asked Nov 02 '12 03:11

reco


2 Answers

I had the same problem with 300 contacts, it took around 5 minutes. After I patched it only takes 10 seconds.

Here is my pull request : https://github.com/phonegap/phonegap/pull/19

They have to generate a temp file for each picture and they are using a crazy loop to find a free file path. Something like :

do {        
  filePath = [NSString stringWithFormat:@"%@/photo_%03d.jpg", docsPath, i++];       
} while ([fileMgr fileExistsAtPath:filePath]);

Now I use mktemp and everything is faster.

If you don't need full res pictures, you can also replace :

CFDataRef photoData = ABPersonCopyImageData(self.record);

by :

CFDataRef photoData = ABPersonCopyImageDataWithFormat(self.record, kABPersonImageFormatThumbnail);

I hope that'll help you !

Edit :

IOS'll flush the temp directory each time you start the application:

You are responsible for deleting any temporary files that you created. The system will clean them up at startup, but that could be a very long time away.

From: http://cocoadev.com/wiki/NSTemporaryDirectory

If you don't want to slow down the bootstrap of your application, you should use always the same filepath based on the contact id. You'll save cleanup and write time if the file already exists :

- (NSObject*)extractPhotos
{
    NSMutableArray* photos = nil;

    if (ABPersonHasImageData(self.record)) {

        //CFDataRef photoData = ABPersonCopyImageDataWithFormat(self.record, kABPersonImageFormatThumbnail);
        CFDataRef photoData = ABPersonCopyImageData(self.record);
        NSData* data = (__bridge NSData*)photoData;

        // write to temp directory and store URI in photos array
        // get the temp directory path
        NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];
        NSError* err = nil;
        int recordId = ABRecordGetRecordID(self.record);

        NSFileManager* fileMgr = [[NSFileManager alloc] init];
        NSString* filePath = [NSString stringWithFormat:@"%@/photo_%03d.jpg", docsPath, recordId];
        BOOL hasImage = NO;

        if ([fileMgr fileExistsAtPath:filePath]) {
            hasImage = YES;
        } else if ([data writeToFile:filePath options:NSAtomicWrite error:&err]) {
            hasImage = YES;
        }

        if (hasImage) {
            photos = [NSMutableArray arrayWithCapacity:1];
            NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithCapacity:2];
            [newDict setObject:filePath forKey:kW3ContactFieldValue];
            [newDict setObject:@"url" forKey:kW3ContactFieldType];
            [newDict setObject:@"false" forKey:kW3ContactFieldPrimary];
            [photos addObject:newDict];
        }

        CFRelease(photoData);
    }
    return photos;
}

Edit (08/01/2013): FYI : merged in cordova : http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/c6a1dbe3

like image 200
Emmanuel Tabard Avatar answered Nov 18 '22 08:11

Emmanuel Tabard


First you have to add plugin from terminal command line

$ cordova plugin add org.apache.cordova.contacts

onDeviceReady you can call a method to open contact list

function chooseContact() {
    var options = new ContactFindOptions();
    options.fields = ["displayName", "name", "emails", "phoneNumbers"];
    navigator.contacts.chooseContact(onSuccess, options);
}

function onSuccess(id, contact) {
    console.log(JSON.stringify(contact));
}
like image 27
Muhammad Aamir Ali Avatar answered Nov 18 '22 08:11

Muhammad Aamir Ali