我想将预先填充的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?
答案 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 - 但它对我有用。