基于 react-native-sqlite-storage 的 OpenHarmony 适配版,SQLite 数据库存储
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 6 天前 | ||
| 5 个月前 | ||
| 6 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 6 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 10 年前 | ||
| 1 个月前 | ||
| 3 个月前 | ||
| 1 年前 | ||
| 18 天前 | ||
| 18 天前 | ||
| 3 个月前 | ||
| 6 天前 | ||
| 1 年前 |
模板版本:v0.4.2
react-native-sqlite-storage
本项目基于 react-native-sqlite-storage 开发。
该第三方库的仓库已迁移至 Gitcode,且支持直接从 npm 下载,新的包名为:@react-native-ohos/react-native-sqlite-storage 版本所属关系如下:
| 三方库名称 | 三方库版本(npm地址) | 发布信息 | 支持RN版本 | Autolink | 编译API版本 | 社区基线版本 | 源码地址 |
|---|---|---|---|---|---|---|---|
| @react-native-ohos/react-native-sqlite-storage | ~ 6.1.2 | Gitcode Releases | 0.77 | 否 | API12+ | 6.0.1 | br_rnoh0.77 |
简介
一个基于 SQLite 的 React Native 本地数据库三方库,提供数据库创建/打开、SQL 查询与更新、事务处理等常用能力,便于在应用内持久化结构化数据。
下载安装
进入到工程目录并输入以下命令:
npm
npm install @react-native-ohos/react-native-sqlite-storage
yarn
yarn add @react-native-ohos/react-native-sqlite-storage
下面的代码展示了这个库的基本使用场景:
使用时 import 的库名不变。
import React, { Component } from 'react';
import { View, Text, TouchableOpacity, ScrollView, StyleSheet } from 'react-native';
import SQLite from 'react-native-sqlite-storage';
// 全局基础配置
SQLite.DEBUG(true);
SQLite.enablePromise(false);
const db_name = 'Test.db';
const db_version = '1.0';
const db_displayname = 'SQLite Test Database';
const db_size = 200000;
let db;
class SQLiteDemo extends Component {
constructor(props) {
super(props);
this.state = {
progress: [],
};
}
updateProgress = (text) => {
this.setState((prevState) => ({
progress: [...prevState.progress, text],
}));
};
// 1. 打开/初始化数据库
loadDB = () => {
this.updateProgress('Opening database...');
db = SQLite.openDatabase(
db_name, db_version, db_displayname, db_size,
() => { this.updateProgress('Database OPENED successfully'); },
(err) => { this.updateProgress('Database OPEN Error: ' + err.message); }
);
};
// 2. 事务分发与写操作 (执行建表、表插入等)
populateDB = () => {
if (!db) return this.updateProgress('Error: Please Open DB first');
this.updateProgress('Populating database...');
db.transaction((tx) => {
tx.executeSql('DROP TABLE IF EXISTS Users;');
tx.executeSql(
'CREATE TABLE IF NOT EXISTS Users(id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(55))',
[],
() => this.updateProgress('Table created successfully'),
(err) => this.updateProgress('Table create failed: ' + err.message)
);
tx.executeSql('INSERT INTO Users (name) VALUES ("HarmonyOS");', []);
tx.executeSql('INSERT INTO Users (name) VALUES ("React Native");', []);
this.updateProgress('Insert queries executed');
});
};
// 3. 执行查询操作并解析结果集
queryData = () => {
if (!db) return this.updateProgress('Error: Please Open DB first');
this.updateProgress('Querying data...');
db.transaction((tx) => {
tx.executeSql(
'SELECT * FROM Users',
[],
(tx, results) => {
let len = results.rows.length;
this.updateProgress('Query completed, total rows: ' + len);
for (let i = 0; i < len; i++) {
let row = results.rows.item(i);
this.updateProgress('Record ' + i + ': ' + row.name);
}
},
(err) => this.updateProgress('Query error: ' + err.message)
);
});
};
// 4. 重置与清理操作 (关闭与删除)
closeDB = () => {
if (db) {
db.close(
() => {
this.updateProgress('Database CLOSED (connection released on API 12+, error reported on older versions)');
db = null;
},
(err) => this.updateProgress('Database CLOSE Error: ' + err.message)
);
} else {
this.updateProgress('Database is already closed');
}
};
deleteDB = () => {
this.updateProgress('Deleting database...');
this.closeDB();
SQLite.deleteDatabase(
db_name,
() => this.updateProgress('Database DELETED'),
(err) => this.updateProgress('Database DELETE Error: ' + err.message)
);
SQLite.deleteDatabase(
'test2.db',
() => this.updateProgress('test2.db DELETED'),
(err) => this.updateProgress('test2.db DELETE Error: ' + err.message)
);
}
// 5. 附加其他数据库
attachDB = () => {
if (db) {
this.updateProgress('Attaching test2.db...');
let dbMaster = SQLite.openDatabase('test2.db', db_version, db_displayname, db_size, () => {
dbMaster.attach(
db_name,
'aliasName',
() => this.updateProgress('Database Attached successfully'),
(err) => this.updateProgress('Attach ERROR: ' + err.message)
);
});
} else {
this.updateProgress('Error: Master DB not open');
}
}
render() {
return (
<View style={styles.container}>
<View style={styles.toolbar}>
<TouchableOpacity style={styles.btn} onPress={this.loadDB}><Text style={styles.btnText}>Open DB</Text></TouchableOpacity>
<TouchableOpacity style={styles.btn} onPress={this.populateDB}><Text style={styles.btnText}>Populate</Text></TouchableOpacity>
<TouchableOpacity style={styles.btn} onPress={this.queryData}><Text style={styles.btnText}>Query</Text></TouchableOpacity>
<TouchableOpacity style={styles.btn} onPress={this.attachDB}><Text style={styles.btnText}>Attach</Text></TouchableOpacity>
<TouchableOpacity style={styles.btnDanger} onPress={this.closeDB}><Text style={styles.btnText}>Close DB</Text></TouchableOpacity>
<TouchableOpacity style={styles.btnDanger} onPress={this.deleteDB}><Text style={styles.btnText}>Delete DB</Text></TouchableOpacity>
</View>
<ScrollView style={styles.logContainer}>
{this.state.progress.map((item, index) => (
<Text key={index} style={styles.logText}>{item}</Text>
))}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 10 },
toolbar: { flexDirection: 'row', flexWrap: 'wrap', marginBottom: 10 },
btn: { paddingHorizontal: 10, paddingVertical: 8, margin: 5, borderWidth: 1, borderColor: '#ccc' },
btnDanger: { paddingHorizontal: 10, paddingVertical: 8, margin: 5, borderWidth: 1, borderColor: '#ccc' },
btnText: { color: '#333', fontSize: 14 },
logContainer: { flex: 1, backgroundColor: '#f5f5f5', padding: 10, borderWidth: 1, borderColor: '#eee' },
logText: { color: '#333', fontSize: 13, marginBottom: 5 }
});
export default SQLiteDemo;
Link
| 是否支持autolink | RN框架版本 | |
|---|---|---|
| ~6.1.2 | 否 | 0.77 |
使用AutoLink的工程需要根据该文档配置,Autolink框架指导文档:https://gitcode.com/CPF-RN/ohos_react_native/blob/master/docs/zh-cn/Autolinking.md
如您使用的版本支持 Autolink,并且工程已接入 Autolink,可跳过ManualLink配置。
ManualLink: 此步骤为手动配置原生依赖项的指导
首先需要使用 DevEco Studio 打开项目里的 HarmonyOS 工程 harmony。
1. Overrides RN SDK
为了让工程依赖同一个版本的 RN SDK,需要在工程根目录的 oh-package.json5 添加 overrides 字段,指向工程需要使用的 RN SDK 版本。替换的版本既可以是一个具体的版本号,也可以是一个模糊版本,还可以是本地存在的 HAR 包或源码目录。
关于该字段的作用请阅读官方说明
{
"overrides": {
"@rnoh/react-native-openharmony": "file:../react_native_openharmony"
}
}
2.引入原生端代码
目前有两种方法:
- 通过 har 包引入(在 IDE 完善相关功能后该方法会被遗弃,目前首选此方法);
- 直接链接源码。
方法一:通过 har 包引入(推荐)
har 包位于三方库安装路径的 `harmony` 文件夹下。
打开 entry/oh-package.json5,添加以下依赖
"dependencies": {
"@rnoh/react-native-openharmony": "file:../react_native_openharmony",
"@react-native-ohos/react-native-sqlite-storage": "file:../../node_modules/@react-native-ohos/react-native-sqlite-storage/platforms/harmony/sqlite_storage.har"
}
点击右上角的 sync 按钮
或者在终端执行:
cd entry
ohpm install
方法二:直接链接源码
如需使用直接链接源码,请参考[直接链接源码说明](https://gitcode.com/CPF-RN/usage-docs/blob/master/zh-cn/link-source-code.md)
3. 配置 CMakeLists 和引入 SQLitePluginPackage
打开 entry/src/main/cpp/CMakeLists.txt,添加:
...
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
add_subdirectory("${RNOH_CPP_DIR}" ./rn)
# RNOH_END: manual_package_linking_1
add_subdirectory("../../../../sample_package/src/main/cpp" ./sample-package)
+ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-sqlite-storage/src/main/cpp" ./sqlite_storage)
# RNOH_END: manual_package_linking_1
add_library(rnoh_app SHARED
"./PackageProvider.cpp"
"${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)
# RNOH_BEGIN: manual_package_linking_2
target_link_libraries(rnoh_app PUBLIC rnoh_sample_package)
+ target_link_libraries(rnoh_app PUBLIC rnoh_sqlite_storage)
# RNOH_BEGIN: manual_package_linking_2
打开 entry/src/main/cpp/PackageProvider.cpp,添加:
#include "RNOH/PackageProvider.h"
+ #include "SqliteStoragePackage.h"
using namespace rnoh;
std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
return {
+ std::make_shared<SqliteStoragePackage>(ctx)
}
4. 在 ArkTs 侧引入 SQLitePluginPackage
打开 entry/src/main/ets/RNPackagesFactory.ts,添加:
...
+ import {SQLitePluginPackage} from '@react-native-ohos/react-native-sqlite-storage/ts';
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
return [
new SamplePackage(ctx),
+ new SQLitePluginPackage(ctx)
];
}
运行
点击右上角的 sync 按钮
或者在终端执行:
cd entry
ohpm install
然后编译、运行即可。
约束与限制
兼容性
本文档内容基于以下版本验证通过:
- RNOH: 0.77.18; SDK: HarmonyOS 6.0.0 Release SDK; IDE: DevEco Studio 6.0.0.858; ROM: 6.0.0.112;
平台差异说明
-
语法错误的 SQL 不报错:底层
relationalStore.querySql对语法错误的 SQL(如拼写错误的表名/列名、无效语句)不抛异常,而是返回 0 列空结果集并按成功处理(Android 的rawQuery会抛SQLiteException)。因此executeSql/transaction对这类 SQL 会正常 resolve(查询结果为空),事务也不会中止。由于"合法但无结果集"的语句(PRAGMA/DETACH 等)与语法错误在该层面不可区分,本库不做弥补。业务侧需自行保证 SQL 正确性,调试期可开启SQLite.DEBUG查看原生执行日志。 -
SQLCipher 加密不支持(
key参数被忽略):鸿蒙端基于@ohos.data.relationalStore实现,不内置 SQLCipher。openDatabase传入的key参数在鸿蒙端会被静默忽略,数据库以非加密(明文)方式落盘。启用 SQLCipher 需自行编译带加密的 SQLite 内核并绕过 relationalStore,属大型原生改造,超出三方库适配范围,因此明确标注"不支持"。(注:SQLCipher 本身是跨平台的 SQLite 加密扩展,并非 iOS 特有;但在本库范围内,Android 桥接层不读取key、从未支持加密,iOS 端key亦仅在自行编译 SQLCipher 内核并定义SQLCIPHER宏时才生效——上游默认安装下三端行为一致、均忽略key,真实差异仅存在于"iOS 自备 SQLCipher 内核"的迁移场景。)Warning
若原应用依赖 SQLCipher 加密(在本库范围内仅 iOS 自备加密内核场景可启用),迁移到鸿蒙后
key被忽略,加密将退化为明文,请勿假设数据仍受加密保护,数据保护请另行处理。鸿蒙relationalStore自带库级加密能力(encrypt/cryptoParam,AES_256_GCM/CBC),但算法非 SQLCipher、密文与 iOS/Android 的 SQLCipher 库文件不互通,且本库未接入该能力。
rawfile 资源放置路径
预填充数据库文件需放置在 entry/src/main/resources/rawfile/rdb/ 目录下。源码中使用 getRawFdSync('rdb/' + dbName) 读取此路径。
API
"Platform"列表示该属性在原三方库上支持的平台。
"HarmonyOS Support"列为 yes 表示 HarmonyOS 平台支持该属性;no 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。
| Name | Description | Type | Required | Platform | HarmonyOS Support |
|---|---|---|---|---|---|
| openDatabase | 打开或初始化, 参数createFromLocation设为1时,会从rawfile/rdb把现成 SQLite 数据库文件导入项目。readOnly选项在API 12+支持;key加密参数不支持(被静默忽略,数据库明文存储,见"平台差异说明") | SQLitePlugin | yes | All | partially(readOnly需API 12+) |
| transaction | SQL事务分发 | void | yes | All | yes |
| readTransaction | 只读事务 | void | yes | All | yes |
| executeSql | 在后台执行一批SQL语句,不阻塞当前线程或进程 | void | yes | All | yes |
| executeSqlBatch | 批量执行SQL语句 | void | yes | All | yes |
| sqlBatch | 批量执行SQL语句(Promise模式) | void | yes | All | yes |
| close | 关闭数据库连接,释放资源。API 12+真正关闭数据库并清理引用;API 11及以下close()调用失败,经error回调上报 | void | yes | All | yes |
| deleteDatabase | 删除数据库 | void | yes | All | yes |
| attach | 连接或关联外部数据库 | void | yes | All | yes |
| detachDatabase | 断开关联的外部数据库 | void | yes | All | yes |
| echoTest | 测试原生模块通信 | void | yes | All | yes |
| enablePromise | 启用/禁用Promise模式 | void | yes | All | yes |
| DEBUG | 开启/关闭调试模式 | void | yes | All | yes |
| sqliteFeatures | 获取SQLite特性 | void | yes | All | yes |
遗留问题
- BLOB 数据类型返回
Uint8Array而非 Base64 字符串,与上游不一致(平台 API 差异,不可修改) rowsAffected在 CREATE/DROP/INSERT 语句中硬编码为 1,与上游 SQLite 标准行为不一致(修改会引起非兼容变更)
其它
无
目录结构
/rntpc_react-native-sqlite-storage # 项目根目录
├── harmony # 鸿蒙适配代码
│ ├── sqlite_storage.har # har 包
│ └── sqlite_storage # 鸿蒙适配核心代码
│ ├── index.ets # 鸿蒙适配代码入口
│ ├── ts.ets # Package / TurboModule 导出
│ ├── src/main/ets
│ │ ├── SQLitePluginPackage.ets # RNOH Package 注册
│ │ ├── SQLitePluginTurboModule.ts # 实现 TurboModule 接口
│ │ ├── CommonConstants.ts # 常量
│ │ ├── Logger.ts # 日志
│ │ └── generated/ # codegen 生成代码
│ └── src/main/cpp
│ ├── SqliteStoragePackage.h # C++ Package
│ ├── CMakeLists.txt
│ └── generated/ # codegen 生成代码
├── lib
│ └── sqlite.core.js # SQLite JS 核心实现
├── sqlite.js # RN 入口(Promise/Callback 运行时封装)
├── NativeSQLitePlugin.ts # TurboModule 类型 / Spec
├── README.md # 中文安装使用方法
└── README.OpenSource # 开源说明
贡献代码
使用过程中发现任何问题都可以提交 Issue,当然,也非常欢迎提交 PR 。
开源协议
本项目基于 The MIT License (MIT) ,请自由地享受和参与开源。