You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native使用expo-sqlite在iOS无法打开预存数据库求助

Expo SQLite 预存数据库 iOS 加载失败问题解决

问题场景

使用expo-sqlite加载预存的products.db数据库,Android端运行正常,但iOS端出现两类错误:

场景1:使用SQLiteProvider时的错误

代码:

return (
    <>
        <SQLiteProvider databaseName="@/data/products.db" assetSource={{ assetId: require('@/data/products.db') }}>
            <ResultRenderer profile={profile} />
            <Text>{buildSQLquery(profile)}</Text>
        </SQLiteProvider>
    </>
);

iOS报错:

ERROR  Error: The file “ExponentAsset-171a7c1e81bf6393675b790dec0140a7.db” doesn’t exist.
...(错误栈省略)

场景2:使用openDatabaseSync时的错误

代码:

const db = SQLite.openDatabaseSync("@/data/products.db", {});
const result = db.getAllSync("SELECT * from products")
console.log(result);

iOS报错:

ERROR  Error: FunctionCallException: Calling the 'initSync' function has failed (at ExpoModulesCore/SyncFunctionDefinition.swift:87)
→ Caused by: ArgumentCastException: The 1st argument cannot be cast to type SharedObject<NativeDatabase> (at ExpoModulesCore/JavaScriptUtils.swift:61)
→ Caused by: NativeSharedObjectNotFoundException: Unable to find the native shared object associated with given JavaScript object (at ExpoModulesCore/DynamicSharedObjectType.swift:58)
...(错误栈省略)

解决方法

1. 错误原因说明

  • ExponentAsset-xxx.db是Expo处理资源时生成的哈希命名文件,iOS沙盒机制不允许直接访问项目资产目录下的文件,必须先将数据库复制到可写的沙盒路径中。
  • openDatabaseSync的错误是因为传入的路径无效,无法找到对应的本地数据库实例。

2. 复制数据库到可访问沙盒路径

通过expo-asset和expo-file-system将预存数据库复制到iOS可读写的沙盒目录:

import { Asset } from 'expo-asset';
import * as FileSystem from 'expo-file-system';

async function getValidDatabasePath() {
  // 获取数据库资产实例
  const dbAsset = Asset.fromModule(require('@/data/products.db'));
  // 下载资产到本地临时路径
  await dbAsset.downloadAsync();
  // 定义沙盒中的目标存储路径
  const targetDbPath = `${FileSystem.documentDirectory}products.db`;
  // 检查目标路径是否已存在数据库,避免重复复制
  const fileInfo = await FileSystem.getInfoAsync(targetDbPath);
  
  if (!fileInfo.exists) {
    await FileSystem.copyAsync({
      from: dbAsset.localUri!,
      to: targetDbPath,
    });
  }
  
  return targetDbPath;
}

3. 修复SQLiteProvider用法

结合React Suspense处理异步路径获取,传入有效沙盒路径:

import React from 'react';
import { SQLiteProvider } from 'expo-sqlite';

function AppDatabaseProvider({ children }) {
  // React.use 用于在组件中处理异步逻辑,需包裹在Suspense中
  const dbPath = React.use(getValidDatabasePath());
  
  return (
    <SQLiteProvider databaseName={dbPath}>
      {children}
    </SQLiteProvider>
  );
}

// 调用时用Suspense包裹加载状态
function App() {
  return (
    <React.Suspense fallback={<Text>Loading database...</Text>}>
      <AppDatabaseProvider>
        <ResultRenderer profile={profile} />
        <Text>{buildSQLquery(profile)}</Text>
      </AppDatabaseProvider>
    </React.Suspense>
  );
}

4. 修复openDatabaseSync用法

确保数据库复制完成后,传入有效沙盒路径调用同步方法:

import * as SQLite from 'expo-sqlite';

async function queryDatabase() {
  const dbPath = await getValidDatabasePath();
  const db = SQLite.openDatabaseSync(dbPath);
  const result = db.getAllSync("SELECT * from products");
  console.log(result);
}

// 在组件生命周期中触发查询
useEffect(() => {
  queryDatabase();
}, []);

5. 资产打包配置

在app.json中声明数据库资产,确保Expo正确打包:

{
  "expo": {
    "assets": [
      "./data/products.db" // 替换为你的数据库实际路径
    ]
  }
}

内容的提问来源于stack exchange,提问作者apioltk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 05:39:54