- Published on
react-native-sqlite-storage如何使用预置数据库
- Authors
- Name
- 万码皆空
官方README.md
中已经有详细的说明,见Pre-populated SQLite database import from application bundle and sandbox。
按照作者的说法,需要创建一个叫做www
的目录,并且强调必须是www
才可以。
之后呢,就是添加到ios和android工程。按着说明都弄好了之后,作者给出了使用的示例代码如下:
1.SQLite.openDatabase({name : "testDB", createFromLocation : 1}, okCallback,errorCallback);
// default - if your folder is called www and data file is named the same as the dbName - testDB in this example
2.SQLite.openDatabase({name : "testDB", createFromLocation : "~data/mydbfile.sqlite"}, okCallback,errorCallback);
// if your folder is called data rather than www or your filename does not match the name of the db
3.SQLite.openDatabase({name : "testDB", createFromLocation : "/data/mydbfile.sqlite"}, okCallback,errorCallback);
// if your folder is not in app bundle but in app sandbox i.e. downloaded from some remote location.
我们先看第一行代码,作者注释说如果我们创建的文件夹是www
,并且数据库名与文件名相同,就可以使用这种方式。这里没有什么问题。
我们再看第二行代码,作者注释说如果我们创建的文件夹是data
而不是www
,或者我们的数据库名和文件名不一致,就是用这种调用方式。
这样问题就来了,一开始作者说文件夹必须要以www
命名,这里又表示可以使用data
来命名,到底是怎么回事?另外,为什么要用www
命名?是ios的限制还是android的限制?~
又是什么鬼?为什么加这个符号?
虽然README.md
里文字不少,可是关于这部分说的含含糊糊,另外我对必须使用www
这个名字也很不满意。于是特意去查了下,发现ios和android下并没有这种限制,看来是作者自己加的。那只好去看源码了。
打开ios的相关源码node_modules/react-native-sqlite-storage/platforms/ios/SQLite.m
,以下是代码片段:
NSString *assetFilePath = options[@"assetFilename"];
if (assetFilePath != NULL && assetFilePath.length > 0) {
@try {
if ([assetFilePath isEqualToString:@"1"]){
NSString *targetBundleDirPath = [[NSBundle mainBundle] resourcePath];
targetBundleDirPath = [targetBundleDirPath stringByAppendingPathComponent: @"www"];
assetFilePath = [targetBundleDirPath stringByAppendingPathComponent: dbfilename];
RCTLog(@"Built path to pre-populated DB asset from app bundle www subdirectory: %@",assetFilePath);
} else if ([assetFilePath hasPrefix:@"~"]) {
assetFilePath = [assetFilePath substringFromIndex:1];
NSString *targetBundleDirPath = [[NSBundle mainBundle] resourcePath];
assetFilePath = [targetBundleDirPath stringByAppendingPathComponent: assetFilePath];
RCTLog(@"Built path to pre-populated DB asset from app bundle subdirectory: %@",assetFilePath);
} else {
NSURL * documentsDirUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
assetFilePath = [documentsDirUrl.path stringByAppendingPathComponent:assetFilePath];
RCTLog(@"Built path to pre-populated DB asset from app sandbox documents directory: %@",assetFilePath);
}
} @catch(NSException *ex){
RCTLog(@"Error building path for pre-populated DB asset %@",ex.reason);
}
}
我们看到,果然是作者搞的鬼:
- 如果
createFromLocation
值是1
,则使用name
的值作为数据库的名字,并且前面加上www
构建出数据库文件路径。 - 如果
createFromLocation
的值是以~
开头,则使用~
以后的值拼接出数据库的文件路径。
android的代码在node_modules/react-native-sqlite-storage/platforms/android-native/src/main/java/io/liteglue/SQLitePlugin.java
中,实现逻辑类似,有兴趣的自己看下。
作者这样的实现,我觉得是不够有诚意的,完全没有必要使用www
和~
。简单点,增加一个调用参数来标识是否使用包内数据库就可以了,也方便使用的人理解。
说归说,还是得用,不过明白了这里面的逻辑也能安心了。