Flutter项目移动端SQLite升级指南:解决json_extract函数缺失问题

引言

Flutter移动端项目中依赖于SQLite的高级功能(如json_extract),在低版本的Android系统上部署时,可能会遇到函数不支持的问题。本文将指导你如何通过升级项目中使用的SQLite版本来解决这一问题。

前置条件

Flutter项目使用sqflite: ^2.3.3+1进行SQLite数据库操作。

IMBoy APP具有C2C类型的消息表,其中payload字段存储JSON字符串。

需求背景

实现"查找聊天"记录功能,涉及到对JSON字段的搜索查询,需要使用json_extract函数。

复制代码
SELECT auto_id, id, type, from_id, to_id, payload, created_at, is_author, topic_id, status, conversation_uk3 FROM message WHERE 1=1 AND (json_extract(payload, '$.text') LIKE '%abc%' or json_extract(payload, '$.quote_text') LIKE '%abc%' or json_extract(payload, '$.title') LIKE '%abc%') and conversation_uk3=? ORDER BY created_at desc LIMIT 10 OFFSET 0, (OS error - 2:No such file or directory)) sql 'SELECT auto_id, id, type, from_id, to_id, payload, created_at, is_author, topic_id, status, conversation_uk3 FROM message WHERE 1=1 AND (json_extract(payload, '$.text') LIKE '%abc%' or json_extract(payload, '$.quote_text') LIKE '%abc%' or json_extract(payload, '$.title') LIKE '%abc%') and conversation_uk3=?

问题描述

在低版本的Android系统上,SQLite数据库不支持json_extract函数,导致查询失败。

具体错误:

复制代码
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: DatabaseException(no such function: json_extract (Sqlite code 1 SQLITE_ERROR): , while compiling: SELECT auto_id, id, type, from_id, to_id, payload, created_at, is_author, topic_id, status, conversation_uk3 FROM message WHERE 1=1 AND (json_extract(payload, '$.text') LIKE '%abc%' or json_extract(payload, '$.quote_text') LIKE '%abc%' or json_extract(payload, '$.title') LIKE '%abc%') and conversation_uk3=? ORDER BY created_at desc LIMIT 10 OFFSET 0, (OS error - 2:No such file or directory)) sql 'SELECT auto_id, id, type, from_id, to_id, payload, created_at, is_author, topic_id, status, conversation_uk3 FROM message WHERE 1=1 AND (json_extract(payload, '$.text') LIKE '%abc%' or json_extract(payload, '$.quote_text') LIKE '%abc%' or json_extract(payload, '$.title') LIKE '%abc%') and conversation_uk3=? ORDER BY created_at desc

问题分析

json1扩展需要SQLite版本至少为3.38.0。

sqflite使用平台自带的SQLite,版本比较低为 3.22.0。

解决方案

为Android版本添加最新版本的SQLite库,以支持json1扩展。

操作步骤

    1. 下载最新版本的SQLite AAR文件并校验其SHA3-256哈希值。

下载 https://sqlite.org/2024/sqlite-android-3460100.aar ,放入 ./android/app/lib/ 目录(如果目录不存在就创建之);

https://sqlite.org/download.html

复制代码
Precompiled Binaries for Android
sqlite-android-3460100.aar
(3.44 MiB)      A precompiled Android library containing the core SQLite together with appropriate Java bindings, ready to drop into any Android Studio project.
(SHA3-256: c3bec0e3a17349d3a7a6b9b7d9f23e4b14ae38a175469c28377cd1e7aa41f62c)

然后手动校验aar的 sha3-256

复制代码
openssl dgst -sha3-256 /Users/leeyi/project/imboy.pub/imboyflutter/android/app/lib/sqlite-android-3460100.aar
  SHA3-256(/Users/leeyi/project/imboy.pub/imboyflutter/android/app/lib/sqlite-android-3460100.aar)= c3bec0e3a17349d3a7a6b9b7d9f23e4b14ae38a175469c28377cd1e7aa41f62c
    1. 在 ./android/app/build.gradle 文件中添加对SQLite AAR的依赖。

    andriod {
    ...
    dependencies {
    ...
    // 添加sqlite的依赖
    implementation files('lib/sqlite-android-3460100.aar')
    }
    }

    1. 在Flutter代码中初始化数据库,确保使用最新版本的SQLite。

在flutter代码中使用 sqlite-android-3460100.aar,需要安装 依赖 sqflite_common_ffisqlite3_flutter_libs

我安装了最新版本的依赖(2024-08-15)

复制代码
  sqflite: ^2.3.3+1
  sqflite_common_ffi: ^2.3.3
  sqlite3_flutter_libs: ^0.5.24

/Users/leeyi/project/imboy.pub/imboyflutter/lib/service/sqlite.dart

在dart源码中应用

复制代码
  Future<Database?> _initDatabase() async {
    // Init ffi loader if needed.
    sqfliteFfiInit();
    ...
    String path = await dbPath();
    ...
    // debugPrint("> on open db path {$path}");
    return await databaseFactoryFfi.openDatabase(
      path,
      options: OpenDatabaseOptions(
        version: _dbVersion,
        onConfigure: _onConfigure,
        onCreate: _onCreate,
        onUpgrade: _onUpgrade,
        onDowngrade: _onDowngrade,
        readOnly: false,
        singleInstance: true,
      ), // 重新打开相同的文件是安全的,它会给你相同的数据库。
    );
  }

结果验证

    1. 在Android Studio里面真机调试,打印日志为:

    andriod [ +225 ms] I/flutter (19060): iPrint SQLite version: [{sqlite_version(): 3.46.0}]

    复制代码
    Future<Database?> get db async {
      _db ??= await _initDatabase();
    
      // https://developer.android.com/reference/android/database/sqlite/package-summary
      // 查询 SQLite 版本
      final versionResult =
          await _db?.database.rawQuery('select sqlite_version();');
      if (versionResult!.isNotEmpty) {
        iPrint('SQLite version: $versionResult');
        // ios [  +55 ms] flutter: iPrint SQLite version: [{sqlite_version(): 3.46.1}]
        // andriod [ +225 ms] I/flutter (19060): iPrint SQLite version: [{sqlite_version(): 3.46.0}]
      }
      return _db;
    }
    1. 真机执行"查找聊天记录"也正常了
    1. 理论上应该要为3.46.1才对,是吧?

我也感觉困惑,针对这个问题,我在sqlite论坛发表了帖子,https://sqlite.org/forum/forumpost/03226f767e

不管怎么样,问题还是解决了

总结

通过升级项目使用的SQLite版本,我们成功解决了在低版本Android系统上json_extract函数缺失的问题,保证了APP功能的完整性和稳定性。

唯一的缺点是 APP的打包体检有增加了 3.6M (sqlite-android-3460100.aar 还有3.6M)了,不过还是值得的.

参考资料:

欢迎关注 IMBoy 开源项目 https://gitee.com/imboy-pub

相关推荐
福柯柯26 分钟前
Android ContentProvider的使用
android·contenprovider
不想迷路的小男孩26 分钟前
Android Studio 中Palette跟Component Tree面板消失怎么恢复正常
android·ide·android studio
餐桌上的王子27 分钟前
Android 构建可管理生命周期的应用(一)
android
菠萝加点糖31 分钟前
Android Camera2 + OpenGL离屏渲染示例
android·opengl·camera
用户20187928316742 分钟前
🌟 童话:四大Context徽章诞生记
android
yzpyzp1 小时前
Android studio在点击运行按钮时执行过程中输出的compileDebugKotlin 这个任务是由gradle执行的吗
android·gradle·android studio
aningxiaoxixi1 小时前
安卓之service
android
TeleostNaCl2 小时前
Android 应用开发 | 一种限制拷贝速率解决因 IO 过高导致系统卡顿的方法
android·经验分享
用户2018792831672 小时前
📜 童话:FileProvider之魔法快递公司的秘密
android
吴Wu涛涛涛涛涛Tao2 小时前
一步到位:用 Very Good CLI × Bloc × go_router 打好 Flutter 工程地基
flutter·ios