HarmonyOS 鸿蒙Next中服务卡片与Flutter应用共享SQLite数据库的实践探索
在鸿蒙OS的开发中,服务卡片作为一种轻量级的信息展示方式,广受开发者欢迎。同时,Flutter作为一种跨平台的应用开发框架,也越来越多地被应用于鸿蒙OS的应用开发中。今天,我们就来探讨一下如何在鸿蒙OS中,实现服务卡片与使用Flutter技术开发的应用共享同一个SQLite数据库。
开发准备 在开始之前,请确保您的开发环境满足以下条件:
已安装鸿蒙OS的开发工具DevEco Studio。 已安装Flutter开发环境。(https://gitee.com/openharmony-sig/flutter_flutter) 熟悉Dart语言和Flutter框架。 创建Flutter应用 请参考 https://gitee.com/openharmony-sig/flutter_flutter 构建步骤章节,创建一个Flutter应用。
用DevEco Studio打开该应用,并确保应用已经运行在模拟器或真机上。 直接在命令行 flutter run --debug -d 运行应用。 确保项目可以运行在手机中。
实现步骤
- 创建SQLite数据库 在Flutter应用中,我们可以使用sqflite插件来创建和管理SQLite数据库。首先,我们需要在pubspec.yaml文件中添加sqflite插件的依赖:
sqflite:
git:
url: "https://gitee.com/openharmony-sig/flutter_sqflite.git"
path: "sqflite"
然后,在Flutter应用的主文件中,我们可以创建一个SQLite数据库:
import 'package:get/get.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart' as path;
import 'logger_service.dart';
class DbService extends GetxService {
static DbService get to => Get.find();
late Database database;
Future<DbService> init() async {
var databasesPath = await getDatabasesPath();
String dbPath = path.join(databasesPath, "database.db");
database = await openDatabase(
dbPath,
version: 7,
onCreate: (Database db, int version) async {
await _createTables(db);
LoggerService.to.logger.d('onCreate dbPath: $dbPath ');
},
onOpen: (Database db) async {
LoggerService.to.logger.d('onOpen dbPath: $dbPath ');
},
onUpgrade: (Database db, int oldVersion, int newVersion) async {
LoggerService.to.logger.d(
'onUpgrade dbPath: $dbPath oldVersion: $oldVersion newVersion: $newVersion');
},
);
return this;
}
Future<void> _createTables(Database db) async {
LoggerService.to.logger.d('createTables');
try {
await db.execute('''
CREATE TABLE IF NOT EXISTS formTable (
formId TEXT,
formName TEXT,
formDimension INTEGER,
formConf TEXT
);
''');
LoggerService.to.logger.d('formTable created successfully');
await db.execute('''
CREATE TABLE IF NOT EXISTS propsTable (
props TEXT
);
''');
LoggerService.to.logger.d('propsTable created successfully');
} catch (e) {
LoggerService.to.logger.e('Error creating tables: $e');
rethrow;
}
}
Future<List<String>> getAllTables() async {
final List<Map<String, dynamic>> tables = await database.rawQuery(
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';");
return tables.map((table) => table['name'] as String).toList();
}
Future<List<Map<String, dynamic>>> getAllFormsData() async {
try {
final List<Map<String, dynamic>> result =
await database.query('formTable');
LoggerService.to.logger
.d('Retrieved ${result.length} forms from formTable');
return result;
} catch (e) {
LoggerService.to.logger.e('Error retrieving forms data: $e');
return [];
}
}
}
- 创建服务卡片 基于:DevEco Studio Build Version: 5.0.3.900
步骤如下:
在DevEco Studio中,打开你的项目 在entry文件点击右键,选择New -> Service Widget -> Dynamic Widget 在弹出的对话框中,输入Service Widget的名称 点击OK,DevEco Studio会自动生成Service Widget的代码文件 3. 在鸿蒙项目中添加数据库操作 【定义数据库配置】 新建 Constants.ets 文件,定义数据库的配置和表结构。该文件包含数据库的配置以及创建表的 SQL 语句。
import relationalStore from '@ohos.data.relationalStore';
export interface WidgetTable {
tableName: string;
sqlCreate: string;
columns: string[];
}
export default class Constants {
static readonly STORE_CONFIG: relationalStore.StoreConfig = {
name: "database.db",
securityLevel: relationalStore.SecurityLevel.S1,
};
static readonly FORM_TABLE: WidgetTable = {
tableName: 'formTable',
sqlCreate: `
CREATE TABLE IF NOT EXISTS formTable (
formId TEXT,
formName TEXT,
formDimension INTEGER,
formConf TEXT
);
`,
columns: ['formId', 'formName', 'formDimension', 'formConf']
};
static readonly PROPS_TABLE: WidgetTable = {
tableName: 'propsTable',
sqlCreate: `
CREATE TABLE IF NOT EXISTS propsTable (
props TEXT
);
`,
columns: ['props']
};
}
【创建数据库助手类】 新建 Rdb.ets 文件,创建一个助手类来管理数据库操作,如插入、删除、更新和查询。该类使用 relationalStore 模块与数据库进行交互。
import relationalStore from '@ohos.data.relationalStore';
import { hilog } from '@kit.PerformanceAnalysisKit';
import Constants from '../common/Constants';
export default class Rdb {
private rdbStore: relationalStore.RdbStore | null = null;
private tableName: string;
private sqlCreateTable: string;
private columns: Array<string>;
constructor(tableName: string, sqlCreateTable: string, columns: Array<string>) {
this.tableName = tableName;
this.sqlCreateTable = sqlCreateTable;
this.columns = columns;
}
getRdbStoreWithContext(context: Context, callback: Function = () => {}) {
if (this.rdbStore !== null) {
hilog.debug(1, 'XS', `[RDB] The rdbStore exists.`);
callback();
return;
}
relationalStore.getRdbStore(context, Constants.STORE_CONFIG, (err, rdb) => {
if (err) {
hilog.debug(1, 'XS', `[RDB] gerRdbStore() failed, err: ${err}`);
return;
}
this.rdbStore = rdb;
hilog.debug(1, 'XS', `[RDB] getRdbStore finished.`);
callback();
});
}
insertData(data: relationalStore.ValuesBucket, callback: Function = () => {}) {
if (this.rdbStore) {
this.rdbStore.insert(this.tableName, data, (err, ret) => {
if (err) {
hilog.debug(1, 'XS', `[RDB] insertData() failed, err: ${err}`);
callback(false);
return;
}
hilog.debug(1, 'XS', `[RDB] insertData() finished: ${ret}`);
callback(ret);
});
}
}
// 其他操作方法(删除、更新、查询)...
}
【实现特定表的操作】 新建 FormTable.ets 文件,实现特定表的操作。该文件提供了插入、删除、更新和查询 formTable 数据的方法。
import relationalStore from '@ohos.data.relationalStore';
import Constants from '../../common/Constants';
import FormData from '../../model/FormData';
import Rdb from '../Rdb';
export default class FormTable {
private formTable = new Rdb(Constants.FORM_TABLE.tableName, Constants.FORM_TABLE.sqlCreate, Constants.FORM_TABLE.columns);
getRdbStore(context: Context, callback: Function = () => {}) {
this.formTable.getRdbStoreWithContext(context, callback);
}
insertData(form: FormData, callback: Function) {
this.queryFormById(form.formId).then((existingForm) => {
if (existingForm) {
callback(true, 0);
return;
}
const valueBucket: relationalStore.ValuesBucket = generateBucket(form);
this.formTable.insertData(valueBucket, (insertResult: number) => {
callback(null, insertResult);
});
});
}
// 其他操作方法(删除、更新、查询)...
private queryFormById(formId: string): Promise<FormData | null> {
return new Promise((resolve, reject) => {
let predicates = new relationalStore.RdbPredicates(Constants.FORM_TABLE.tableName);
predicates.equalTo('formId', formId);
this.formTable.query(predicates, (resultSet: relationalStore.ResultSet) => {
if (resultSet.rowCount > 0) {
resultSet.goToFirstRow();
const form: FormData = {
formId: resultSet.getString(resultSet.getColumnIndex('formId')),
formName: resultSet.getString(resultSet.getColumnIndex('formName')),
formDimension: resultSet.getDouble(resultSet.getColumnIndex('formDimension')),
formConf: resultSet.getString(resultSet.getColumnIndex('formConf'))
};
resolve(form);
} else {
resolve(null);
}
});
});
}
}
function generateBucket(form: FormData): relationalStore.ValuesBucket {
let obj: relationalStore.ValuesBucket = {};
obj.formId = form.formId;
obj.formName = form.formName;
obj.formDimension = form.formDimension;
obj.formConf = form.formConf;
return obj;
}
在鸿蒙项目中,您可以通过 EntryFormAbility.ets 文件来实际使用数据库操作类。以下是如何在 EntryFormAbility 中集成和使用数据库操作的详细步骤。
使用数据库操作类的步骤 导入必要的模块和服务:
确保在 EntryFormAbility.ets 文件中导入了 FormService,它是用于与数据库交互的服务。 在 onAddForm 方法中插入数据:
当添加新表单时,使用 FormService 的 insert 方法将表单数据插入到数据库中。 在 onUpdateForm 方法中更新数据:
当表单需要更新时,调用 FormService 的 updateCard 方法来更新数据库中的表单数据。 在 onRemoveForm 方法中删除数据:
当表单被移除时,使用 FormService 的 delete 方法从数据库中删除表单数据。 代码示例 以下是一个完整的代码示例,展示了如何在 EntryFormAbility 中使用 FormService 和 FormTable 类来管理表单数据。
import { formBindingData, FormExtensionAbility, formInfo } from '@kit.FormKit';
import { Configuration, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import Constants from '../common/Constants';
import FormData from '../model/FormData';
import { FormService } from '../service/FormService';
export default class EntryFormAbility extends FormExtensionAbility {
onAddForm(want: Want) {
let parameters: Record<string, Object> = want.parameters!;
let formId: string = parameters[Constants.FORM_PARAM_IDENTITY_KEY] as string;
let formName: string = parameters[Constants.FORM_PARAM_NAME_KEY] as string;
let formDimension: number = parameters[Constants.FORM_PARAM_DIMENSION_KEY] as number;
hilog.debug(1, 'XS', "[WANT] onAddForm formId: " + formId);
let formData: FormData = {
formId: formId,
formName: formName,
formDimension: formDimension,
formConf: JSON.stringify({})
};
FormService.getService().insert(this.context.getApplicationContext(), formData, (data: FormData) => {
hilog.debug(1, 'XS', "[WANT] onAddForm formId: " + formId + " | save DB " + JSON.stringify(data));
FormService.getService().updateCard(this.context.getApplicationContext(), formId);
});
return formBindingData.createFormBindingData(formData);
}
onUpdateForm(formId: string) {
hilog.debug(1, 'XS', "[WANT] onUpdateForm formId: " + formId);
FormService.getService().updateCard(this.context.getApplicationContext(), formId);
}
onRemoveForm(formId: string) {
hilog.debug(1, 'XS', "[WANT] onRemoveForm formId: " + formId);
FormService.getService().delete(this.context.getApplicationContext(), formId, (isSuccess: boolean) => {
hilog.debug(1, 'XS', "[WANT] onRemoveForm isSuccess: " + isSuccess);
});
}
// 其他方法...
}
说明 onAddForm 方法:当添加新表单时,创建一个 FormData 对象并使用 FormService.insert 方法将其插入到数据库中。 onUpdateForm 方法:当表单需要更新时,调用 FormService.updateCard 方法更新数据库中的数据。 onRemoveForm 方法:当表单被移除时,使用 FormService.delete 方法从数据库中删除相应的数据。 通过以上步骤,您可以在鸿蒙项目中有效地管理数据库操作。确保在项目中正确配置和调用这些类和方法,以实现所需的数据库功能。
重点 必需要用 this.context.getApplicationContext() 获取到的鸿蒙上下文,才可以和Flutter共享数据库。
结语 Flutter操作数据的方法已经相对成熟和常见,因此在本文中不再赘述。在服务卡片中的操作方案,我已经提供了详细且关键的代码示例。欢迎大家进一步探讨和交流。我研发的软件《享咖小记》已上线鸿蒙商店,正是采用了这样的方案。
在HarmonyOS 鸿蒙Next系统中,实现服务卡片与Flutter应用共享SQLite数据库的实践探索,需要关注几个关键点。
首先,HarmonyOS NEXT中的关系型数据库基于SQLite组件,它提供了轻量级、高性能且易于嵌入应用程序的数据库解决方案。这使得SQLite成为移动应用开发中的常用选择,包括Flutter应用。
为了实现服务卡片与Flutter应用之间的数据共享,你需要确保两者能够访问到同一个SQLite数据库实例。这通常涉及到数据库文件的路径配置和访问权限设置。在Flutter应用中,你可以通过配置依赖和编写原生代码来访问SQLite数据库。而在服务卡片中,你可能需要利用HarmonyOS提供的原生API来实现对数据库的访问。
此外,为了保持数据的一致性和完整性,你需要在应用和服务卡片之间实现数据同步机制。这可以通过监听数据库的变化并实时更新服务卡片的内容来实现。同时,你也需要考虑数据安全和隐私保护的问题,确保在数据共享过程中不会泄露用户的敏感信息。
总之,实现HarmonyOS 鸿蒙Next中服务卡片与Flutter应用共享SQLite数据库的实践探索需要综合考虑数据库访问、数据同步和数据安全等多个方面。如果你在实施过程中遇到具体问题,可以参考HarmonyOS的官方文档或社区资源来寻求解决方案。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。