Flutter-电子书EPub解析Iridium

Iridium

Iridium 是一个功能强大的 Flutter 电子书阅读器组件集合,旨在提供高质量的电子书阅读体验。

📚 功能特点

  • 支持 EPUB 格式电子书的显示和阅读
  • 提供完整的阅读器 UI 组件
  • 可自定义的主题设置
  • 字体大小、行距等排版设置
  • 页面导航和进度显示
  • 可嵌入任何 Flutter 应用中

📦 包结构

该项目包含多个核心组件:

  • reader_widget: 即插即用的阅读器 Widget 组件
  • components/commons: 通用工具和辅助类
  • components/navigator: 导航和页面控制
  • components/opds: OPDS 目录支持
  • components/server: 服务器相关功能
  • components/shared: 共享组件
  • components/streamer: 流媒体处理
  • components/webview: Web 视图组件

🚀 快速开始

  1. 添加依赖到 pubspec.yaml:
yaml 复制代码
dependencies:
  iridium_reader_widget:
    path: path/to/iridium/reader_widget

1 加载EPUB

1. 从文件路径加载

EpubScreen.fromPath( filePath: "path/to/book.epub", location: "书签位置", settings: "100", // 字体大小设置 theme: "主题设置JSON" );

2. 从 File 对象加载

EpubScreen.fromFile( file: File("path/to/book.epub") );

3. 从 URI 加载

EpubScreen.fromUri( rootHref: "example.com/book.epub" );

加载完成后是BookScreen

  1. 阅读进度保存
  • 自动记录上次阅读位置
  • 支持书签功能
  • 可在不同设备间同步进度(使用 Firestore 存储时)
  1. 阅读设置
  • 字体大小调节
  • 主题切换
  • 自定义样式
  1. 交互功能
  • 文本选择
  • 页面导航
  • 进度跳转

2 读取EPUB

状态管理
  • 支持实时更新和状态同步
  • 使用 BLoC 模式管理主题和阅读器设置
  • 支持实时更新和状态同步
less 复制代码
  Widget buildWidgetWrapper(BuildContext context, Widget child,
          List<Link> spineItems, ServerStarted state) =>
      Stack(
        children: <Widget>[
          buildBackground(),
          child,
          Align(
            alignment: Alignment.bottomCenter,
            child: MultiBlocProvider(
              providers: [
                BlocProvider<ReaderThemeBloc>(
                  create: (_) => BlocProvider.of<ReaderThemeBloc>(context),
                ),
                BlocProvider<ViewerSettingsBloc>(
                  create: (_) => BlocProvider.of<ViewerSettingsBloc>(context),
                ),
              ],
              child: ReaderToolbar(
                readerContext: readerContext,
                onSkipLeft: publicationController.onSkipLeft,
                onSkipRight: publicationController.onSkipRight,
              ),
            ),
          ),
          // SafeArea(
          //   top: false,
          //   child: Align(
          //     alignment: Alignment.topCenter,
          //     child: ReaderAppBar(
          //       readerContext: readerContext,
          //       publicationController: publicationController,
          //     ),
          //   ),
          // ),
     
        ],
      );

1. 组件概述

这是一个用于 EPUB 电子书阅读的导航组件,文件名为 epub_navigator.dart 。它包含两个主要类:

  • EpubNavigator :继承自 PublicationNavigator 的 Widget 类
  • EpubNavigatorState :对应的 State 类,处理具体的导航逻辑
less 复制代码
@override
  Widget buildReaderView(List<Link> spine, ServerStarted serverState) =>
      PreloadPageView.builder(
        controller: epubController.pageController,
        scrollDirection: Axis.horizontal,
        // TODO Currently, with Hybrid Composition activated, preloadPagesCount > 1 provides erratic behavior.
        // To investigate!
        // preloadPagesCount: min(spine.length, 2),
        preloadPagesCount: 1,
        onPageChanged: epubController.onPageChanged,
        physics: const AlwaysScrollableScrollPhysics(),
        reverse: readerContext?.readingProgression?.isReverseOrder() ?? false,
        itemCount: spine.length,
        itemBuilder: (context, position) =>
            (Platform.isAndroid || Platform.isIOS)
                ? WebViewScreen(
                    address: serverState.address,
                    link: spine[position],
                    position: position,
                    readerContext: readerContext!,
                    publicationController: epubController,
                  )
                : const SizedBox.shrink(),
      );
}

主要特性:

  • 使用 PreloadPageView.builder 实现页面预加载
  • 水平滚动方向
  • 当前仅预加载 1 页(由于混合渲染模式下多页预加载存在问题)
  • 支持根据阅读方向反转页面顺序
  • 使用WebView来加载EPUB

3 功能解析

1. 整体架构
  • 采用了 Flutter 框架实现跨平台电子书阅读器
  • 主要支持 EPUB 和 CBZ 两种电子书格式
  • 使用 WebView 来渲染 EPUB 内容
  • 采用 BLoC 模式进行状态管理
2. 核心功能模块

阅读器导航

  • EpubNavigator 和 CbzNavigator 分别处理不同格式电子书的导航

  • 支持页面跳转、目录导航和书签功能

  • 通过 ReaderContext 管理阅读状态和上下文 EPUB 渲染

  • 使用 WebViewScreen 渲染 EPUB 内容

  • 支持自定义主题和排版设置

  • 实现了手势控制和页面切换 注释和高亮

  • 支持文本选择和高亮标注

  • 提供书签和注释功能

  • 可以保存和管理用户的标注 主题和设置

  • ReaderThemeBloc 管理阅读主题

  • ViewerSettingsBloc 处理阅读器设置

  • 支持自定义字体、颜色和排版

3. 关键类说明

EpubController

  • 控制 EPUB 阅读器的核心类

  • 管理页面控制器和阅读状态

  • 处理用户交互和导航 WebViewScreenState

  • 负责 EPUB 内容的渲染和显示

  • 处理 WebView 相关的事件和回调

  • 管理注释和高亮功能 ReaderContext

  • 维护阅读器的全局状态

  • 管理书签和注释

  • 处理阅读进度和位置信息

4. 特色功能
  • 支持多种电子书格式 (EPUB, CBZ)
  • 提供完整的注释和标注系统
  • 支持主题自定义和排版设置
  • 实现了跨平台兼容性
  • 提供流畅的阅读体验和手势控制
5. 数据持久化
  • 支持多种注释存储方式:
    • 内存存储 (InMemoryReaderAnnotationRepository)
    • SQLite 存储 (SqliteReaderAnnotationRepository)
    • Firestore 存储 (FirestoreReaderAnnotationRepository)

###页面跳转解析书签功能

webview_screen_state.dart

使用js的方式进行跳转 _jsApi?.openPage

scss 复制代码
   void _onPageFinished(InAppWebViewController controller, Uri? url) async {
    try {
      if (_jsApi == null || !mounted) {
        return;
      }
      // // 获取页面请求数据
      OpenPageRequest? openPageRequestData =
          _getOpenPageRequestFromCommand(readerContext.readerCommand);
      List<String> elementIds =
          readerContext.getElementIdsFromSpineItem(position);
      _jsApi?.setElementIds(elementIds);
      
      if (openPageRequestData != null) {
        _jsApi?.openPage(openPageRequestData);
      }

    // 如果存在跳转请求,执行页面跳转
      try {
        _jsApi?.setStyles(_readerThemeBloc.state.readerTheme,
            _viewerSettingsBloc.viewerSettings);
      } catch (e) {
        Fimber.d("Error setting styles", ex: e);
      }

      _updateSpineItemPosition(_currentSpineItemBloc.state);
      await _loadDecorations();
      await _loadBookmarks();
    } catch (e, stacktrace) {
      Fimber.d("Error in _onPageFinished", ex: e, stacktrace: stacktrace);
    }
  }


void _onPaginationInfo(PaginationInfo? paginationInfo) {
    if (currentSelectedSpineItem && paginationInfo != null) {
        // 更新书签
        _updateBookmarks(paginationInfo);
        // 通知当前位置变化
        readerContext.notifyCurrentLocation(paginationInfo, spineItem);
    }
}
  1. 直接跳转
  • 通过目录跳转到指定章节
  • 通过书签跳转到保存的位置
  • 通过进度条跳转到指定位置

文本选择和高亮标注

1 文本选择监听器在 simple_selection_listener.dart 中实现了基本的选择监听功能:

scss 复制代码
  @override
 void showHighlightPopup(Selection selection, HighlightStyle style, Color tint,
     {String? highlightId}) {
   _hideSelectionPopup();
   _highlightPopup = HighlightPopup(this);
   _highlightPopup!
       .showHighlightPopup(context, selection, style, tint, highlightId);
 }

Selection是选种的文本 HighlightStyle选择的样式 Color文本选种的颜色

  1. 文本选择:
  • 用户在WebView中选择文本时触发选择事件
  • SelectionListener监听选择事件并显示操作弹窗
  • 用户可以选择进行高亮标注或其他操作
  1. 高亮标注:
  • 用户选择高亮操作后,创建ReaderAnnotation对象保存标注信息
  • 使用annotationMarkTemplate生成高亮样式
  • 将高亮效果应用到WebView中的选中文本
  1. 标注管理:
  • 标注数据通过ReaderAnnotationRepository进行持久化存储
  • 支持查看、编辑和删除已有标注
  • 可以通过ReaderNavigationScreen查看所有标注列表

书签和注释功能实现 webview_screen_state.dart

加载书签功能使用**_jsApi?.initPagination()**

scss 复制代码
// 加载书签
Future<void> _loadBookmarks() async {
   _spineItemContext.bookmarks.addAll(
       await readerContext.readerAnnotationRepository.allWhere(
           predicate: AnnotationTypeAndDocumentPredicate(
               spineItem.href, AnnotationType.bookmark)));
   _jsApi?.initPagination();
}

注释功能在simple_selection_listener.dart

scss 复制代码
  @override
 void showAnnotationPopup(Selection selection,
     {HighlightStyle? style, Color? tint, String? highlightId}) async {
      // 隐藏其他弹窗
   hidePopup();
       // 清除文本选择
   jsApi?.clearSelection();
       
   // 设置默认样式和颜色
   style ??= HighlightStyle.highlight;
   tint ??= HighlightPopup.highlightTints[0];
       
   // 获取已有注释(如果是编辑模式)
   ReaderAnnotation? highlight;
   if (highlightId != null) {
     highlight = await readerAnnotationRepository.get(highlightId);
     style = highlight?.style ?? style;
     tint = highlight?.tint?.let((it) => Color(it)) ?? tint;
   }
       // 显示注释弹窗
   if (state.mounted) {
     AnnotationPopup.showAnnotationPopup(context, this, selection, style, tint,
         highlight?.annotation, highlightId);
   }
 }
}
相关推荐
excel6 分钟前
前端必备:从能力检测到 UA-CH,浏览器客户端检测的完整指南
前端
前端小巷子13 分钟前
Vue 3全面提速剖析
前端·vue.js·面试
悟空聊架构20 分钟前
我的网站被攻击了,被干掉了 120G 流量,还在持续攻击中...
java·前端·架构
CodeSheep21 分钟前
国内 IT 公司时薪排行榜。
前端·后端·程序员
尖椒土豆sss25 分钟前
踩坑vue项目中使用 iframe 嵌套子系统无法登录,不报错问题!
前端·vue.js
遗悲风26 分钟前
html二次作业
前端·html
江城开朗的豌豆29 分钟前
React输入框优化:如何精准获取用户输入完成后的最终值?
前端·javascript·全栈
CF14年老兵30 分钟前
从卡顿到飞驰:我是如何用WebAssembly引爆React性能的
前端·react.js·trae
画月的亮33 分钟前
前端处理导出PDF。Vue导出pdf
前端·vue.js·pdf
江城开朗的豌豆39 分钟前
拆解Redux:从零手写一个状态管理器,彻底搞懂它的魔法!
前端·javascript·react.js