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

相关推荐
xiangpanf10 小时前
Laravel 10.x重磅升级:五大核心特性解析
android
电商API&Tina12 小时前
【电商API接口】开发者一站式电商API接入说明
大数据·数据库·人工智能·云计算·json
robotx13 小时前
安卓线程相关
android
消失的旧时光-194313 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon14 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon14 小时前
VSYNC 信号完整流程2
android
dalancon14 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户693717500138416 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android16 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才17 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android