如何将预先填充的sqlite数据库集成到phonegap iPhone应用程序中

时间:2013-07-09 17:20:39

标签: iphone database sqlite cordova

我想将预先填充的sqlite数据库集成到phonegap iPhone应用程序中,但我无法使用javascript连接数据库。

整合的必要步骤是什么?

我使用Phonegap-SQLite插件(https://github.com/davibe/Phonegap-SQLitePlugin/)。单元测试运行正常。 (动态创建数据库,从中读/写),这样插件就可以了。但我无法访问预先填充的数据库。

db放在Resources文件夹中。它列在项目选项/构建阶段/复制捆绑资源

我尝试在javascript中按如下方式分配它:

var db = window.sqlitePlugin.openDatabase({name: "dbname.db"});

它返回一个db对象,但不是填充的db。有趣的是,当我在模拟器中进行新的运行时,会使用相同的数据库。

在日志窗口中,我收到以下消息:

  

成品装载:   文件:///Users/username/Library/Application%20Support/iPhone%20Simulator/5.0/Applications/33553FCA-3FFA-4BBB-9986-110721148F85/Appname.app/www/index.html

     

2013-07-09 18:39:14.977 Raumklima [49796:c07]检测到文档路径:   / Users / dave / Library / Application Support / iPhone   模拟器/ 5.0 /应用/ 33553FCA-3FFA-4BBB-9986-110721148F85 /文件

     

2013-07-09 18:39:14.977 AppName [49796:c07]使用db name:   / Users / usernam / Library / Application Support / iPhone   模拟器/ 5.0 /应用/ 33553FCA-3FFA-4BBB-9986-110721148F85 /文档/ dbname.db

我使用手机差距2.5.0

有人知道我在哪里寻找解决方案吗?可能是什么问题呢?或者一般来说应该如何解决这个问题。

在这个平台上已经提出了类似的问题,但还没有答案:

Creating a PhoneGap iOS app with a pre-existing database

How to use a prepopulated SQLite database with PhoneGap / Cordova 2.0?

3 个答案:

答案 0 :(得分:3)

SQLitePlugin不会为您提供已预先填充的数据库。所以目前发生的是您在Documents中打开数据库,该数据库尚不存在,因此SQLite创建并打开一个空数据库。

如果希望SQLitePlugin从参考资料部分的现有SQLite数据库填充数据库,则需要做一些工作才能实现。这就是我所做的:(替换open中的SQLPlugin.m方法)

/* This is a hacked version which will copy the file from the Resources path
   if it does not exist in the Documents path or if it is newer. */

-(void)open: (CDVInvokedUrlCommand*)command
{
    CDVPluginResult* pluginResult = nil;
    NSMutableDictionary *options = [command.arguments objectAtIndex:0];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *dbname = [self getDBPath:[options objectForKey:@"name"]];
    NSValue *dbPointer;

    if (dbname == NULL) {
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"You must specify database name"];
    }
    else {
        dbPointer = [openDBs objectForKey:dbname];
        if (dbPointer != NULL) {
            // NSLog(@"Reusing existing database connection");
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"Database opened"];
        }
        else {
            //NSLog(@"Opening %@", dbname );
            NSError *error;
            NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:[options objectForKey:@"name"]];
            //NSLog(@"Date in app was %@", [[[fileManager attributesOfItemAtPath:databasePathFromApp error:NULL] fileModificationDate] description]);
            //NSLog(@"Local date was %@", [[[fileManager attributesOfItemAtPath:dbname error:NULL] fileModificationDate] description]);


            if (![fileManager fileExistsAtPath:dbname]) {
                BOOL success = [fileManager copyItemAtPath:databasePathFromApp toPath:dbname error:&error] ;
                if (!success) {
                    NSLog(@"Failed to create writable database file with message '%@'.",   [error localizedDescription]);
                }
                NSLog(@"Database didn't exist in %@, copying it from %@", dbname, databasePathFromApp);
            } else if ([[[fileManager attributesOfItemAtPath:databasePathFromApp error:NULL] fileModificationDate] compare:[[fileManager attributesOfItemAtPath:dbname error:NULL] fileModificationDate]] == NSOrderedDescending) {
                [fileManager removeItemAtPath:dbname error:NULL];
                BOOL success = [fileManager copyItemAtPath:databasePathFromApp toPath:dbname error:&error];
                if (!success) {
                    NSLog(@"Failed to create writable database file with message '%@'.",   [error localizedDescription]);
                }
                NSLog(@"Database in app was newer, copying it from %@", databasePathFromApp);
                [[NSURL fileURLWithPath:dbname] setResourceValue: [NSNumber numberWithBool: YES]
                                              forKey: NSURLIsExcludedFromBackupKey error: NULL];
            }
            const char *name = [dbname UTF8String];
            // NSLog(@"using db name: %@", dbname);
            sqlite3 *db;

            if (sqlite3_open(name, &db) != SQLITE_OK) {
                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Unable to open DB"];
                return;
            }
            else {
                // Extra for SQLCipher:
                // const char *key = [[options objectForKey:@"key"] UTF8String];
                // if(key != NULL) sqlite3_key(db, key, strlen(key));

                // Attempt to read the SQLite master table (test for SQLCipher version):
                if(sqlite3_exec(db, (const char*)"SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) == SQLITE_OK) {
                    dbPointer = [NSValue valueWithPointer:db];
                    [openDBs setObject: dbPointer forKey: dbname];
                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"Database opened"];
                } else {
                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Unable to encrypt DB"];
                }
            }
        }
    }

    if (sqlite3_threadsafe()) {
        NSLog(@"Good news: SQLite is thread safe!");
    }
    else {
        NSLog(@"Warning: SQLite is not thread safe.");
    }

    [self.commandDelegate sendPluginResult:pluginResult callbackId: command.callbackId];
}

现在,如果您确保已将数据库添加到项目的“资源”部分(并且还将它们添加到目标的“构建阶段”部分中的“复制捆绑资源”),则将从{{1}复制数据库必要时到Resources。这将返回Documents目录中可写数据库的句柄。

答案 1 :(得分:1)

我修改了http://gauravstomar.blogspot.com/2011/08/prepopulate-sqlite-in-phonegap.html中的代码,修改了最后一个代码,添加了一个检查sqlite db是否已经存在。

void copy(String file, String folder) throws IOException {
    File CheckDirectory;
    CheckDirectory = new File(folder);
    if (!CheckDirectory.exists())
    { 
        CheckDirectory.mkdir();
    }

    File f = new File(folder+file);
    if(!f.exists()) {       
    InputStream in = getApplicationContext().getAssets().open(file);
    OutputStream out = new FileOutputStream(folder+file);

    // Transfer bytes from in to out
    byte[] buf = new byte[1024];
    int len; while ((len = in.read(buf)) > 0) out.write(buf, 0, len);
    in.close(); out.close();
    }
}

答案 2 :(得分:0)

我在这个问题上工作了很长时间 - 问题是你要导入一个预先填充的数据库 - 这里没有很多简单的解决方案。我找到了最好的 - 目前只是唯一的解决方案是LiteHelpers CORDOVA-SQLITE-EXT(https://github.com/litehelpers/cordova-sqlite-ext

我已将此添加到我的应用中并且运行良好。我不得不从PhoneGap切换 - 并使用CORDOVA - 但它对我有用。