2

我想将预填充的 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。有趣的是,当我在模拟器中进行新的运行时,会使用相同的数据库。

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

完成加载:file:///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 Simulator/5.0/Applications/33553FCA-3FFA-4BBB-9986-110721148F85/Documents

2013-07-09 18:39:14.977 AppName[49796:c07] 使用数据库名称:/Users/usernam/Library/Application Support/iPhone Simulator/5.0/Applications/33553FCA-3FFA-4BBB-9986-110721148F85/Documents/dbname 。D b

我使用电话间隙 2.5.0

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

在这个平台上也有人问过类似的问题,但还没有答案:

使用预先存在的数据库创建 PhoneGap iOS 应用程序

如何在 PhoneGap / Cordova 2.0 中使用预填充的 SQLite 数据库?

4

3 回答 3

3

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

如果您希望 SQLitePlugin 从资源部分中的现有 SQLite DB 填充数据库,则需要做一些工作才能到达那里。这就是我所做的:(替换中的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];
}

现在,如果您确保已将数据库添加到项目的 Resources 部分(并且还将它们添加到目标的 Build Phases 部分的“Copy Bundle Resources”),则数据库将在必要时从Resourcesto复制Documents。这将返回 Documents 目录中可写数据库的句柄。

于 2013-08-14T00:40:52.073 回答
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();
    }
}
于 2013-08-31T00:08:19.380 回答
0

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

我已将此添加到我的应用程序中,并且运行良好。虽然我不得不放弃 PhoneGap - 并使用 CORDOVA - 但它对我有用。

于 2017-04-20T16:33:50.687 回答