Expo中预填充SQLite数据库连接异常问题排查
问题诊断与解决方案
你的问题核心出在Android平台的路径处理、Asset资源预加载逻辑缺失,以及缺少数据库存在性检查这几个方面,以下是针对性的修正方案:
1. 修复SQLite目录路径的斜杠问题
你代码中创建目录的写法${FileSystem.documentDirectory}SQLite存在隐患:FileSystem.documentDirectory在Android平台结尾自带斜杠(例如/data/user/0/com.yourapp/files/),拼接后会变成/data/user/0/com.yourapp/filesSQLite——这是无效路径,直接导致目录创建失败、数据库无法复制。
推荐使用FileSystem.join统一处理路径,避免斜杠问题:
import * as FileSystem from 'expo-file-system'; const dbDir = FileSystem.join(FileSystem.documentDirectory, 'SQLite'); const dbPath = FileSystem.join(dbDir, 'db_name.db');
2. 补充Asset资源预加载步骤
Asset.fromModule(require('./assets/db_name.db'))仅创建了Asset对象,但Android平台需要先调用await dbAsset.downloadAsync()确保资源已加载到本地,否则直接使用dbAsset.uri可能指向未就绪的资源地址,导致复制失败。
3. 增加数据库存在性检查
每次启动都重复复制数据库,不仅会产生冗余操作,还可能因Android平台文件已存在而触发报错。先检查目标路径是否已有数据库,存在则直接打开即可。
修正后的完整copyDatabase函数
import * as FileSystem from 'expo-file-system'; import * as Asset from 'expo-asset'; import * as SQLite from 'expo-sqlite'; const dbDir = FileSystem.join(FileSystem.documentDirectory, 'SQLite'); const dbPath = FileSystem.join(dbDir, 'db_name.db'); const copyDatabase = async () => { // 检查数据库是否已存在 const fileInfo = await FileSystem.getInfoAsync(dbPath); if (fileInfo.exists) { console.log('数据库已存在,直接打开'); return SQLite.openDatabase('db_name.db'); } // 创建SQLite目录 await FileSystem.makeDirectoryAsync(dbDir, { intermediates: true }); // 预加载Asset资源 const dbAsset = Asset.fromModule(require('./assets/db_name.db')); await dbAsset.downloadAsync(); // Android平台必须的预加载步骤 // 复制数据库文件 await FileSystem.copyAsync({ from: dbAsset.localUri || dbAsset.uri, // 兼容Android/iOS的URI格式 to: dbPath, }); console.log('数据库复制完成,路径:', dbPath); return SQLite.openDatabase('db_name.db'); };
4. EAS构建额外配置
- 确保
app.json中配置了资源打包规则,让EAS构建时正确包含db文件:
{ "expo": { "assetBundlePatterns": [ "assets/**/*" ] } }
- 若使用旧版本
expo-sqlite,需在app.json中添加文件访问权限:
{ "expo": { "android": { "permissions": ["READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"] } } }
5. 修正组件内调用时机
不要在App组件开头同步调用异步函数copyDatabase(),应使用useEffect在组件挂载时执行,避免阻塞渲染:
import { useState, useEffect } from 'react'; import { Text } from 'react-native'; export default function App() { const [db, setDb] = useState(null); useEffect(() => { const initDb = async () => { const database = await copyDatabase(); setDb(database); }; initDb(); }, []); // 等待数据库初始化完成后再渲染业务组件 if (!db) { return <Text>加载中...</Text>; } return ( // 你的业务组件内容 ); }
内容的提问来源于stack exchange,提问作者FrankyBravo
相关产品推荐
相关产品推荐

