tags:

views:

76

answers:

5

Is it possible to have a self-updating iPhone application?

I believe the answer is no, but I am not sure.

I have a database driven app that is in effect a catalogue of products. I want the database to be on the users iPhone so the catalog is fast to use. However, periodically the content in the database changes.

I could create a push notification to tell the user that there is a database update ready, but it would be better if the app updates itself.

+2  A: 

as long as you don't need to change anything inside the app-bundle this is possible. Just save your content to the Documents Directory.

And of course you are allowed to update your own database.

fluchtpunkt
+2  A: 

As fluchtpunkt answered, an iOS app can download new data, it just can't download new code. Many iOS apps, such as the multitude of Twitter clients, primarily download and display data.

Where an app will get into trouble is if its interface doesn't make clear the app is downloading data. An app shouldn't use up an iPhone's data plan allotment without the user knowing. Letting the user know can range from explicit notifications including the option to cancel the download to making the concept of the app all about downloading data (e.g. Twitter clients).

The user must also be notified if the app is sharing any information with the server. The app may want to send such data to selectively download specific data. For example the app could use location information to tailor the database, downloading only items available in the region the device happens to be. A login process may be sufficient notification, if the data is account specific.

Mr. Berna
A: 

u can do it with push notification apart from that u can set timer which will download new data every specified time but the problem is the app has to be open all the time.in ios 4 there is local notification which can send notificationn to user even when app is closed

pankaj kainthla
A: 

My app uses an SQLite database and updates it. With every start (or waking up from suspended mode) it connects to my web server and checks for a new database. To authenticate the database, it first only downloads a file containing the MD5 sum of the online database and calculates the MD5 sum of the database on the phone. Only if the sums differ, the new database will be downloaded. This has the nice side effect that it keeps the traffic low.

Sample code for calculatimg the MD5 sum:

#define CHUNK_SIZE 16384
#import <CommonCrypto/CommonDigest.h>

+ (NSString *)md5SumForFileAtPath:(NSString *)path {
    NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];

    CC_MD5_CTX md5;
    CC_MD5_Init(&md5);

    BOOL done = NO;
    while(!done)
    {
        NSData* fileData = [handle readDataOfLength:CHUNK_SIZE];
        CC_MD5_Update(&md5, [fileData bytes], [fileData length]);
        if ([fileData length] == 0) done = YES;
    }
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final(result, &md5);

    NSString *digest = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                    result[0], result[1], result[2], result[3],result[4], 
                    result[5], result[6], result[7], result[8], result[9], 
                    result[10], result[11], result[12], result[13],
                    result[14], result[15]
                    ];
    XLog("Checksum for file %@: %@", path, digest);
    return digest;  
}

However, downloading the entire database is only a good solution if the database is not to large. Additionally, I gzipped the database and extract it after the download.

#import <zlib.h>
+ (void)gunzipFileAtPath:(NSString *)zippedPath toPath:(NSString *)unzippedPath {
    gzFile file = gzopen([zippedPath UTF8String], "rb");
    FILE *dest = fopen([unzippedPath UTF8String], "w");
    unsigned char buffer[CHUNK_SIZE];
    int uncompressedLength;
    while (uncompressedLength = gzread(file, buffer, CHUNK_SIZE) ) {
        if(fwrite(buffer, 1, uncompressedLength, dest) != uncompressedLength || ferror(dest)) {
            NSLog(@"error writing data");
        }
    }
    fclose(dest);
    gzclose(file);
}

It is perfectly fine to only show the network activity indicator in the status bar and not use a progress bar or other indicator. If the phone's database is up to date, I do not even notify the user, as it is unnecessary information and will only distract him. However, if there is an update, I fade in an overlay of the status bar and display the information for a few seconds. From the feedback of my users, I can tell that they pretty much appreciate this solution.

Do not forget that you add cryptography by calculating the MD5 sum. You have to indicate this to Apple when uploading your next Update. I only had to answer one more question and say that I use encryption only for authentication. The app was approved without any problems.

muffix
+1  A: 

It's not possible to load an executable on the iPhone, although it's worth noting that you can load resource bundles dynamically. If you use IB for creating your views, then you can create an entirely new view, put it up on the cloud and load it from the app. The only caveat is that you can only update the design, but not extend functionality.

To load a XIB dynamically, use the initWithNibName method,

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle

and pass in the dynamically loaded bundle.

On the Mac, it is possible to have bundles that contain executable code which can be dynamically loaded, but not on the iPhone. There is a Plist configuration named NSPrincipalClass for the Mac, but unfortunately not for the iPhone yet.

Anurag