当前位置: 首页 > ai >正文

Flutter接入ProtoBuff和原生Android通信【性能最优】

Protocol Buffers(简称Protobuf)是由 Google 开发的一种结构化数据序列化框架,旨在实现高效的数据交换与存储。其核心特性及优势如下:

一、核心特性

  1. 跨语言与跨平台
    支持多种编程语言(如 C++、Java、Python、Dart 等),生成的语言无关代码可在不同平台间无缝交互。
  2. 高性能编码
    采用二进制格式进行序列化,数据体积小且解析速度快,相较于 XML 和 JSON 可缩减数据量 3–10 倍,解析速度提升 20–100 倍。
  3. 灵活扩展性
    通过 .proto 文件定义数据结构,支持向后兼容的字段更新(如新增字段不影响旧版解析)。
     

二、工作原理

  1. 定义数据结构
    使用 .proto 文件声明消息类型及其字段规则,例如:
message User {required string name = 1;optional int32 age = 2;repeated string emails = 3;
}
  1. 代码生成
    通过 Protobuf 编译器(protoc)配合语言插件(如 protoc_plugin)生成目标语言的序列化/反序列化类。
  2. 序列化与反序列化
    生成的类提供接口将对象转换为二进制流(网络传输或存储)或从二进制流重建对象。

三、典型应用场景

四、与其他序列化协议的对比 

 五、flutter访问原生Android图库实践

5.1 protobuff环境搭建

需要 protobuff 安装环境,以mac为例:

1. 检查protoc_plugin插件版本

dart pub global list | grep protoc_plugin

 安装protoc_plugin插件

MacBook-Pro ~ % dart pub global activate protoc_pluginDownloading packages... . + collection 1.19.1+ fixnum 1.1.1+ meta 1.16.0+ path 1.9.1+ protobuf 4.0.0+ protoc_plugin 22.0.1

输出(protoc_plugin 22.0.1、要求:protobuf 4.0.0):

⚠️注意:flutter项目pubspec.yaml也需要配置:

  protobuf: ^4.0.0protoc_plugin: ^22.0.1

2. 检查libprotoc版本及安装

MacBook-Pro ~ % protoc --version 
libprotoc 3.21.12

5.2 Android原生配置

 1. android/build.radle

    dependencies {classpath 'com.android.tools.build:gradle:7.4.2'classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"classpath 'com.google.protobuf:protobuf-gradle-plugin:0.9.4' // 增加}

2.  android/app/build.radle

apply plugin: 'com.google.protobuf' // 导入插件android {// 添加sourceSets {main {proto {srcDir 'src/main/proto'}}}
}// 添加
protobuf {protoc {artifact = 'com.google.protobuf:protoc:3.24.4'}generateProtoTasks {all().each { task ->task.builtins {java {option 'lite'}}}}
}dependencies {implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"implementation 'androidx.multidex:multidex:2.0.1'//    # Flutter 侧(确保两侧一致protoc --version)//    protoc --version && dart pub global list | grep protoc_pluginimplementation 'com.google.protobuf:protobuf-javalite:3.21.12'
}

5.3 Android原生proto开发及编译

1. 编写代码:android/app/src/main/proto/media.proto

syntax = "proto3";
package com.example.test.proto;message MediaItem {int64 id = 1;string path = 2;string album = 3;int64 size = 4;int64 date_added = 5;int64 date_modified = 6;int64 duration = 7; // 0表示图片string mime_type = 8; // 新增字段
}message MediaList {repeated MediaItem items = 1;
}

2. 编译输出产物flutter项目根目录下:lib/protos/media目录

执行终端命令:

# 创建目录
mkdir -p lib/protos/media# 生成代码
protoc --dart_out=grpc:lib/protos/media --proto_path=android/app/src/main/proto android/app/src/main/proto/media.proto

输出:

5.4 Android原生插件通信开发

开发业务model:

class PhotoMediaModel {@TargetApi(Build.VERSION_CODES.JELLY_BEAN)@SuppressLint("Range")fun getPhotoMedias(context: Context): ByteArray {val proto = MediaList.newBuilder()val projection = arrayOf(MediaStore.MediaColumns._ID,MediaStore.MediaColumns.DATA,MediaStore.MediaColumns.BUCKET_DISPLAY_NAME,MediaStore.MediaColumns.SIZE,MediaStore.MediaColumns.DATE_ADDED,MediaStore.MediaColumns.DATE_MODIFIED,MediaStore.Video.VideoColumns.DURATION)val uri = MediaStore.Files.getContentUri("external")val selection = "${MediaStore.Files.FileColumns.MEDIA_TYPE} IN (?,?)"val args = arrayOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE.toString(),MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO.toString())context.contentResolver.query(uri,projection,selection,args,null)?.use { cursor ->val idCol = cursor.getColumnIndex(MediaStore.MediaColumns._ID)val dataCol = cursor.getColumnIndex(MediaStore.MediaColumns.DATA)val albumCol = cursor.getColumnIndex(MediaStore.MediaColumns.BUCKET_DISPLAY_NAME)val sizeCol = cursor.getColumnIndex(MediaStore.MediaColumns.SIZE)val addedCol = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_ADDED)val modifiedCol = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_MODIFIED)val durationCol = cursor.getColumnIndex(MediaStore.Video.VideoColumns.DURATION)val itemBuilder = MediaItem.newBuilder()while (cursor.moveToNext()) {val item = itemBuilder.clear().apply {id = cursor.getLong(idCol)path = cursor.getString(dataCol)album = cursor.getString(albumCol) ?: ""size = cursor.getLong(sizeCol)dateAdded = cursor.getLong(addedCol)dateModified = cursor.getLong(modifiedCol)duration = if (cursor.isNull(durationCol)) 0 else cursor.getLong(durationCol)}.build()proto.addItems(item)}}return proto.build().toByteArray()}
}

然后在Actvity注册自己的插件业务:


class MainActivity : FlutterActivity() {private val CHANNEL_PHOTO = "com.example.test/photo_media_channel"private val photoMediaModel = PhotoMediaModel()override fun configureFlutterEngine(flutterEngine: FlutterEngine) {super.configureFlutterEngine(flutterEngine)registerPlugins(flutterEngine, this)}private fun registerPlugins(flutterEngine: FlutterEngine, context: Context) {// 图库查询MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_PHOTO).setMethodCallHandler { call, result ->when (call.method) {"getPhotoMedias" -> {val byteArray = photoMediaModel.getPhotoMedias(context)result.success(byteArray)}else -> {result.notImplemented()}}}}
}

至此原生开发完成。

5.6 Flutter访问原生插件

开发对应的MethodChannel

class PhotoMediaOptChannel {static const MethodChannel _photoMediaChannel = MethodChannel("com.example.test/photo_media_channel");static Future<List<MediaItem>> getPhotoMedias() async {if (!Platform.isAndroid) {return [];}try {final byteArray = await _photoMediaChannel.invokeMethod<Uint8List>('getPhotoMedias');// 使用 Protobuf 生成的代码进行反序列化if (byteArray == null) {debugPrint('Performance: getPhotoMedias 错误: protoBytes 为空');return [];}final MediaList mediaList = MediaList.fromBuffer(byteArray);debugPrint('Performance: getPhotoMedias 结束: ${mediaList.items.length}');return mediaList.items;} catch (e) {debugPrint('Performance: getPhotoMedias 错误: $e');return [];}}
}

 注意:flutter需要配置依赖:pubspec.yaml

  protobuf: ^4.0.0protoc_plugin: ^22.0.1

运行输出:
2025-05-08 19:21:37.929 12321-12487 flutter                 com.example.test                   I  Performance: getPhotoMedias 结束: 264

六、总结

由于对protobuff不太了解版本关系,一直搞不定,坑了半天,总结一下实践步骤以供借鉴。

http://www.xdnf.cn/news/4751.html

相关文章:

  • day23-集合(泛型Set数据结构)
  • A. Row GCD(gcd的基本性质)
  • C++模板【下篇】— 详解模板进阶语法及模板细节
  • 软考知识点汇总
  • [java八股文][Java并发编程面试篇]场景
  • 基于Java实现(PC)民航订票管理系统
  • 关于Bearer Token
  • System-V 共享内存
  • Java流程控制
  • 果汁厂通信革新利器:Ethernet/IP转CANopen协议网关
  • 为什么跨境电商要了解固定IP?常见疑问解析
  • 算法竞赛进阶指南.次小生成树
  • 同比和环比有什么区别?同比和环比的计算方法
  • Oracle OCP认证考试考点详解083系列12
  • RISC-V hardfault分析工具,RTTHREAD-RVBACKTRACE
  • C语言 指针(9)
  • 初学者如何获得WordPress技术支持
  • 模拟内存管理
  • 如何添加二级域名
  • Linux操作系统中的通知机制
  • 单片机 + 图像处理芯片 + TFT彩屏 指示灯控件
  • python小记(十四):Python 中 **参数解包:深入理解与应用实践
  • 【java】oop 结课模拟题版
  • 探索大语言模型(LLM):硅基流动+Cherry studio免费白嫖Qwen3模型
  • librosa.load 容易遇到的采样率问题
  • RISC-V入门资料
  • Pyinstaller编译EXE及反编译
  • 在Postman中高效生成测试接口:从API文档到可执行测试的完整指南
  • Linux下的c/c++开发之操作Sqlite3数据库
  • SpringBoot3 + Druid + DynamicDataSource + PgSQL 连接池优化方案