欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net

目录

前言:跨生态开发的新机遇

在移动开发领域,Flutter凭借其跨平台优势为开发者带来了高效的开发体验。随着鸿蒙生态的迅速崛起,将Flutter应用适配到OpenHarmony平台成为了开发者面临的新挑战与机遇。

本次开发聚焦于在OpenHarmony平台上实现Flutter第三方库flutter_html的富文本/HTML内容展示功能。通过组件化开发方式,我们成功实现了灵活的富文本展示效果,并确保了在OpenHarmony环境下的稳定运行。

混合工程结构深度解析

项目目录架构

当Flutter项目集成鸿蒙支持后,典型的项目结构会发生显著变化。以下是经过ohos_flutter插件初始化后的项目结构:

my_flutter_harmony_app/
├── lib/                          # Flutter业务代码(基本不变)
│   ├── main.dart                 # 应用入口
│   ├── components/               # 组件目录
│   │   └── html_viewer.dart      # 富文本/HTML展示组件
├── pubspec.yaml                  # Flutter依赖配置
├── ohos/                         # 鸿蒙原生层(核心适配区)
│   ├── entry/                    # 主模块
│   │   └── src/main/
│   │       ├── ets/              # ArkTS代码
│   │       │   ├── entryability/
│   │       │   │   └── EntryAbility.ets
│   │       │   └── pages/
│   │       │       └── Index.ets
│   │       ├── resources/        # 鸿蒙资源文件
│   │       └── module.json5
│   ├── hvigor/                   # 构建配置
│   └── oh-package.json5          # 鸿蒙依赖管理
└── README.md

展示效果图片

  • Flutter 实时预览效果展示

  • 在这里插入图片描述

  • 运行到鸿蒙虚拟设备中效果展示
    在这里插入图片描述

引入第三方库 flutter_html

在项目中引入flutter_html库非常简单,只需在pubspec.yaml文件中添加依赖即可:

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.8
  flutter_html: ^3.0.0  # 添加flutter_html依赖
  url_launcher: ^6.2.5  # 添加url_launcher依赖,用于处理链接点击

添加依赖后,运行flutter pub get命令来获取库文件。

功能代码实现

富文本/HTML展示组件

组件结构与实现

我们创建了HtmlViewer组件,实现了富文本/HTML内容展示功能。该组件位于lib/components/html_viewer.dart文件中:

import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:url_launcher/url_launcher.dart';

class HtmlViewer extends StatefulWidget {
  const HtmlViewer({super.key});

  
  State<HtmlViewer> createState() => _HtmlViewerState();
}

class _HtmlViewerState extends State<HtmlViewer> {
  // 示例HTML内容
  final String _htmlContent = '''
  <h1>Flutter Html 富文本展示</h1>
  <p>这是一个使用 <strong>flutter_html</strong> 库实现的富文本展示示例。</p>
  
  <h2>支持的功能</h2>
  <ul>
    <li>标题标签 (h1-h6)</li>
    <li>段落标签 (p)</li>
    <li>强调标签 (strong, em)</li>
    <li>列表标签 (ul, ol, li)</li>
    <li>链接标签 (a)</li>
    <li>图片标签 (img)</li>
    <li>表格标签 (table)</li>
  </ul>
  
  <h2>链接示例</h2>
  <p>访问 <a href="https://flutter.dev">Flutter官方网站</a> 了解更多信息。</p>
  
  <h2>图片示例</h2>
  <p>Flutter logo:</p>
  <img src="https://flutter.dev/assets/flutter-lockup-4cb0ee072ab312e59784d9fbf4fb7ad42688a7fdaea1270ccf6bbf4f34b7e03f.svg" alt="Flutter Logo" width="200" height="80">
  
  <h2>表格示例</h2>
  <table border="1" cellpadding="5" cellspacing="0">
    <tr>
      <th>姓名</th>
      <th>年龄</th>
      <th>职业</th>
    </tr>
    <tr>
      <td>张三</td>
      <td>25</td>
      <td>工程师</td>
    </tr>
    <tr>
      <td>李四</td>
      <td>30</td>
      <td>设计师</td>
    </tr>
  </table>
  
  <h2>样式示例</h2>
  <p style="color: blue; font-size: 16px;">这段文字是蓝色的,字体大小为16px。</p>
  <p style="background-color: #f0f0f0; padding: 10px; border-radius: 5px;">这段文字有灰色背景和内边距。</p>
  ''';

  // 记录点击的链接
  String? _lastClickedLink;

  // 处理链接点击
  void _handleLinkTap(String? url, Map<String, String> attributes, element) async {
    if (url == null) return;
    
    setState(() {
      _lastClickedLink = url;
    });
    
    // 显示SnackBar提示
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('你点击了链接: $url'),
        duration: const Duration(seconds: 2),
      ),
    );
    
    // 尝试打开链接
    if (await canLaunch(url)) {
      await launch(url);
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('无法打开链接: $url'),
          duration: const Duration(seconds: 2),
        ),
      );
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('富文本/HTML内容展示'),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              'HTML内容展示:',
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 20),
            
            // 使用flutter_html展示HTML内容
            Html(
              data: _htmlContent,
              onLinkTap: _handleLinkTap,
              style: {
                'h1': Style(
                  fontSize: FontSize.xLarge,
                  fontWeight: FontWeight.bold,
                  color: Colors.deepPurple,
                ),
                'h2': Style(
                  fontSize: FontSize.large,
                  fontWeight: FontWeight.bold,
                  color: Colors.deepPurple,
                ),
                'p': Style(
                ),
                'ul': Style(
                ),
                'table': Style(
                  border: Border.all(color: Colors.grey),
                ),
                'th': Style(
                  backgroundColor: Colors.grey[200],
                ),
                'td': Style(
                ),
                'a': Style(
                  color: Colors.blue,
                  textDecoration: TextDecoration.underline,
                ),
              },
            ),
            
            const SizedBox(height: 30),
            
            // 显示最后点击的链接
            if (_lastClickedLink != null)
              Container(
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  color: Colors.deepPurple.withOpacity(0.1),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      '最后点击的链接:',
                      style: TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(height: 8),
                    Text(
                      _lastClickedLink!,
                      style: const TextStyle(
                        fontSize: 14,
                        color: Colors.blue,
                        decoration: TextDecoration.underline,
                      ),
                    ),
                  ],
                ),
              ),
            
            const SizedBox(height: 30),
            
            // 交互提示
            Center(
              child: Text(
                '点击上面的链接查看交互效果',
                style: TextStyle(
                  fontSize: 14,
                  color: Colors.grey[600],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

核心功能说明

  1. HTML内容展示:使用Html组件展示HTML内容,支持多种HTML标签和样式,包括标题、段落、列表、链接、图片和表格等。

  2. 链接点击处理:通过onLinkTap回调函数处理链接点击事件,显示SnackBar提示并尝试打开链接,增强用户交互体验。

  3. 样式定制:通过style参数定制HTML元素的样式,包括字体大小、颜色、背景色等,确保在不同设备上的显示效果一致。

  4. 状态管理:使用setState管理最后点击的链接,实时更新UI显示,确保界面与数据的同步。

  5. 滚动支持:使用SingleChildScrollView确保长内容可以正常滚动,提升用户体验。

使用方法

main.dart文件中,我们直接将HtmlViewer组件作为首页显示:

import 'package:flutter/material.dart';
import 'package:aa/components/html_viewer.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter for openHarmony',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      debugShowCheckedModeBanner: false,
      home: const MyHomePage(title: 'Flutter for openHarmony'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  
  Widget build(BuildContext context) {
    return const HtmlViewer();
  }
}

开发中需要注意的点

  1. 依赖管理flutter_html库可能依赖其他包,需要确保所有依赖都正确安装,特别是url_launcher库,用于处理链接点击事件。

  2. 版本兼容性:不同版本的flutter_html库API可能有所不同,需要注意版本兼容性,避免因API变更导致的编译错误。

  3. 样式定制:根据实际需求定制HTML元素的样式,确保在不同设备上的显示效果一致,提升用户体验。

  4. 性能优化:对于复杂的HTML内容,可能会影响性能,建议合理使用缓存和懒加载,提升应用运行速度。

  5. OpenHarmony适配:确保在OpenHarmony环境下测试HTML内容的显示效果,特别是图片和表格等复杂元素,确保跨平台体验一致。

本次开发中容易遇到的问题

  1. 依赖冲突问题

    • 问题flutter_html库可能与其他依赖包产生冲突,导致编译失败。
    • 解决方案:使用兼容的依赖版本,或通过dependency_overrides解决冲突,确保所有依赖包版本兼容。
  2. 链接点击问题

    • 问题:点击链接无反应,无法打开浏览器。
    • 解决方案:添加url_launcher依赖,并正确实现onLinkTap回调函数,确保链接点击事件被正确处理。
  3. 样式显示问题

    • 问题:HTML样式在不同平台上显示不一致,影响用户体验。
    • 解决方案:使用flutter_htmlstyle参数统一设置样式,避免依赖HTML自带样式,确保跨平台显示效果一致。
  4. 图片加载问题

    • 问题:网络图片无法加载或加载缓慢,影响页面美观度。
    • 解决方案:确保网络连接正常,考虑使用图片缓存库优化加载速度,提升用户体验。
  5. API变更问题

    • 问题flutter_html库不同版本的API可能有所不同,导致编译错误。
    • 解决方案:根据使用的库版本,查阅相关文档,使用正确的API,避免因API变更导致的编译错误。
  6. OpenHarmony平台适配问题

    • 问题:在OpenHarmony环境下,某些HTML元素显示异常,影响用户体验。
    • 解决方案:针对OpenHarmony平台进行测试,必要时对特定元素进行特殊处理,确保在OpenHarmony环境下的显示效果良好。

总结本次开发中用到的技术点

  1. Flutter组件化开发

    • 使用StatefulWidget创建可复用的富文本展示组件,提高代码的可维护性和可复用性
    • 通过抽离组件,使代码结构更加清晰,便于后续扩展和维护
  2. 第三方库集成

    • 集成flutter_html库实现HTML内容展示,支持多种HTML标签和样式
    • 集成url_launcher库处理链接点击,实现浏览器打开功能
    • 正确配置依赖版本,确保库的稳定性和兼容性
  3. HTML内容处理

    • 支持多种HTML标签和属性,包括标题、段落、列表、链接、图片和表格等
    • 定制HTML元素的样式,确保在不同设备上的显示效果一致
    • 处理HTML中的链接点击事件,实现交互功能
  4. 用户交互

    • 使用onLinkTap回调函数处理链接点击,增强用户交互体验
    • 通过ScaffoldMessenger显示用户反馈,提升应用的友好性
    • 实现链接点击后的浏览器打开功能,方便用户访问外部资源
  5. 状态管理

    • 使用setState管理组件状态,实现UI与数据的同步
    • 实现最后点击链接的记录和显示,提升用户体验
  6. UI设计

    • 使用SingleChildScrollView实现内容滚动,确保长内容可以正常显示
    • 设计美观的布局和交互效果,提升用户体验
    • 确保在不同屏幕尺寸上的良好显示效果,实现响应式布局
  7. OpenHarmony适配

    • 确保Flutter代码在OpenHarmony环境下正常运行,验证跨平台兼容性
    • 测试并优化在OpenHarmony设备上的用户体验,确保应用在鸿蒙生态中表现良好
    • 处理平台特定的显示问题,确保跨平台体验一致

通过本次开发,我们成功实现了在OpenHarmony平台上使用Flutter第三方库flutter_html的富文本/HTML内容展示功能,为Flutter应用在OpenHarmony生态中的落地提供了实践参考。该实现不仅功能完整,而且代码结构清晰,用户体验良好,展示了Flutter跨平台开发的优势。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐