Flutter标签解析插件taglib_ffi_dart的使用
Flutter标签解析插件taglib_ffi_dart的使用
概述
taglib_ffi_dart 是一个基于 TagLib 的 Dart/Flutter 插件,用于管理和解析音频文件的元数据标签。它支持多种音频格式,并允许读取和写入标签信息。
当前状态
- 工作状态:插件目前处于开发阶段(WIP),API 可能会随版本更新而发生变化。
 - 测试平台:已在 Android 和 Linux 平台上进行了测试。
 
使用方法
1. 添加依赖
在 pubspec.yaml 文件中添加以下依赖:
dependencies:
  taglib_ffi_dart: current_version
  taglib_ffi_dart_libs: current_version
然后运行 dart pub get 来安装依赖。
示例代码
以下是一个完整的 Flutter 示例,展示如何使用 taglib_ffi_dart 插件来读取音频文件的元数据。
代码实现
import 'dart:async';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:taglib_ffi_dart/taglib_ffi_dart.dart' as taglib;
Future<void> main() async {
  await taglib.initialize(); // 初始化插件
  runApp(const MyApp());
}
class MyApp extends StatefulWidget {
  const MyApp({super.key});
  @override
  State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
  final formKey = GlobalKey<FormState>();
  final titleC = TextEditingController();
  final artistC = TextEditingController();
  final albumC = TextEditingController();
  final trackC = TextEditingController();
  final yearC = TextEditingController();
  final genreC = TextEditingController();
  final commentC = TextEditingController();
  final sampleRateC = TextEditingController();
  final bitrateC = TextEditingController();
  final channelsC = TextEditingController();
  final lengthC = TextEditingController();
  final lyricsC = TextEditingController();
  Uint8List? albumCoverData;
  @override
  void initState() {
    super.initState();
  }
  // 读取音频文件的元数据
  Future<void> readMetadataFromFile() async {
    FilePickerResult? result = await FilePicker.platform.pickFiles();
    if (result == null) {
      return;
    }
    final filePath = result.files.single.path;
    if (filePath == null) {
      return;
    }
    // 获取元数据
    taglib.Metadata? metaData;
    try {
      metaData = await taglib.readMetadata(filePath);
    } on PlatformException {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Failed to read metadata: $PlatformException'),
        ),
      );
      return;
    }
    setState(() {
      if (metaData == null) {
        return;
      }
      titleC.text = metaData.title ?? '';
      artistC.text = metaData.artist ?? '';
      albumC.text = metaData.album ?? '';
      trackC.text = metaData.track == 0 ? '' : metaData.track.toString();
      yearC.text = metaData.year == 0 ? '' : metaData.year.toString();
      genreC.text = metaData.genre ?? '';
      commentC.text = metaData.comment ?? '';
      sampleRateC.text =
          metaData.sampleRate == 0 ? '' : metaData.sampleRate.toString();
      bitrateC.text = metaData.bitrate == 0 ? '' : metaData.bitrate.toString();
      channelsC.text =
          metaData.channels == 0 ? '' : metaData.channels.toString();
      lengthC.text = metaData.length == 0 ? '' : metaData.length.toString();
      lyricsC.text = metaData.lyrics ?? '';
      albumCoverData = metaData.albumCover;
    });
  }
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('taglib_ffi_dart 示例应用'),
        ),
        body: Scrollbar(
          child: SingleChildScrollView(
            primary: true,
            child: Padding(
              padding: const EdgeInsets.all(15),
              child: Form(
                key: formKey,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    // 显示专辑封面
                    if (albumCoverData != null) Image.memory(albumCoverData!),
                    TextFormField(
                      autofocus: false,
                      controller: titleC,
                      decoration: const InputDecoration(
                        labelText: '标题',
                      ),
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: artistC,
                      decoration: const InputDecoration(
                        labelText: '艺术家',
                      ),
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: albumC,
                      decoration: const InputDecoration(
                        labelText: '专辑',
                      ),
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: trackC,
                      decoration: const InputDecoration(
                        labelText: '轨道号',
                      ),
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: yearC,
                      decoration: const InputDecoration(
                        labelText: '年份',
                      ),
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: genreC,
                      decoration: const InputDecoration(
                        labelText: '流派',
                      ),
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: commentC,
                      decoration: const InputDecoration(
                        labelText: '评论',
                      ),
                      minLines: 1,
                      maxLines: 10,
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: sampleRateC,
                      decoration: const InputDecoration(
                        labelText: '采样率 (kHz)',
                      ),
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: bitrateC,
                      decoration: const InputDecoration(
                        labelText: '比特率 (kbps)',
                      ),
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: channelsC,
                      decoration: const InputDecoration(
                        labelText: '声道数',
                      ),
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: lengthC,
                      decoration: const InputDecoration(
                        labelText: '时长 (秒)',
                      ),
                    ),
                    TextFormField(
                      autofocus: false,
                      controller: lyricsC,
                      decoration: const InputDecoration(
                        labelText: '歌词',
                      ),
                      minLines: 1,
                      maxLines: 20,
                    )
                  ],
                ),
              ),
            ),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          child: const Icon(Icons.add),
          onPressed: () async {
            await readMetadataFromFile(); // 点击按钮时读取文件元数据
          },
        ),
      ),
    );
  }
}
功能说明
- 
初始化插件: 在
main()函数中调用taglib.initialize()初始化插件。 - 
读取文件: 使用
FilePicker提供的pickFiles()方法让用户选择音频文件。 - 
解析元数据: 调用
taglib.readMetadata(filePath)获取音频文件的元数据。 - 
显示结果: 将解析出的元数据显示在表单中,包括标题、艺术家、专辑、轨道号等信息。
 - 
专辑封面: 如果音频文件包含专辑封面图像,则通过
Uint8List显示。 
平台支持
| 平台 | 支持情况 | 
|---|---|
| Android | ✅ | 
| iOS | ❌ | 
| Linux | ✅ | 
| macOS | ❌ | 
| Windows | ❌ (即将支持) | 
格式支持
| 格式 | 标签类型 | 读取支持 | 写入支持 | 
|---|---|---|---|
| mp3 | Id3v2 | ✔️ | ❌ | 
| flac | Vorbis | ❌ | ❌ | 
| ape | APEv2 | ❌ | ❌ | 
| wma | ASF | ❌ | ❌ | 
| dsd/dsf | Id3v2 | ❌ | ❌ | 
| wav | RIFF | ❌ | ❌ | 
标签支持
| 标签 | 支持情况 | 
|---|---|
| 标题 | ✅ | 
| 艺术家 | ✅ | 
| 专辑 | ✅ | 
| 专辑艺术家 | ✅ | 
| 轨道号 | ✅ | 
| 专辑总轨道数 | ✅ | 
| 年份 | ✅ | 
| 流派 | ✅ | 
| 评论 | ✅ | 
| 采样率 | ✅ | 
| 比特率 | ✅ | 
| 声道数 | ✅ | 
| 时长 | ✅ | 
| 歌词 | ✅ | 
| 专辑封面图像 | ✅ | 
| 多张封面图像 | ❌ | 
| 自定义标签 | ❌ | 
构建方式
1. 所有平台
首先生成绑定代码:
dart pub get
dart run ffigen --config ffigen.yaml
2. Android
export ANDROID_HOME=/path/to/Android/SDK
cd packages
./taglib_ffi_dart/scripts/build_android.sh ./taglib_ffi_dart_libs/android/src/main/jniLibs
3. Linux
./taglib_ffi_dart/scripts/build_linux.sh ./taglib_ffi_dart_libs/linux
更多关于Flutter标签解析插件taglib_ffi_dart的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter标签解析插件taglib_ffi_dart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
taglib_ffi_dart 是一个 Flutter 插件,用于解析和编辑音频文件的元数据(如 ID3 标签、MP3 标签等)。它基于 TagLib 库,并通过 Dart 的 FFI(Foreign Function Interface)与原生代码进行交互。
以下是使用 taglib_ffi_dart 插件的基本步骤:
1. 添加依赖
首先,在 pubspec.yaml 文件中添加 taglib_ffi_dart 插件的依赖:
dependencies:
  flutter:
    sdk: flutter
  taglib_ffi_dart: ^0.1.0  # 请使用最新版本
然后运行 flutter pub get 来安装依赖。
2. 导入包
在你的 Dart 文件中导入 taglib_ffi_dart 包:
import 'package:taglib_ffi_dart/taglib_ffi_dart.dart';
3. 使用插件
你可以使用 TagLib 类来读取和编辑音频文件的元数据。
读取标签
void readTags() async {
  final tagLib = TagLib();
  // 打开音频文件
  final file = await tagLib.openFile('path/to/your/audiofile.mp3');
  // 读取标签
  final title = file.title;
  final artist = file.artist;
  final album = file.album;
  final year = file.year;
  final comment = file.comment;
  final genre = file.genre;
  final track = file.track;
  print('Title: $title');
  print('Artist: $artist');
  print('Album: $album');
  print('Year: $year');
  print('Comment: $comment');
  print('Genre: $genre');
  print('Track: $track');
  // 关闭文件
  file.close();
}
编辑标签
void editTags() async {
  final tagLib = TagLib();
  // 打开音频文件
  final file = await tagLib.openFile('path/to/your/audiofile.mp3');
  // 编辑标签
  file.title = 'New Title';
  file.artist = 'New Artist';
  file.album = 'New Album';
  file.year = 2023;
  file.comment = 'New Comment';
  file.genre = 'New Genre';
  file.track = 1;
  // 保存更改
  file.save();
  // 关闭文件
  file.close();
}
4. 处理异常
在使用 taglib_ffi_dart 时,可能会遇到文件无法打开或标签无法读取的情况。因此,建议在处理这些操作时添加异常处理:
void readTagsSafely() async {
  final tagLib = TagLib();
  try {
    final file = await tagLib.openFile('path/to/your/audiofile.mp3');
    print('Title: ${file.title}');
    file.close();
  } catch (e) {
    print('Error reading tags: $e');
  }
}
        
      
            
            
            
