Expo Go开发环境数据库可完整加载,TestFlight仅加载243字节求助
Expo生产构建(TestFlight)中SQLite数据库仅加载243字节问题排查与解决
问题背景
开发的Expo应用依赖assets文件夹内4.8MB的预加载数据库worldEnglishBible.db,通过expo-file-system将数据库复制到可访问目录供expo-sqlite使用。Expo Go测试时数据库可完整加载,但生产构建上传至TestFlight后,仅能加载243字节的不完整文件,导致无法正常访问数据。
现有实现代码
数据库加载逻辑
import * as FileSystem from "expo-file-system"; import { Asset } from "expo-asset"; const downloadWEB = async (setDatabaseSize, setConsoleText) => { const callback = (downloadProgress) => { console.log(downloadProgress.totalBytesWritten); setDatabaseSize(downloadProgress.totalBytesWritten); }; const downloadResumableWEB = FileSystem.createDownloadResumable( Asset.fromModule(require("../assets/worldEnglishBible.db")).uri, FileSystem.documentDirectory + "SQLite/worldEnglishBible.db", {}, callback ); try { await FileSystem.makeDirectoryAsync( FileSystem.documentDirectory + "SQLite" ); const { uri } = await downloadResumableWEB.downloadAsync(); console.log("Finished downloading to ", uri); setConsoleText("Finished downloading to " + uri); } catch (error) { console.log(error.message); setConsoleText(error.message); } }; const deleteDatabaseSQL = async (setDatabaseSize, setConsoleText) => { try { await FileSystem.deleteAsync(FileSystem.documentDirectory + "SQLite"); console.log("database deleted"); setConsoleText("database deleted"); setDatabaseSize(0); } catch (error) { console.log(error.message); setConsoleText(error.message); } }; export { downloadWEB, deleteDatabaseSQL };
Metro配置(metro.config.js)
const { getDefaultConfig } = require("expo/metro-config"); const config = getDefaultConfig(__dirname); config.resolver.assetExts.push( // Adds support for `.db` files for SQLite databases "db" ); module.exports = config;
解决方案
方案1:确保Asset预加载完成
生产构建中,Asset.fromModule返回的URI可能指向未完全就绪的资源,导致下载到不完整文件。需先调用Asset.loadAsync确保资源加载完成,同时优化目录创建逻辑避免重复报错:
import * as FileSystem from "expo-file-system"; import { Asset } from "expo-asset"; const downloadWEB = async (setDatabaseSize, setConsoleText) => { const callback = (downloadProgress) => { console.log(downloadProgress.totalBytesWritten); setDatabaseSize(downloadProgress.totalBytesWritten); }; try { // 预加载Asset,确保资源可用 const asset = Asset.fromModule(require("../assets/worldEnglishBible.db")); if (!asset.downloaded) { await asset.loadAsync(); } // 创建目录时忽略已存在的情况 await FileSystem.makeDirectoryAsync( FileSystem.documentDirectory + "SQLite", { exists: 'ignore' } ); const downloadResumableWEB = FileSystem.createDownloadResumable( asset.uri, FileSystem.documentDirectory + "SQLite/worldEnglishBible.db", {}, callback ); const { uri } = await downloadResumableWEB.downloadAsync(); console.log("Finished downloading to ", uri); setConsoleText("Finished downloading to " + uri); // 可选:验证文件完整性 const fileInfo = await FileSystem.getInfoAsync(uri); console.log("下载后文件大小:", fileInfo.size); if (fileInfo.size < 4 * 1024 * 1024) { setConsoleText("数据库文件可能不完整"); } } catch (error) { console.log(error.message); setConsoleText(error.message); } };
方案2:改用FileSystem.copyAsync替代下载逻辑
Asset在生产构建中是打包到应用内的本地资源,直接复制比下载更可靠,避免下载逻辑带来的潜在问题:
import * as FileSystem from "expo-file-system"; import { Asset } from "expo-asset"; const downloadWEB = async (setDatabaseSize, setConsoleText) => { try { const asset = Asset.fromModule(require("../assets/worldEnglishBible.db")); if (!asset.downloaded) { await asset.loadAsync(); } const targetDir = FileSystem.documentDirectory + "SQLite"; const targetPath = `${targetDir}/worldEnglishBible.db`; // 检查目标文件是否已存在且完整,避免重复操作 const targetInfo = await FileSystem.getInfoAsync(targetPath); if (targetInfo.exists && targetInfo.size > 4 * 1024 * 1024) { setConsoleText("数据库已存在且完整"); setDatabaseSize(targetInfo.size); return; } await FileSystem.makeDirectoryAsync(targetDir, { exists: 'ignore' }); // 直接复制Asset到目标路径 await FileSystem.copyAsync({ from: asset.uri, to: targetPath, }); const finalInfo = await FileSystem.getInfoAsync(targetPath); console.log("复制后数据库大小:", finalInfo.size); setDatabaseSize(finalInfo.size); setConsoleText("数据库已复制到:" + targetPath); } catch (error) { console.log(error.message); setConsoleText(error.message); } };
方案3:清理构建缓存确保资源正确打包
- 运行
expo r -c清除Metro开发缓存 - 构建生产包时执行
expo build:ios --clear-cache,确保db资源被正确打包进应用
问题根源
- Expo Go与生产构建的资源处理差异:Expo Go实时加载资源,而生产构建将资源打包到应用包内,未预加载的Asset可能返回临时占位路径,导致下载到不完整文件。
- 目录创建逻辑缺陷:原代码未处理目录已存在的情况,可能触发隐式错误影响后续操作。
- 下载逻辑不适用于本地资源:
createDownloadResumable更适合远程资源下载,处理本地Asset时不如直接复制可靠。
内容的提问来源于stack exchange,提问作者Sam Sweetin
相关产品推荐
相关产品推荐

