没有人比我更懂Flutter第三方依赖鸿蒙化了之Sqflite

66 阅读5分钟

最近又折腾了一波鸿蒙,发现鸿蒙的数据库支持SQLite,于是乎,就想着把Sqflite鸿蒙化,于是乎,就有了这个系列。

在此之前先打个广告,有鸿蒙5+的设备朋友帮我刷个下载量,在AppGallery下载以下app打开并运行一下子,感谢:

  • 乐活伴侣
  • 阿默宠物

和Sqflite无关的东西

先说点和鸿蒙相关的其他的小知识点,不算什么新知识,但是可能会帮到你。 作为后起之秀,鸿蒙算是站在不少巨人的肩膀上的,因此,一些权限管理的相对比较严格,以下内容仅对上架华为应用市场的手机app有效,对于非上架华为应用市场的app及其他类型设备本人没有研究。

应用读取剪贴板

对剪切板的主动读取,不像Android那样,直接调用ClipboardManager就可以。 在鸿蒙中,应用读取剪贴板是不仅要在module.json5中申请权限:

      {
        "name": "ohos.permission.READ_PASTEBOARD",
        "reason": "$string:request_paste_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },

还要在申请Profile时申请ACL权限,得等ACL权限申请通过后,才能使用这个权限。目前,官方允许使用该权限的只有符合以下场景:

  • 银行卡号复制:银行类应用需要读取剪贴板中的银行卡号自动生成卡片。
  • 口令复制:应用需要读取剪贴板中特定格式口令,自动打开应用内对应页面。
  • 文档编辑类应用。
  • 输入法:系统级输入法需要读取剪贴板信息实现自动填充。应用内置输入法不能申请此权限。

同时,官方也给出了一个解决方案,使用“粘贴控件”读取剪贴板数据,使用方式请参考:使用粘贴控件,但这是一个原生组件,Flutter中似乎无法使用(当然我也没有试过)。

以下是我在申请时,给我的答复:

审核意见: 开发者您好:

受限权限仅少量符合特殊场景的应用可在通过审批后使用,您的场景不符合权限使用要求,请使用非权限的替代方案实现功能。

粘贴场景ArkUI输入框支持长按拉起toolbar,可以直接粘贴剪切板内的第一条内容,无需申请ohos.permission.READ_PASTEBOARD权限,如您使用的是三方框架,请在申请理由中描述并重新提交申请,感谢您的理解与支持!

其他权限

还有一些权限,在我看起来好像并不需要声明,但实际上你还是要在module.json5中声明一下,比如调用系统的打印服务:

 {
        "name": "ohos.permission.PRINT",
        "reason": "$string:request_print_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }

不声明是无法使用的。关于权限具体可以参看:应用权限管控 ,文档说的很详细了,不赘述了。

Sqflite鸿蒙化

起初,我以为flutter_sqflite已经支持鸿蒙了,那理应问题不大,但是,当我尝试使用时,还是给我了一些小小的惊喜。

INTEGER变blob了?

用flutter_sqflite库建表时候,字段为INTEGER,理论上sqlite的INTEGER兼容long型。并且dart中 int也是兼容long。但是现在dart模型中int字段(比如:DateTime.now().millisecondsSinceEpoch),存入数据库,会被强制转成blob类型,然后查询上来的数据是unmodifiableUint8arrayview。

如何解决?

答:像时间戳这种比较大的数据类型字段要用UNLIMITED INT,不能用INTEGER ,例如:

CREATE TABLE $_tableName(id INTEGER PRIMARY KEY, name TEXT, age INTEGER, create_t UNLIMITED INT)

不支持REAL

有一个字段的类型是REAL,在鸿蒙中是不支持的,因此,我又把其类型改成DOUBLE类型。结果我发现,我取出来的值全成成了整数,精度全部丢失了,我不太清楚是哪个环节出现了问题,是数据库本身的问题还是插件层的代码出现了问题,总之,精度确实丢了。评论区如果有知道原因的,可以告诉我。没办法,我又把其类型改成TEXT类型,用字符串存储,然后在dart层进入解析才算完事。

兼容性

我从flutter_sqflite中摘抄了部分文档,大家可以参考一下:

属性

[!TIP] "ohos Support"列为 yes 表示 ohos 平台支持该属性;no 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。

存储类型

NameDescriptionTypeohos Support
String存储字符串值Stringyes
int存储整数值intyes
real存储浮点数值doubleno
bool存储布尔值boolyes
nullnullyes
date_time储存时间值date_timeyes

OpenDatabaseOptions

NameDescriptionTypeohos Support
version数据库版本int?yes
onConfigure数据库配置回调OnDatabaseConfigureFn?yes
onCreate数据库首次创建回调OnDatabaseCreateFn?yes
onUpgrade数据库版本升级回调OnDatabaseVersionChangeFn?yes
onDowngrade数据库版本降级回调OnDatabaseVersionChangeFn?yes
onOpen数据库成功打开回调OnDatabaseOpenFn?yes
readOnly是否以只读模式打开数据库bool?yes
singleInstance是否强制单例模式bool?yes

API

[!TIP] "ohos Support"列为 yes 表示 ohos 平台支持该属性;no 则表示不支持;partially 表示部分支持。使用方法跨平台一致,效果对标 iOS 或 Android 的效果。

DatabaseFactory

Namereturn valueDescriptionTypeohos Support
openDatabase(String path, {OpenDatabaseOptions? options})Future打开指定路径的数据库,可配置打开选项functionyes
getDatabasesPathFuture获取数据库默认存储路径functionyes
setDatabasesPath(String path)Future设置默认数据库存储路径functionyes
deleteDatabase(String path)Future删除指定路径的数据库functionyes
databaseExists(String path)Future检查指定路径的数据库是否存在functionyes

DatabaseExecutor

Namereturn valueDescriptionTypeohos Support
execute(String sql, [List<Object?>? arguments])Future执行 SQL 语句functionyes
rawInsert(String sql, [List<Object?>? arguments])Future直接执行插入 SQL 返回行数functionyes
insert(String table, Map<String, Object?> values, {String? nullColumnHack,ConflictAlgorithm? conflictAlgorithm})Future插入 SQL 返回行数functionyes
query(String table,
{bool? distinct,
List? columns,
String? where,
List<Object?>? whereArgs,
String? groupBy,
String? having,
String? orderBy,
int? limit,
int? offset});
Future<List<Map<String, Object?>>>查询返回结果集列表functionyes
rawQuery(String sql, [List<Object?>? arguments])Future<List<Map<String, Object?>>>直接执行 SQL 查询返回结果集列表functionyes
rawQueryCursor(String sql, List<Object?>? arguments, {int? bufferSize})Future执行原始 SQL 查询返回游标对象functionyes
queryCursor(String table,
{bool? distinct,
List? columns,
String? where,
List<Object?>? whereArgs,
String? groupBy,
String? having,
String? orderBy,
int? limit,
int? offset,
int? bufferSize})
Future查询返回游标对象functionyes
rawUpdate(String sql, [List<Object?>? arguments])Future直接执行更新 SQL 返回影响行数functionyes
update(String table, Map<String, Object?> values,
{String? where,
List<Object?>? whereArgs,
ConflictAlgorithm? conflictAlgorithm})
Future执行更新 SQL 返回影响行数functionyes
rawDelete(String sql, [List<Object?>? arguments])Future直接执行SQL删除符合条件的数据行functionyes
delete(String table, {String? where, List<Object?>? whereArgs})Future删除符合条件的数据行functionyes
batchBatch获取批处理操作对象functionyes
get databaseDatabase获取底层数据库实例functionyes

Batch

Namereturn valueDescriptionTypeohos Support
commit({
bool? exclusive,
bool? noResult,
bool? continueOnError,
})
Future<List<Object?>>提交批量操作functionyes
apply({bool? noResult, bool? continueOnError})Future<List<Object?>>执行批量操作并自动提交functionyes
rawInsert(String sql, [List<Object?>? arguments])void执行SQL插入语句functionyes
insert(String table, Map<String, Object?> values,
{String? nullColumnHack, ConflictAlgorithm? conflictAlgorithm})
void执行SQL插入语句functionyes
rawUpdate(String sql, [List<Object?>? arguments])void执行SQL更新语句functionyes
update(String table, Map<String, Object?> values,
{String? where,
List<Object?>? whereArgs,
ConflictAlgorithm? conflictAlgorithm})
void执行SQL更新语句functionyes
rawDelete(String sql, [List<Object?>? arguments])void执行SQL删除语句functionyes
delete(String table, {String? where, List<Object?>? whereArgs})void执行SQL删除语句functionyes
execute(String sql, [List<Object?>? arguments])void执行通用SQL语句functionyes
query(String table,
{bool? distinct,
List? columns,
String? where,
List<Object?>? whereArgs,
String? groupBy,
String? having,
String? orderBy,
int? limit,
int? offset})
void执行 SQL 查询语句functionyes
rawQuery(String sql, [List<Object?>? arguments])void执行 SQL 查询语句functionyes
get lengthint获取累计操作数量functionyes