Preloading a SQLite Database on iPhone - Solution

6,702 views
Skip to first unread message

reverend

unread,
Mar 2, 2009, 3:58:15 PM3/2/09
to phonegap
I was pounding my head against installing a big (120K rows) SQLite
database in an iPhone application. It's a dictionary for a game.
Trying to build the database with Javascript was prohibitive. I
could do it, but it took forever, and sometimes crashed on the phone,
even though it worked in the simulator.

But from that, I was able to take the database that was build for the
simulator, and copy it in to my Resources folder, and then modify the
Objective C to install it in the proper location on the iPhone.
Actually, there are 2 files that need to be installed. The database
file itself, and the "Databases.db" file, which keeps track of the
webkit databases and their names...

So here's the process I used.

* I built the SQLite database file in the iPhone simulator (it was
named 0000000000000001.db)

* The iPhone simulator files live (by default) at /Users/<your user>/
Library/Application\ Support/iPhone\ Simulator/User/Applications/<your
app id>/Library/WebKit/Databases/file__0/<database name>

* I copied both the "Databases.db" file (from the Databases folder),
and the "0000000000000001.db" file (from the file_0 folder) in to the
Resources folder of my project, which makes them included in the app
bundle that is installed.

* I then modified the GlassAppDelegate.h file to include the following
INSIDE the @interface GlassAppDelegate section (inside the { })

// Database variables
NSString *databaseName;
NSString *databasePath;
NSString *databaseFile;
NSString *masterName;
NSString *masterPath;
NSString *masterFile;

* I added the following to the GlassAppDelegate.m file INSIDE the
applicationDidFinishLaunching function

//Copy over the database if it doesn't exist
// Setup some globals
databaseName = @"0000000000000001.db";
masterName = @"Databases.db";

// Get the path to the Library directory and append the databaseName
NSArray *libraryPaths = NSSearchPathForDirectoriesInDomains
(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libraryDir = [libraryPaths objectAtIndex:0];
// the directory path for the Databases.db file
masterPath = [libraryDir stringByAppendingPathComponent:@"WebKit/
Databases/"];
// the directory path for the 0000000000000001.db file
databasePath = [libraryDir stringByAppendingPathComponent:@"WebKit/
Databases/file__0/"];
// the full path for the Databases.db file
masterFile = [masterPath stringByAppendingPathComponent:masterName];
// the full path for the 0000000000000001.db file
databaseFile = [databasePath
stringByAppendingPathComponent:databaseName];
// Execute the "checkAndCreateDatabase" function
[self checkAndCreateDatabase];


* And finally, I added another function below
applicationDidFinishLaunching called checkAndCreateDatabase, as
follows:


-(void) checkAndCreateDatabase{
// Check if the SQL database has already been saved to the users
phone, if not then copy it over
BOOL success;

// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];

// Check if the database has already been created in the users
filesystem
success = [fileManager fileExistsAtPath:databasePath];

// If the database already exists then return without doing anything
if(success) return;

// If not then proceed to copy the database from the application to
the users filesystem



// Get the path to the database in the application package
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:databaseName];
NSString *masterPathFromApp = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:masterName];

// Create the database folder structure
[fileManager createDirectoryAtPath:databasePath
withIntermediateDirectories:YES attributes:nil error:NULL];

// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databaseFile
error:nil];
// Copy the Databases.db from the package to the appropriate place
[fileManager copyItemAtPath:masterPathFromApp toPath:masterFile
error:nil];

[fileManager release];
}



So this all works great! It is very quick, and won't overwrite the
database upon subsequent launches...

Hope it helps!

Pete

Brian LeRoux

unread,
Mar 2, 2009, 4:42:01 PM3/2/09
to phon...@googlegroups.com
wow, pete this is cool stuff man, need to get this in the wiki ---
wonder what pains we'd see bringing this idea into android..

davidroe

unread,
Mar 2, 2009, 4:55:30 PM3/2/09
to phonegap
nice work, Pete. you da man.

Douglas

unread,
Mar 5, 2009, 3:40:32 AM3/5/09
to phonegap
Wow. This addresses the exact issue I'm having, and I don't think
there's another answer to this problem to be found anywhere, so
cheers!

I haven't yet attempted this solution, for a few reasons, but before I
do I'd like to ask you a question or 2 if I might:

1) I guess the main question is: how will I then reference the
database from javascript once this is all complete? I'm using the:

mydb = openDatabase(shortName, version, displayName, maxSize);

as per the example code. Would I still use this method? If so, what
would be the "shortName"?


2) My other question is directed at the group in general: WOULD
ANYONE BE INTERESTED IN BEING PAID TO MAKE A MUCH SIMPLER SOLUTION TO
THIS PROBLEM?

I'm not talking bundles here, but, I don't know, how about a bounty of
$500 for the solution I'm looking for? Maybe it doesn't even require
writing any code, just telling me what the heck to do :)

Here's my situation:

I am building an app using PhoneGap where I too want to include a pre-
populated database (~50K rows). For this app it will be read-only,
though I don't suppose that matters much.

As reverend says, this is impractical to do by loading the data in
javascript. I would imagine it taking an eternity to launch. Just
not the way to go.

At this point I've built the database itself using sqlite3 on the
command-line. I'm just learning sqlite, but it seems to work well
enough. I've got a myapp.db file that I can shell-into using sqlite3,
run queries, check the schema, everything seems kosher.

So that alone is different than reverend's method, since he built the
database from javascript to begin with. I suppose I could try that,
but since this is a technique I plan to use quite a bit on different
apps, I'd much rather have a clean way to build a database using
whatever my preferred method, then just add it as a Resource or
something and be able to open it from Javascript.

So if anyone knows how to do this relatively simply, or could code-up
a simple extension to PhoneGap (I'm no C-coder, hence why I'm using
PhoneGap to begin with [love it], and an Xcode noob to boot) that
would make this possible, I would be very thankful.

And if a monetary incentive would help, let's talk.

Thanks.
-Douglas

Douglas

unread,
Mar 6, 2009, 9:51:20 AM3/6/09
to phonegap
WORKS WITH EXISTING DATABASE!

So, I answered my own question (above). Using all of Pete's steps, I
was able to get my large database loaded.

However, I didn't need to build the full database first in
Javascript. Well I did build an identical schema, but the full
database I built using other tools.

But copying over my sqlite db, and renaming it 0000000000000001.db, as
well as copying over the Database.db file, plus the other code
changes, did indeed work. I am amazed. Thank you thank you thank
you.

Now I did need to make the leap of faith that the files to edit were
PhoneGapDelegate.h and PhoneGapDelegate.m, NOT GlassApp*

Don't know if the project name changed recently, or if I downloaded an
older version or what, but hey, it worked.

Thanks much.



On Mar 3, 3:58 am, reverend <rever...@ntw.net> wrote:
> I was pounding my head against installing a big (120K rows) SQLitedatabasein an iPhone application.   It's a dictionary for a game.
> Trying to build thedatabasewith Javascript was prohibitive.   I
> could do it, but it took forever, and sometimes crashed on the phone,
> even though it worked in the simulator.
>
> But from that, I was able to take thedatabasethat was build for the
> simulator, and copy it in to my Resources folder, and then modify the
> Objective C to install it in the proper location on the iPhone.
> Actually, there are 2 files that need to be installed.   Thedatabase
> file itself, and the "Databases.db" file, which keeps track of the
> webkit databases and their names...
>
> So here's the process I used.
>
> * I built the SQLitedatabasefile in the iPhone simulator (it was
> named 0000000000000001.db)
>
> * The iPhone simulator files live (by default) at /Users/<your user>/
> Library/Application\ Support/iPhone\ Simulator/User/Applications/<your
> app id>/Library/WebKit/Databases/file__0/<databasename>
>
> * I copied both the "Databases.db" file (from the Databases folder),
> and the "0000000000000001.db" file (from the file_0 folder) in to the
> Resources folder of my project, which makes them included in the app
> bundle that is installed.
>
> * I then modified the GlassAppDelegate.h file to include the following
> INSIDE the @interface GlassAppDelegate section (inside the { })
>
>         //Databasevariables
>          NSString *databaseName;
>          NSString *databasePath;
>          NSString *databaseFile;
>          NSString *masterName;
>          NSString *masterPath;
>          NSString *masterFile;
>
> * I added the following to the GlassAppDelegate.m file INSIDE the
> applicationDidFinishLaunching function
>
>         //Copy over thedatabaseif it doesn't exist
>         // Setup some globals
>         databaseName = @"0000000000000001.db";
>         masterName = @"Databases.db";
>
>         // Get the path to the Library directory and append the databaseName
>         NSArray *libraryPaths = NSSearchPathForDirectoriesInDomains
> (NSLibraryDirectory, NSUserDomainMask, YES);
>         NSString *libraryDir = [libraryPaths objectAtIndex:0];
>         // the directory path for the Databases.db file
>         masterPath = [libraryDir stringByAppendingPathComponent:@"WebKit/
> Databases/"];
>         // the directory path for the 0000000000000001.db file
>         databasePath = [libraryDir stringByAppendingPathComponent:@"WebKit/
> Databases/file__0/"];
>         // the full path for the Databases.db file
>         masterFile = [masterPath stringByAppendingPathComponent:masterName];
>         // the full path for the 0000000000000001.db file
>         databaseFile = [databasePath
> stringByAppendingPathComponent:databaseName];
>         // Execute the "checkAndCreateDatabase" function
>         [self checkAndCreateDatabase];
>
> * And finally, I added another function below
> applicationDidFinishLaunching called checkAndCreateDatabase, as
> follows:
>
> -(void) checkAndCreateDatabase{
>         // Check if the SQLdatabasehas already been saved to the users
> phone, if not then copy it over
>         BOOL success;
>
>         // Create a FileManager object, we will use this to check the status
>         // of thedatabaseand to copy it over if required
>         NSFileManager *fileManager = [NSFileManager defaultManager];
>
>         // Check if thedatabasehas already been created in the users
> filesystem
>         success = [fileManager fileExistsAtPath:databasePath];
>
>         // If thedatabasealready exists then return without doing anything
>         if(success) return;
>
>         // If not then proceed to copy thedatabasefrom the application to
> the users filesystem
>
>         // Get the path to thedatabasein the application package
>         NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath]
> stringByAppendingPathComponent:databaseName];
>         NSString *masterPathFromApp = [[[NSBundle mainBundle] resourcePath]
> stringByAppendingPathComponent:masterName];
>
>         // Create thedatabasefolder structure
>         [fileManager createDirectoryAtPath:databasePath
> withIntermediateDirectories:YES attributes:nil error:NULL];
>
>         // Copy thedatabasefrom the package to the users filesystem
>         [fileManager copyItemAtPath:databasePathFromApp toPath:databaseFile
> error:nil];
>         // Copy the Databases.db from the package to the appropriate place
>         [fileManager copyItemAtPath:masterPathFromApp toPath:masterFile
> error:nil];
>
>         [fileManager release];
>
> }
>
> So this all works great!    It is very quick, and won't overwrite thedatabaseupon subsequent launches...
>
> Hope it helps!
>
> Pete

reverend

unread,
Mar 6, 2009, 1:29:31 PM3/6/09
to phonegap
On Mar 6, 7:51 am, Douglas <nanowo...@gmail.com> wrote:
>
> Thanks much.
>

Yep, my pleasure....

Glad you got it figured out. Basically, what you're doing is
installing the database in the same location as if it had been built
by the Javascript, so you can use it exactly the same way, with
openDatabase, etc.

Sorry about the Delegate file issue. I had built it on an older
project that was using an older PhoneGap, so thanks for pointing that
out :-)

Pete

David Orchard

unread,
Mar 6, 2009, 7:16:00 PM3/6/09
to phon...@googlegroups.com
Another option is fmdb-migration-manager, a very cool tool for this
exact purpose.

http://github.com/mocra/fmdb-migration-manager/tree/master

cheers,
Dave

Chuks Ugwuh

unread,
Sep 23, 2013, 4:35:15 PM9/23/13
to phon...@googlegroups.com
Hi, came across your solution for using prepopulated databases on iOS. Do you have any solution for android? I have tried all the solutions I found online and have still been unable to get it to work. I can send my code across for you to take a look at. 

Thanks

shafi

unread,
Nov 2, 2013, 7:02:21 AM11/2/13
to phon...@googlegroups.com
Hi

This solution doesnt work right now.. Any idea about implementing prepopulated db on ios 7?

WebSteve

unread,
Nov 4, 2013, 5:07:33 PM11/4/13
to phon...@googlegroups.com

isoftga...@gmail.com

unread,
Feb 27, 2014, 5:33:46 AM2/27/14
to phon...@googlegroups.com
Hi,

Nice to see that all of you are contributing in development.

I m noob developer and i too want to develop a app using PhoneGap...
Now i just need some instructions or sample code to access the sqlite database located in app.
I want to get database data to be presented in html.

Please help. Any suggestions and resources are appreciated.

Sandi Laufenberg-Deku (TruthLuvver/ LadySword )

unread,
Oct 28, 2016, 4:07:13 PM10/28/16
to phonegap, SANDI.tr...@gmail.com, sa...@ladysword.biz
NOTE FOR ANDROID - I found a way to do a pre-load equivalent to this iPhone solution.  This will load a sqlite db to Android. However, it MAY only work with newer versions of PhoneGap/Cordova & Android... See #1 and 2, "Litehelpers/Cordova" below.

I AM STILL SEEKING a way using PhoneGap 1.3.0. (from like 2012).  I have briefly tried:
    "Litehelpers/Cordova-sqlite-storage" and "Litehelpers/Cordova-sqlite-legacy-build-support"
... but it didn't work straight out of the box with PhoneGap 1.3.0. 

The documentation for Litehelpers legacy #2 reads:
    >>>     A recent version of the Cordova CLI (such as 6.3.1) is recommended. Cordova versions older than 6.0.0 are missing the cordo...@4.0.0 security fixes.  <<<
 
It's easy to connect to an external SQLite .db file with native Java, but I don't know how to access it from Javascript yet. (I also found a Litehelpers example to use for that back in 2012.)

I have been searching and searching for a way to do it with older Phonegap - it seems hardly any others know how to do it also.  MAYBE WE SHOULD TRY THE COPY METHOD used for iPhone here?  We just need to know where to copy it to in Android. If someone can get this to work, please post a reply here, if possible.

Here are the Litehelper packages:

======

(1) litehelpers/Cordova-sqlite-storage
A Cordova/PhoneGap plugin to open and use sqlite databases on Android, iOS and Windows with HTML5/Web SQL API

Native interface to sqlite in a Cordova/PhoneGap plugin for Android, iOS, macOS, and Windows, with API similar to HTML5/Web SQL API.

This is the common version which supports the most widely used features and serves as the basis for the other versions.

    • It is recommended to read through the usage and sample sections before building more complex applications. In general it is recommended to start by doing things one step at a time, especially when an application does not work as expected.
    • The new brodybits / Cordova-sqlite-bootstrap-test sample is intended to be a boilerplate to reproduce and demonstrate any issues you may have with this plugin. You may also use it as a starting point to build a new app.
    • In case you get stuck with something please read through the support section and follow the instructions before raising an issue. Professional support is also available by contacting: sa...@litehelpers.net

Pasted from <https://github.com/litehelpers/Cordova-sqlite-storage>

=====

(2) litehelpers/Cordova-sqlite-legacy-build-support
Legacy version of Cordova/PhoneGap plugin to open and use sqlite databases on Android/iOS/Windows/WP8 with HTML5/Web SQL API
    2ND VERSION - BUT NEEDS
    A recent version of the Cordova CLI (such as 6.3.1) is recommended. Cordova versions older than 6.0.0 are missing the cordo...@4.0.0 security fixes.

Pasted from <https://github.com/litehelpers/Cordova-sqlite-legacy-build-support>

=====

NOTE:  Why am I still using PhoneGap 1.3.0 version? Cuz it works for me. I learned PhoneGap with this version. Then later they came out with advanced versions requiring cmd line configurations/install, etc.  Since all I have to do is drop my 1.3.0 library in to Eclipse project for 1.3.0, I am finding that MUCH EASIER and have not yet upgraded to higher versions.  So I AM NOT SURE that the litehelpers can be used with 1.3.0. But they do provide a way, though, for higher versions of PhoneGap/Cordova!

- Sandi TruthLuvver
www.LadySword.net

Steve Husting

unread,
Oct 31, 2016, 10:55:45 AM10/31/16
to phonegap, SANDI.tr...@gmail.com, sa...@ladysword.biz
The docs have already answered your question: "A recent version of the Cordova CLI (such as 6.3.1) is recommended. Cordova versions older than 6.0.0 are missing the cordo...@4.0.0 security fixes." Besides which, Google Play will not accept the app in its store. Is this for the Play store?
Reply all
Reply to author
Forward
0 new messages