Flutter for OpenHarmony 三方库鸿蒙适配实战:flutter_video_info
欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net 本文详细记录了flutter_video_info库适配 HarmonyOS鸿蒙平台的完整过程包括前置准备、项目导入、模板创建、代码实现、问题解决以及最佳实践。 目录一、前置准备二、项目导入与初始化三、项目结构分析四、适配步骤详解五、示例应用适配六、文档编写七、代码提交八、总结与注意事项一、前置准备1.1 环境要求在开始适配前请确保你的开发环境满足以下条件环境项要求Flutter SDK建议 3.27.及以上版本并配置好环境变量DevEco Studio已安装 OpenHarmony 开发工具并配置 OH SDKOpenHarmony 设备真机或模拟器且开启开发者模式AtomGit已配置代码仓库的访问权限1.2 验证环境# 检查 Flutter 版本flutter --version# 检查连接的设备flutter devices二、项目导入与初始化2.1 将项目托管到 AtomGit方式一Fork 原项目如果原项目在 GitHub 上可以通过 Fork 的方式导入登录 AtomGit 平台点击「导入仓库」或「Fork」输入原项目的 GitHub 地址如https://atomgit.com/oh-flutter/flutter_video_info选择目标组织和仓库名称点击确认方式二创建新仓库推荐使用Fork登录 AtomGit 平台创建新的代码仓库建议命名与插件名一致如flutter_video_info将本地待适配的 Flutter 插件代码推送到该仓库2.2 克隆代码到本地将 AtomGit 上的仓库克隆到本地开发环境# 替换为你的 AtomGit 仓库地址gitclone https://atomgit.com/[你的用户名]/flutter_video_info.git# 进入项目目录cdflutter_video_info# 建议创建 ohos-adapt 分支进行适配开发gitcheckout -b ohos-adapt2.3 初始化 OH 平台插件结构Flutter 插件默认不包含 OH 平台的代码结构需要通过命令初始化# 在插件根目录执行初始化 OH 平台的插件模板flutter create.--templateplugin --platformsohos命令参数说明参数说明.表示在当前目录执行--templateplugin指定创建插件模板--platformsohos仅生成 OH 平台相关的代码目录避免覆盖已有 iOS/Android 代码执行结果flutter_video_info/ ├── ohos/ # 自动生成的鸿蒙平台目录 │ ├── src/main/ets/ │ │ └── components/plugin/ │ │ └── FlutterVideoInfoPlugin.ets │ ├── module.json5 │ ├── oh-package.json5 │ ├── build-profile.json5 │ ├── hvigorfile.ts │ └── index.ets ├── example/ohos/ # 自动生成的鸿蒙示例项目 │ ├── AppScope/ │ ├── entry/ │ ├── oh-package.json5 │ └── ... └── pubspec.yaml # 已更新添加 ohos 平台配置2.4 更新依赖执行依赖更新命令确保 Flutter 侧能识别 OH 平台的配置flutter pub get验证 pubspec.yaml 配置flutter:plugin:platforms:android:package:com.example.flutter_video_infopluginClass:FlutterVideoInfoPluginios:pluginClass:FlutterVideoInfoPluginohos:# 自动添加的鸿蒙配置pluginClass:FlutterVideoInfoPlugin三、项目结构分析3.1 原有目录结构flutter_video_info/ ├── android/ # Android 平台实现 │ └── src/main/java/ │ └── FlutterVideoInfoPlugin.java ├── ios/ # iOS 平台实现 │ └── Classes/ │ └── SwiftFlutterVideoInfoPlugin.swift ├── lib/ # Dart 层代码 │ ├── flutter_video_info.dart │ └── flutter_video_info_platform_interface.dart ├── example/ # 示例应用 └── pubspec.yaml3.2 分析原有实现 Android 实现JavaAndroid 平台使用MediaMetadataRetriever类获取视频元数据// FlutterVideoInfoPlugin.javaMediaMetadataRetrievermediaRetrievernewMediaMetadataRetriever();mediaRetriever.setDataSource(context,Uri.fromFile(file));StringauthorgetData(MediaMetadataRetriever.METADATA_KEY_AUTHOR,mediaRetriever);StringmimeTypegetData(MediaMetadataRetriever.METADATA_KEY_MIMETYPE,mediaRetriever);StringwidthgetData(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH,mediaRetriever);StringheightgetData(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT,mediaRetriever);StringdurationgetData(MediaMetadataRetriever.METADATA_KEY_DURATION,mediaRetriever);// ... 更多字段 iOS 实现SwiftiOS 平台使用AVURLAsset获取视频元数据// SwiftFlutterVideoInfoPlugin.swiftletassetAVURLAsset(url:url)lettracksasset.tracks(withMediaType:.video)letfpstracks.first?.nominalFrameRateletsizetracks.first?.naturalSizeletdurationTimeround(CMTimeGetSeconds(asset.duration)*1000) Dart 层接口// flutter_video_info.dartclassFlutterVideoInfo{staticconstMethodChannel_channelMethodChannel(flutter_video_info);FutureVideoData?getVideoInfo(Stringpath)async{finaljsonStrawait_channel.invokeMethod(getVidInfo,{path:path});finaljsonMapjson.decode(jsonStr);returnVideoData.fromJson(jsonMap);}}关键发现 使用 MethodChannel 进行平台通信 方法名为getVidInfo 参数为path视频文件路径 返回 JSON 字符串格式四、适配步骤详解4.1 实现核心功能 初始实现第一版根据 Android 实现使用鸿蒙的AVMetadataRetrieverimport{AVMetadataRetriever}fromohos.multimedia.media;// ❌ 错误导入方式不正确遇到问题编译报错Module has no exported member AVMetadataRetriever 修正实现第二版查阅鸿蒙 API 文档后发现正确用法import{media}fromkit.MediaKit;import{fileIoasfs}fromkit.CoreFileKit;exportdefaultclassFlutterVideoInfoPluginimplementsFlutterPlugin,MethodCallHandler{privatechannel:MethodChannel|nullnull;onAttachedToEngine(binding:FlutterPluginBinding):void{this.channelnewMethodChannel(binding.getBinaryMessenger(),flutter_video_info);this.channel.setMethodCallHandler(this);}asynconMethodCall(call:MethodCall,result:MethodResult):Promisevoid{if(call.methodgetVidInfo){letpathcall.argument(path)asstring;letjsonStrawaitthis.getVidInfo(path);result.success(jsonStr);}else{result.notImplemented();}}asyncgetVidInfo(path:string):Promisestring{// 实现细节...}}遇到问题AVMetadata属性名与预期不符 最终实现第三版根据鸿蒙 API 文档AVMetadata的正确属性Android 属性鸿蒙 AVMetadata 属性METADATA_KEY_MIMETYPEmimeTypeMETADATA_KEY_AUTHORartistMETADATA_KEY_VIDEO_WIDTHvideoWidthMETADATA_KEY_VIDEO_HEIGHTvideoHeightMETADATA_KEY_DURATIONduration完整实现代码import{FlutterPlugin,FlutterPluginBinding,MethodCall,MethodCallHandler,MethodChannel,MethodResult,}fromohos/flutter_ohos;import{media}fromkit.MediaKit;import{fileIoasfs}fromkit.CoreFileKit;exportdefaultclassFlutterVideoInfoPluginimplementsFlutterPlugin,MethodCallHandler{privatechannel:MethodChannel|nullnull;constructor(){}getUniqueClassName():string{returnFlutterVideoInfoPlugin;}onAttachedToEngine(binding:FlutterPluginBinding):void{this.channelnewMethodChannel(binding.getBinaryMessenger(),flutter_video_info);this.channel.setMethodCallHandler(this);}onDetachedFromEngine(binding:FlutterPluginBinding):void{if(this.channel!null){this.channel.setMethodCallHandler(null);}}asynconMethodCall(call:MethodCall,result:MethodResult):Promisevoid{if(call.methodgetVidInfo){letpathcall.argument(path)asstring;letjsonStrawaitthis.getVidInfo(path);result.success(jsonStr);}else{result.notImplemented();}}asyncgetVidInfo(path:string):Promisestring{letisFileExistfalse;letmimetype;letauthor;letdateStr;letwidth;letheight;letlocation;letframerate;letduration;letfilesize:number0;letorientation;try{// 检查文件是否存在并获取文件大小letstatfs.statSync(path);isFileExisttrue;filesizestat.size;// 创建元数据提取器letavMetadataExtractor:media.AVMetadataExtractorawaitmedia.createAVMetadataExtractor();try{// 打开文件letfilefs.openSync(path,fs.OpenMode.READ_ONLY);// 设置文件描述符avMetadataExtractor.fdSrcfile;// 获取元数据letmetadata:media.AVMetadataawaitavMetadataExtractor.fetchMetadata();if(metadata){mimetypemetadata.mimeType??;authormetadata.artist??;widthmetadata.videoWidth?.toString()??;heightmetadata.videoHeight?.toString()??;durationmetadata.duration?.toString()??;}// 关闭文件fs.closeSync(file);}catch(e){console.error(AVMetadataExtractor error: e);}finally{// 释放资源awaitavMetadataExtractor.release();}}catch(e){console.error(File access error: e);isFileExistfalse;}// 构建 JSON 返回结果letjsonObj:Recordstring,Object{path:path,mimetype:mimetype,author:author,date:dateStr,width:width,height:height,location:location,framerate:framerate,duration:duration,filesize:filesize,orientation:orientation,isfileexist:isFileExist};returnJSON.stringify(jsonObj);}}4.2 配置权限⚠️ 遇到的问题编译时报错Error: The reason and usedScene attributes are mandatory for user_grant permissions.原因分析ohos.permission.READ_MEDIA是用户授权权限必须包含reason和usedScene属性。✅ 解决方案步骤 1在示例应用的module.json5中配置权限// example/ohos/entry/src/main/module.json5 { module: { requestPermissions: [ { name: ohos.permission.INTERNET }, { name: ohos.permission.READ_MEDIA, reason: $string:read_media_reason, usedScene: { abilities: [EntryAbility], when: inuse } } ] } }步骤 2添加权限说明字符串// example/ohos/entry/src/main/resources/base/element/string.json{string:[{name:module_desc,value:module description},{name:EntryAbility_desc,value:description},{name:EntryAbility_label,value:flutter_video_info_example},{name:read_media_reason,value:用于读取视频文件信息}]}注意HAR 模块本身不能声明权限权限需要在宿主应用中声明。4.3 解决编译错误错误 1导入方式错误Error: Module ohos.multimedia.media has no exported member AVMetadataRetriever解决方案使用正确的导入方式// ❌ 错误import{AVMetadataRetriever}fromohos.multimedia.media;// ✅ 正确import{media}fromkit.MediaKit;letextractorawaitmedia.createAVMetadataExtractor();错误 2使用 any 类型Error: Use explicit types instead of any, unknown (arkts-no-any-unknown)解决方案为所有变量指定明确类型// ❌ 错误letmetadataawaitavMetadataExtractor.fetchMetadata();// ✅ 正确letmetadata:media.AVMetadataawaitavMetadataExtractor.fetchMetadata();错误 3属性不存在Error: Property date does not exist on type AVMetadata Error: Property videoFrameRate does not exist on type AVMetadata解决方案使用正确的属性名部分属性鸿蒙暂不支持// ❌ 错误dateStrmetadata.date;frameratemetadata.videoFrameRate;// ✅ 正确 - 部分属性暂不支持返回空字符串dateStr;framerate;五、示例应用适配5.1 配置 OH 示例项目签名为了真机调试需要对example/ohos目录下的示例项目进行签名配置用 DevEco Studio 打开example/ohos项目点击菜单栏「File」→「Project Structure」→「Modules」→「ohos」→「Signing Configs」选择已有的签名证书若无则创建配置签名信息同步项目Sync Now确保签名配置生效5.2 添加网络视频测试功能由于本地视频路径难以测试添加网络视频下载功能// example/lib/main.dartimportdart:io;importpackage:dio/dio.dart;finalListStringsampleVideoUrls[https://www.w3schools.com/html/mov_bbb.mp4,https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4,// ... 更多示例视频];FutureStringdownloadVideo(Stringurl)async{finalfileNametest_video_${DateTime.now().millisecondsSinceEpoch}.mp4;finaltempDirDirectory.systemTemp;// 使用系统临时目录finalfilePath${tempDir.path}/$fileName;finaldioDio();awaitdio.download(url,filePath);returnfilePath;}5.3 遇到的问题MissingPluginException: No implementation found for method getApplicationDocumentsDirectory原因path_provider插件未适配鸿蒙解决方案使用dart:io的Directory.systemTemp替代// ❌ 错误 - path_provider 未适配鸿蒙finalappDirawaitgetApplicationDocumentsDirectory();// ✅ 正确 - 使用 dart:io 内置方法finaltempDirDirectory.systemTemp;5.4 更新 pubspec.yamldependencies:flutter:sdk:flutterpermission_handler:^11.3.1dio:^5.4.0# 用于下载网络视频cupertino_icons:^1.0.65.5 真机调试将 OH 真机连接到电脑执行调试命令# 在插件根目录执行运行 OH 示例项目flutter run -d[你的设备ID]--verbose调试要点观察终端输出排查代码语法错误、API 调用错误等问题在真机上验证核心功能是否与 iOS/Android 端表现一致反复调试修复兼容性问题六、文档编写6.1 创建中英文 README适配完成后需要新增文档说明 OH 平台的使用方式文档说明README.OpenHarmony_CN.md中文使用文档README.OpenHarmony.md英文使用文档七、代码提交确认所有功能正常、文档完整后执行代码提交操作# 添加适配相关的文件gitaddohos/# OH 平台核心代码gitaddexample/ohos/# OH 示例项目gitaddREADME_CN.md README_EN.md ADAPTATION_GUIDE.md# 适配文档gitaddpubspec.yaml# 平台配置文件gitaddlib/# 若 Flutter 侧代码有改动需添加# 提交代码gitcommit -mohoh适配# 推送到 AtomGit 仓库gitpush origin ohos-adapt八、总结与注意事项8.1 关键技术点技术点AndroidiOSHarmonyOS元数据提取类MediaMetadataRetrieverAVURLAssetAVMetadataExtractor导入方式原生 Java原生 Swiftimport { media } from kit.MediaKit文件操作java.io.FileFileManagerimport { fileIo } from kit.CoreFileKit

相关新闻

当“问卷迷宫”遇上“AI导航”:书匠策AI如何改写教育科研问卷设计规则

当“问卷迷宫”遇上“AI导航”:书匠策AI如何改写教育科研问卷设计规则

在学术研究的江湖里,问卷设计常被研究者视为“第一道险关”。传统问卷设计如同在迷雾中摸索前行:研究者需要手动绘制逻辑链条,反复调试量表信效度,甚至在问卷发放后才发现样本偏差问题。而当书匠策AI携智能算法闯入这一领域时&…

2026/7/5 0:57:10 阅读更多 →
荆州市副市长韩旭一行莅临思恒信息科技考察调研

荆州市副市长韩旭一行莅临思恒信息科技考察调研

5月23日,荆州市副市长韩旭,市场监管局党组书记、局长王开等一行莅临思恒信息科技考察调研,公司创始人陈慧军、副总经理刘明凯等陪同调研。公司创始人陈慧军向韩副市长详细介绍了公司的发展历程、企业文化、创新成果和场景应用。韩副市长对公司…

2026/7/5 22:08:28 阅读更多 →
从“问卷炼狱”到“智能天堂”:书匠策AI如何改写教育科研问卷设计法则

从“问卷炼狱”到“智能天堂”:书匠策AI如何改写教育科研问卷设计法则

在学术江湖中,问卷设计堪称教育科研的“第一道生死关”。传统问卷设计犹如在迷雾中徒手攀岩——研究者需在浩如烟海的文献中提炼理论框架,在Excel表格里逐字打磨题项,在预调查中反复试错,最终还要面对“样本偏差”“信效度崩塌”等…

2026/5/17 4:35:24 阅读更多 →

最新新闻

AI创意工作流深度解析:MiniMax Hub如何重塑内容创作与设计流程

AI创意工作流深度解析:MiniMax Hub如何重塑内容创作与设计流程

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 这次我们来看一个面向创意工作的AI工具——MiniMax Hub。它被描述为“创意工作的Claude Code”,这个定位很有意思。Claude…

2026/7/5 22:16:50 阅读更多 →
AI客服系统选型实战指南:实时性、方言识别与合规性深度解析

AI客服系统选型实战指南:实时性、方言识别与合规性深度解析

1. 这不是“软件排行榜”,而是一份AI客服系统选型实战手记 我做智能客服系统集成和落地已经九年,从最早给银行部署基于规则的IVR语音导航,到后来带团队在电商大促期间扛住单日300万通AI外呼峰值,再到去年帮一家跨境SaaS公司把人工…

2026/7/5 22:14:50 阅读更多 →
步进电机全闭环控制与EtherCAT总线技术详解

步进电机全闭环控制与EtherCAT总线技术详解

1. 步进控制全闭环系统概述 在工业自动化领域,步进电机因其结构简单、控制方便而广受欢迎,但传统开环控制存在丢步风险。ZMC432CL-V2运动控制器通过光栅尺全闭环反馈和EtherCAT总线技术,完美解决了这一问题。这套系统的工作原理是&#xff1a…

2026/7/5 22:12:49 阅读更多 →
ABB IRB 120机器人三种运动模式详解与应用

ABB IRB 120机器人三种运动模式详解与应用

1. ABB IRB 120机器人运动控制基础 IRB 120是ABB公司生产的一款小型六轴工业机器人,最大负载3kg(垂直腕)/4kg(水平腕),工作半径580mm。这款机器人在电子装配、物料搬运、实验室自动化等领域应用广泛。它的运…

2026/7/5 22:12:49 阅读更多 →
openeuler/curl-rust路线图详解:未来规划与Rust生态集成展望

openeuler/curl-rust路线图详解:未来规划与Rust生态集成展望

openeuler/curl-rust路线图详解:未来规划与Rust生态集成展望 【免费下载链接】curl-rust Rewrite memory leak related modules for curl using Rust 项目地址: https://gitcode.com/openeuler/curl-rust 前往项目官网免费下载:https://ar.openeu…

2026/7/5 22:10:49 阅读更多 →
西门子S7-1200 PLC伺服步进控制FB功能块详解

西门子S7-1200 PLC伺服步进控制FB功能块详解

1. 项目概述:自动化控制领域的瑞士军刀 在工业自动化领域,西门子S7-1200系列PLC因其出色的稳定性和灵活的编程环境,已成为中小型自动化项目的首选控制器。而伺服步进控制作为精密运动控制的核心技术,其实现方式直接决定了设备定位…

2026/7/5 22:08:48 阅读更多 →

日新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻