【Expo小记】修复:使用预先准备的SqliteDB,Android真机与Expo Go正常,iOS模拟器与真机无法找到该数据库的问题:File not database.

这几天写了一个粤小词词典应用,打算做个离线版的,于是使用了自己的sqliteDB文件。

Android上一切正常,Expo Go调试正常,一到eas build iOS就文件不是数据库文件。

如果直接解析DB后缀的是没法使用的,更改一下Metro的配置,支持db文件,也可以项目使用其他的。

`

1
2
3
4
5
6
7
const { getDefaultConfig } = require('expo/metro-config');

const defaultConfig = getDefaultConfig(__dirname);

defaultConfig.resolver.assetExts.push('db');

module.exports = defaultConfig;

改完后,执行清理缓存的启动:

expo start -c

然后使用以下写法:

`

1
2
3
4
5
6
7
8
9
10
11
async function openDatabase(pathToDatabaseFile: string): Promise<SQLite.WebSQLDatabase> {
if (!(await FileSystem.getInfoAsync(FileSystem.documentDirectory + 'SQLite')).exists) {
await FileSystem.makeDirectoryAsync(FileSystem.documentDirectory + 'SQLite');
}
await FileSystem.downloadAsync(
Asset.fromModule(require(pathToDatabaseFile)).uri,
FileSystem.documentDirectory + 'SQLite/myDatabaseName.db'
);
return SQLite.openDatabase('myDatabaseName.db');
}

可以看到从资源文件里面解析出来db后,下载到本机(这里说一下:使用expo托管流的,会将资源文件托管到亚马逊的CDN上,在应用首次启动会下载下来)。

回到iOS真机上来,我使用模拟器,打开了模拟器的本地存储,发现实际上是有数据库文件的,但是似乎大小不正常,我的DB有3m,但是模拟器上下载下来的只有200kb,应该是下载的时候损坏了。所以导致不是一个db文件。于是我换了一下写法,使用了copy函数,从资源文件复制到本机,结果打包后还是不行,直接没有复制。

后来去官方论坛查看,非常多的人遇到自带db文件无法使用的问题,并且几乎没有官方人员解答,都是最后被关闭话题。其中一个是:使用hook,来监听文件下载完成后执行其他操作。这样可以避免下载问题导致的文件损坏,鉴于下载问题,我修改了一些逻辑,改成了不托管db文件,然后启动项目后从自带资源文件里复制。

`

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
useEffect(() => {
async function loadResourcesAndDataAsync() {
try {
SplashScreen.preventAutoHideAsync().catch((e) => console.log(e));
const getDatabase = async (databaseAsset: Asset) => {
try {
if (!(await FileSystem.getInfoAsync(sqlDir)).exists) {
await FileSystem.makeDirectoryAsync(sqlDir);
}
await FileSystem.copyAsync({
//@ts-ignore
from: databaseAsset.localUri,
to: sqlDir + '/' + databaseName,
});

return SQLite.openDatabase(databaseName);
} catch (err) { /* Handle error */
}
};

if (assets && assets[0] && !assetsError) {
const databaseAsset = assets[0];
// @ts-ignore
ZenStore.db = await getDatabase(databaseAsset);
}

} catch (e) {
// We might want to provide this error information to an error reporting service
console.warn(e);
alert(e.message);
console.error(e)
} finally {
setLoadingComplete(true);
SplashScreen.hideAsync();
}
}

loadResourcesAndDataAsync();
}, [assets]);

修改托管配置:app.json ,将db排除在外,因为我只托管图片所以将默认的*换成下面的就好了。

`

1
2
3
"assetBundlePatterns": [
"assets/images/*"
],

希望能帮助到遇到这个问题的小伙伴。

另外 粤小词语iOS上线啦:粤小词 Apple Store