You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Flutter本地通知设置基于任务名称的自定义语音提示音

实现动态任务名称语音通知方案

针对你开发的视障人群任务管理App,要实现通知提示音随任务名称动态变化,核心是为每个任务生成专属语音文件,并在通知触发时调用对应文件。以下是具体修改方案:

1. 依赖准备

添加path_provider依赖用于获取应用私有存储路径(避免权限问题),在pubspec.yaml中添加:

dependencies:
  path_provider: ^2.1.2

2. 修改任务添加逻辑,生成唯一语音文件

在AddTasksscreen的onDoubleTap方法中,为每个任务生成唯一语音文件,并将文件路径存入数据库:

onDoubleTap: () async {
  // 生成唯一文件名(用时间戳避免重复)
  String soundFileName = "task_${DateTime.now().millisecondsSinceEpoch}.mp3";
  // 获取应用私有存储目录
  Directory appDir = await getApplicationDocumentsDirectory();
  String soundFilePath = "${appDir.path}/$soundFileName";

  // 生成任务名称的语音文件
  await Tts.synthesizeToFile(titleController.text, soundFilePath);

  // 插入任务时同步存储音频文件名
  int response = await sqlDb.insertdataToDatabase('''
        INSERT INTO tasks ( title , description , date, sound_file )
        VALUES ("${titleController.text}","${descriptionController.text}","${dateController.text}","$soundFileName")
             ''');
  if (response > 0) {
    Navigator.of(context).pushAndRemoveUntil(
        MaterialPageRoute(builder: (context) => TasksListScreen()),
        (route) => false);

    // 调用通知服务时传入音频文件路径
    NotificationService().scheduleNotification(
        id: bookcubit.get(context).id,
        title: titleController.text,
        body: descriptionController.text,
        soundFilePath: soundFilePath,
        DataTime: DateTime.parse(dateController.text));
  }
}

3. 更新NotificationService,支持动态声音

修改NotificationService类,让通知配置可以接收动态音频文件路径,适配Android和iOS平台:

class NotificationService {
  final FlutterLocalNotificationsPlugin notificationsPlugin =
      FlutterLocalNotificationsPlugin();

  Future<void> initNotification() async {
    AndroidInitializationSettings initializationSettingsAndroid =
        const AndroidInitializationSettings('appicon');

    var initializationSettingsIOS = DarwinInitializationSettings(
        requestAlertPermission: true,
        requestBadgePermission: true,
        requestSoundPermission: true,
        onDidReceiveLocalNotification:
            (int id, String? title, String? body, String? payload) async {});

    var initializationSettings = InitializationSettings(
        android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
    await notificationsPlugin.initialize(initializationSettings,
        onDidReceiveNotificationResponse:
            (NotificationResponse notificationResponse) async {});
  }

  // 动态生成通知配置,支持传入音频路径
  Future<NotificationDetails> notificationDetails({String? soundFilePath}) async {
    AndroidNotificationDetails androidDetails;
    if (soundFilePath != null) {
      // Android使用Uri指向应用内存储的音频文件
      androidDetails = AndroidNotificationDetails(
        'channelId', 
        'channelName',
        importance: Importance.max,
        sound: UriAndroidNotificationSound(Uri.parse(soundFilePath)),
      );
    } else {
      androidDetails = const AndroidNotificationDetails(
        'channelId', 
        'channelName',
        importance: Importance.max,
      );
    }

    DarwinNotificationDetails iosDetails;
    // iOS建议利用系统VoiceOver自动播报通知内容,自定义声音需满足格式/目录要求
    iosDetails = DarwinNotificationDetails(
      subtitle: title, // VoiceOver会自动播报通知标题和内容
      sound: soundFilePath?.split('/').last, // 需将文件放到Library/Sounds目录才生效
    );

    return NotificationDetails(android: androidDetails, iOS: iosDetails);
  }

  Future showNotification(
      {int id = 0, String? title, String? body, String? payLoad, String? soundFilePath}) async {
    SqlDb db = SqlDb();
    await db.deleteDatabase('DELETE FROM tasks WHERE id = $id');
    return notificationsPlugin.show(
        id, title, body, await notificationDetails(soundFilePath: soundFilePath));
  }

  Future scheduleNotification({
    int? id,
    String? title,
    String? body,
    String? payload,
    required DateTime DataTime,
    String? soundFilePath,
  }) async {
    return notificationsPlugin.zonedSchedule(
        id!,
        title,
        body,
        tz.TZDateTime.from(
          DataTime,
          tz.local,
        ),
        await notificationDetails(soundFilePath: soundFilePath),
        androidAllowWhileIdle: true,
        uiLocalNotificationDateInterpretation:
            UILocalNotificationDateInterpretation.absoluteTime);
  }
}

4. 数据库结构调整

需要给tasks表新增sound_file字段,用于存储音频文件名:

ALTER TABLE tasks ADD COLUMN sound_file TEXT;

5. 可选:清理过期音频文件

为避免存储冗余,删除任务时同步删除对应的语音文件:

Future<void> deleteTaskWithSound(int taskId, String soundFileName) async {
  SqlDb db = SqlDb();
  await db.deleteDatabase('DELETE FROM tasks WHERE id = $taskId');
  
  Directory appDir = await getApplicationDocumentsDirectory();
  String soundFilePath = "${appDir.path}/$soundFileName";
  File soundFile = File(soundFilePath);
  if (await soundFile.exists()) {
    await soundFile.delete();
  }
}

注意事项

  • Android平台:动态生成的音频文件存储在应用私有目录,无需额外权限
  • iOS平台:自定义通知声音需满足格式(.aiff/.wav/.caf)、大小(≤30秒),且需放到Library/Sounds目录;更推荐依赖系统VoiceOver自动播报通知内容,无需额外生成音频

内容的提问来源于stack exchange,提问作者Amar Mira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 04:15:02