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

Flutter 三方库 flutter_local_notifications 的 OpenHarmony 鸿蒙化适配实践

引言

在移动应用开发中,本地通知是一个非常基础且重要的功能。通过本地通知,应用可以在后台向用户发送提醒、提醒用户完成某些操作或者向用户推送重要信息。flutter_local_notifications 作为 Flutter 生态中最流行的本地通知插件,以其简洁的 API、丰富的功能和强大的跨平台能力,成为众多开发者的首选。随着 OpenHarmony 生态的快速发展,如何在 Flutter-OH 项目中顺利集成和使用 flutter_local_notifications 成为开发者关注的重点。本文将详细介绍 flutter_local_notifications 在 OpenHarmony 平台上的适配实践,包括环境配置、核心功能使用、通知通道管理以及平台特定的注意事项。

一、环境准备与项目初始化

1.1 创建 Flutter-OH 项目

使用 Flutter 命令行工具创建支持 OpenHarmony 的新项目:

flutter create --platforms=ohos flutter_local_notifications_oh
cd flutter_local_notifications_oh

二、集成 flutter_local_notifications 依赖

2.1 添加依赖到 pubspec.yaml

在项目的 pubspec.yaml 文件中添加 flutter_local_notifications 和 timezone 依赖:

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.8
  flutter_local_notifications: ^17.2.1
  timezone: ^0.9.2

flutter_local_notifications 库是一个跨平台的本地通知插件,内部通过平台通道(Method Channel)与各平台的原生通知功能进行通信。对于 OpenHarmony 平台,该库已经提供了良好的支持。timezone 依赖用于处理定时通知的时区问题。

2.2 获取依赖

运行以下命令下载并安装依赖包:

flutter pub get

三、flutter_local_notifications 核心功能与 OpenHarmony 适配实践

3.1 初始化通知插件

flutter_local_notifications 的核心 API 设计简洁明了,首先需要初始化通知插件:

import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  tz.initializeTimeZones();
  
  runApp(const MyApp());
}

Future<void> initializeNotifications() async {
  const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
  const ohosSettings = OHOSInitializationSettings('@mipmap/ic_launcher');
  const initSettings = InitializationSettings(
    android: androidSettings,
    ohos: ohosSettings,
  );

  await _notifications.initialize(
    initSettings,
    onDidReceiveNotificationResponse: _onNotificationResponse,
  );
}

void _onNotificationResponse(NotificationResponse response) {
  print('通知被点击: ${response.payload}');
}

3.2 发送即时通知

发送即时通知是最基本的功能:

Future<void> showNotification() async {
  const androidDetails = AndroidNotificationDetails(
    'default_channel_id',
    '默认通知',
    channelDescription: '这是默认通知通道',
    importance: Importance.high,
    priority: Priority.high,
  );

  const ohosDetails = OHOSNotificationDetails(
    importance: Importance.high,
  );

  const notificationDetails = NotificationDetails(
    android: androidDetails,
    ohos: ohosDetails,
  );

  await _notifications.show(
    0,
    '通知标题',
    '通知内容',
    notificationDetails,
    payload: 'notification_payload',
  );
}

3.3 发送带声音的通知

可以配置通知的声音:

Future<void> showNotificationWithSound() async {
  const androidDetails = AndroidNotificationDetails(
    'sound_channel_id',
    '带声音通知',
    channelDescription: '这是带声音的通知通道',
    importance: Importance.high,
    priority: Priority.high,
    playSound: true,
  );

  const ohosDetails = OHOSNotificationDetails(
    importance: Importance.high,
  );

  const notificationDetails = NotificationDetails(
    android: androidDetails,
    ohos: ohosDetails,
  );

  await _notifications.show(
    0,
    '带声音通知',
    '这条通知带有提示音',
    notificationDetails,
  );
}

3.4 定时通知

使用 timezone 库实现定时通知:

Future<void> scheduleNotification() async {
  final scheduledTime = tz.TZDateTime.now(tz.local).add(Duration(seconds: 10));
  
  const androidDetails = AndroidNotificationDetails(
    'scheduled_channel_id',
    '定时通知',
    channelDescription: '这是定时通知通道',
    importance: Importance.high,
    priority: Priority.high,
  );

  const ohosDetails = OHOSNotificationDetails(
    importance: Importance.high,
  );

  const notificationDetails = NotificationDetails(
    android: androidDetails,
    ohos: ohosDetails,
  );

  await _notifications.zonedSchedule(
    0,
    '定时通知',
    '这条通知将在10秒后发送',
    scheduledTime,
    notificationDetails,
    androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
  );
}

3.5 大文本通知

可以发送包含更多内容的通知:

Future<void> showBigTextNotification() async {
  const androidDetails = AndroidNotificationDetails(
    'bigtext_channel_id',
    '大文本通知',
    channelDescription: '这是大文本通知通道',
    importance: Importance.high,
    priority: Priority.high,
    styleInformation: BigTextStyleInformation(
      '这是通知的详细内容。\n\n'
      '第一行内容...\n'
      '第二行内容...\n'
      '感谢使用 Flutter 本地通知!',
      contentTitle: '大文本通知',
      summaryText: '通知摘要',
    ),
  );

  const ohosDetails = OHOSNotificationDetails(
    importance: Importance.high,
  );

  const notificationDetails = NotificationDetails(
    android: androidDetails,
    ohos: ohosDetails,
  );

  await _notifications.show(0, '通知标题', '大文本通知已发送', notificationDetails);
}

3.6 取消通知

可以取消单条通知或所有通知:

// 取消单条通知
Future<void> cancelNotification(int id) async {
  await _notifications.cancel(id);
}

// 取消所有通知
Future<void> cancelAllNotifications() async {
  await _notifications.cancelAll();
}

四、完整示例应用

4.1 主页面实现

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

  
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final FlutterLocalNotificationsPlugin _notifications = FlutterLocalNotificationsPlugin();
  String _selectedType = '普通通知';
  final TextEditingController _titleController = TextEditingController(text: '通知标题');
  final TextEditingController _bodyController = TextEditingController(text: '这是通知的内容');
  final TextEditingController _delayController = TextEditingController(text: '5');
  
  int _notificationId = 0;

  
  void initState() {
    super.initState();
    _initializeNotifications();
  }

  Future<void> _initializeNotifications() async {
    const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
    const ohosSettings = OHOSInitializationSettings('@mipmap/ic_launcher');
    const initSettings = InitializationSettings(
      android: androidSettings,
      ohos: ohosSettings,
    );

    await _notifications.initialize(
      initSettings,
      onDidReceiveNotificationResponse: _onNotificationResponse,
    );

    await _requestPermissions();
  }

  Future<void> _requestPermissions() async {
    await _notifications
        .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
        ?.requestNotificationsPermission();
  }

  void _onNotificationResponse(NotificationResponse response) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('通知被点击'),
        content: Text('Payload: ${response.payload}'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('确定'),
          ),
        ],
      ),
    );
  }

  Future<void> _showNotification() async {
    _notificationId++;
    
    const androidDetails = AndroidNotificationDetails(
      'default_channel_id',
      '默认通知',
      channelDescription: '这是默认通知通道',
      importance: Importance.high,
      priority: Priority.high,
    );

    const ohosDetails = OHOSNotificationDetails(
      importance: Importance.high,
    );

    const notificationDetails = NotificationDetails(
      android: androidDetails,
      ohos: ohosDetails,
    );

    await _notifications.show(
      _notificationId,
      _titleController.text,
      _bodyController.text,
      notificationDetails,
      payload: 'notification_payload',
    );
  }

  Future<void> _scheduleNotification() async {
    final delay = int.tryParse(_delayController.text) ?? 5;
    final scheduledTime = tz.TZDateTime.now(tz.local).add(Duration(seconds: delay));
    
    const androidDetails = AndroidNotificationDetails(
      'scheduled_channel_id',
      '定时通知',
      channelDescription: '这是定时通知通道',
      importance: Importance.high,
      priority: Priority.high,
    );

    const ohosDetails = OHOSNotificationDetails(
      importance: Importance.high,
    );

    const notificationDetails = NotificationDetails(
      android: androidDetails,
      ohos: ohosDetails,
    );

    await _notifications.zonedSchedule(
      _notificationId++,
      _titleController.text,
      _bodyController.text,
      scheduledTime,
      notificationDetails,
      androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
      payload: 'scheduled_notification_payload',
    );
  }

  Future<void> _cancelAllNotifications() async {
    await _notifications.cancelAll();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('LocalNotifications OH 示例'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            _buildNotificationTypeSelector(),
            const SizedBox(height: 20),
            _buildNotificationContent(),
            const SizedBox(height: 20),
            _buildNotificationActions(),
          ],
        ),
      ),
    );
  }
}

五、OpenHarmony 平台特殊适配处理

5.1 权限配置

在 OpenHarmony 平台上,使用本地通知需要配置通知权限。在 ohos/entry/src/main/module.json5 中添加必要的权限声明:

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": ["phone", "tablet"],
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntrance": "./ets/entryability/EntryAbility.ets",
        "description": "$string:entry_ability_desc",
        "icon": "$media:app_icon",
        "label": "$string:entry_ability_label",
        "type": "page",
        "launchType": "standard"
      }
    ]
  }
}

5.2 通知通道

在 OpenHarmony 平台上,flutter_local_notifications 会自动创建通知通道。不同的通知类型可以使用不同的通道:

  • default_channel_id:默认通知通道
  • sound_channel_id:带声音的通知通道
  • scheduled_channel_id:定时通知通道
  • bigtext_channel_id:大文本通知通道

5.3 通知优先级

flutter_local_notifications 支持设置通知的优先级:

  • Priority.max:最高优先级
  • Priority.high:高优先级
  • Priority.default:默认优先级
  • Priority.low:低优先级
  • Priority.min:最低优先级

六、常见问题与解决方案

6.1 问题:通知不显示

原因分析

  • 通知权限未授权
  • 应用在后台被清理
  • 通知通道配置错误

解决方案

  • 检查并请求通知权限
  • 确保应用未被系统清理
  • 验证通知通道 ID
Future<void> _requestPermissions() async {
  await _notifications
      .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
      ?.requestNotificationsPermission();
}

6.2 问题:定时通知不触发

原因分析

  • 时区配置问题
  • 应用被清理
  • 定时器配置错误

解决方案

  • 确保正确初始化时区
  • 使用 exactAllowWhileIdle 模式
  • 检查定时器配置
await _notifications.zonedSchedule(
  0,
  '定时通知',
  '内容',
  scheduledTime,
  notificationDetails,
  androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
);

6.3 问题:通知声音不响

原因分析

  • 系统静音模式
  • 声音文件不存在
  • 权限配置问题

解决方案

  • 检查系统声音设置
  • 确保声音文件有效
  • 配置正确的通知设置

七、运行验证

7.1 构建命令

flutter build ohos
flutter run -d <device_id>

7.2 功能测试清单

确保测试以下功能点:

  • 即时通知发送
  • 带声音通知发送
  • 定时通知发送
  • 大文本通知发送
  • 单条通知取消
  • 所有通知取消
  • 通知点击响应
  • 权限请求

八、总结与扩展

通过本文的实践,我们成功完成了 flutter_local_notifications 库在 Flutter-OH 项目中的集成与适配。flutter_local_notifications 作为一个成熟的 Flutter 插件,在 OpenHarmony 平台上的适配相对平滑,开发者主要需要关注的是权限配置和通知通道管理。

8.1 核心要点回顾

  1. 环境配置:确保 Flutter 和 OpenHarmony SDK 版本兼容
  2. 依赖管理:在 pubspec.yaml 中正确添加 flutter_local_notifications 和 timezone 依赖
  3. API 使用:遵循库的设计规范,合理使用各种通知方法
  4. 平台适配:关注 OpenHarmony 特有的权限配置和通知通道
  5. 权限处理:做好权限请求和错误处理

8.2 进阶扩展方向

对于更复杂的通知需求,可以考虑以下方案:

  1. 周期性通知:使用 periodic 来实现重复通知
  2. 带操作按钮的通知:添加通知操作按钮
  3. 进度通知:显示下载或处理进度
  4. 通知分类:根据通知类型进行分类管理

flutter_local_notifications 虽然简单,但却是 Flutter 应用开发中不可或缺的工具。结合 OpenHarmony 平台的特性合理使用,可以为用户提供及时、准确的通知提醒,提升用户体验。希望本文能为正在进行鸿蒙化适配的开发者提供有价值的参考。

本文仓库地址:https://atomgit.com/your_username/flutter_local_notifications_oh


参考文献

  • flutter_local_notifications 官方文档:https://pub.dev/packages/flutter_local_notifications
  • timezone 官方文档:https://pub.dev/packages/timezone
  • OpenHarmony 官方文档:https://gitee.com/openharmony/docs
  • Flutter for OpenHarmony 文档:https://gitee.com/openharmony-sig/flutter
Logo

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

更多推荐