HarmonyOS 鸿蒙Next中服务卡片与Flutter应用共享SQLite数据库的实践探索

发布于 1周前 作者 wuwangju 最后一次编辑是 5天前 来自 鸿蒙OS

在鸿蒙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 运行应用。 确保项目可以运行在手机中。

实现步骤

  1. 创建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 [];
    }
  }
}
  1. 创建服务卡片 基于: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操作数据的方法已经相对成熟和常见,因此在本文中不再赘述。在服务卡片中的操作方案,我已经提供了详细且关键的代码示例。欢迎大家进一步探讨和交流。我研发的软件《享咖小记》已上线鸿蒙商店,正是采用了这样的方案。

2 回复
感谢楼主分享~

在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

回到顶部