Flutter周期性闹钟功能插件periodic_alarm的使用

发布于 1周前 作者 vueper 来自 Flutter

Flutter周期性闹钟功能插件periodic_alarm的使用

开始安装

在您的android/app/build.gradle文件中,确保包含以下配置:

android {
  compileSdkVersion 33
  [...]
  defaultConfig {
    [...]
    multiDexEnabled true
  }
}

之后,在您的AndroidManifest.xml文件中添加以下权限:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- For apps with targetSDK=31 (Android 12) -->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>

接着,在<application>标签内添加以下服务和接收器:

<service
    android:name="dev.fluttercommunity.plus.androidalarmmanager.AlarmService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="false"/>
<receiver
    android:name="dev.fluttercommunity.plus.androidalarmmanager.AlarmBroadcastReceiver"
    android:exported="false"/>
<receiver
    android:name="dev.fluttercommunity.plus.androidalarmmanager.RebootBroadcastReceiver"
    android:enabled="false"
    android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

最后,将音频资源添加到项目中。

如何使用

在您的pubspec.yaml文件中添加插件:

flutter pub add periodic_alarm

首先,在main函数中初始化插件:

await PeriodicAlarm.init();

然后,定义闹钟设置:

final alarmSettings = AlarmSettings(
  id: id,
  dateTime: dateTime,
  assetAudioPath: 'assets/alarm.mp3',
  loopAudio: true,
  fadeDuration: 3.0,
  notificationTitle: '这是标题',
  notificationBody: '这是内容',
  enableNotificationOnKill: true,
  monday: true,
  tuesday : true,
  wednesday : true,
  thursday : true,
  friday : true,
  saturday : true,
  sunday : true,
  active : true,
);

最后,设置闹钟:

await PeriodicAlarm.setOneAlarm(alarmModel: alarmModel);

属性说明

属性 类型 描述
id int 闹钟的唯一标识符。
dateTime DateTime 您希望闹钟响起的日期和时间。
assetAudioPath String 您希望用作铃声的音频资产路径。可以是本地资源或网络URL。
loopAudio bool 如果为真,则音频将无限重复播放,直到停止。
fadeDuration double 在多少秒内淡入淡出铃声音量。默认值为0,表示不淡入淡出。
notificationTitle String 当应用程序处于后台时触发的铃声通知标题。
notificationBody String 通知的内容。
enableNotificationOnKill bool 当应用程序被杀死时是否显示通知以警告用户可能无法响铃。默认启用。

完整示例

以下是完整的示例代码:

import 'package:flutter/material.dart';
import 'package:periodic_alarm/model/alarms_model.dart';
import 'dart:async';

import 'package:periodic_alarm/periodic_alarm.dart';
import 'package:periodic_alarm/services/alarm_notification.dart';
import 'package:periodic_alarm/services/alarm_storage.dart';
import 'package:periodic_alarm_example/view/alarm_screen.dart';
import 'package:periodic_alarm/src/android_alarm.dart';

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

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

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/',
      routes: {
        '/': (context) => HomePage(),
        '/alarmscreen': (context) => AlarmScreen()
      },
    );
  }
}

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

  [@override](/user/override)
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  StreamSubscription? _subscription;
  StreamSubscription? _subscription2;
  bool alarm = false;
  bool alarm1 = false;
  int? id;

  [@override](/user/override)
  void initState() {
    super.initState();
    // onRingingControl();
    PeriodicAlarm.init();
    configureSelectNotificationSubject();
  }

  [@override](/user/override)
  void dispose() {
    AndroidAlarm.audioPlayer.dispose();
    super.dispose();
  }

  configureSelectNotificationSubject() {
    _subscription2 ??= AlarmNotification.selectNotificationStream.stream
        .listen((String? payload) async {
      List<String> payloads = [];
      AlarmModel? alarmModel;
      payloads.add(payload!);
      payloads.forEach((element) {
        if (int.tryParse(element) != null) {
          id = int.tryParse(element);
          alarmModel = PeriodicAlarm.getAlarmWithId(id!);
          setState(() {});
        } else if (element == 'stop') {
          PeriodicAlarm.stop(id!);
        } else if (element == "") {
          openAlarmScreen();
        }
      });
    });
  }

  Future<void> setAlarm(int id, DateTime dt) async {
    AlarmModel alarmModel = AlarmModel(
        id: id,
        dateTime: dt,
        assetAudioPath: 'assets/0.mp3',
        notificationTitle: '闹钟来电',
        notificationBody: '点击关闭闹钟',
        // monday: true,
        // tuesday: true,
        // wednesday: true,
        // thursday: true,
        // friday: true,
        active: true,
        musicTime: 1,
        incMusicTime: 0.2272243957519531,
        musicVolume: 1,
        incMusicVolume:1);

    if (alarmModel.days.contains(true)) {
      PeriodicAlarm.setPeriodicAlarm(alarmModel: alarmModel);
    } else {
      PeriodicAlarm.setOneAlarm(alarmModel: alarmModel);
    }
  }

  openAlarmScreen() async {
    Future.delayed(Duration(seconds: 1), () async {
      var alarms = await AlarmStorage.getAlarmRinging();
      if (alarms.isNotEmpty) {
        Navigator.pushNamed(context, '/alarmscreen');
      }
    });
  }

  onRingingControl() {
    _subscription = PeriodicAlarm.ringStream.stream.listen(
      (alarmModel) async {
        openAlarmScreen();
        // if (alarmModel.days.contains(true)) {
        //   alarmModel.setDateTime = alarmModel.dateTime.add(Duration(days: 1));
        //   PeriodicAlarm.setPeriodicAlarm(alarmModel: alarmModel);
        // }
      },
    );

    setState(() {});
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('插件示例应用'),
      ),
      body: Center(
        child: Switch(
          value: alarm,
          onChanged: (value) {
            alarm = value;
            setState(() {});
            if (value) {
              setAlarm(0, DateTime.parse('2023-06-21 16:12:00.000'));
              // setAlarm(1, DateTime(2023, 4, 7, 21, 01, 00));
              // setAlarm(1, DateTime(2023, 4, 7, 19, 54 ,00));
              // setAlarm(1, 20);
            }
          },
        ),
      ),
    );
  }
}

更多关于Flutter周期性闹钟功能插件periodic_alarm的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter周期性闹钟功能插件periodic_alarm的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用Flutter中的periodic_alarm插件来实现周期性闹钟功能的代码示例。请注意,由于Flutter和插件生态系统会随时间变化,请确保您使用的是最新版本的插件,并参考官方文档进行必要的调整。

首先,确保在pubspec.yaml文件中添加periodic_alarm插件依赖:

dependencies:
  flutter:
    sdk: flutter
  periodic_alarm: ^最新版本号  # 请替换为实际最新版本号

然后,运行flutter pub get来安装依赖。

接下来,是一个完整的示例代码,展示了如何使用periodic_alarm插件来设置周期性闹钟:

import 'package:flutter/material.dart';
import 'package:periodic_alarm/periodic_alarm.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Periodic Alarm Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: AlarmScreen(),
    );
  }
}

class AlarmScreen extends StatefulWidget {
  @override
  _AlarmScreenState createState() => _AlarmScreenState();
}

class _AlarmScreenState extends State<AlarmScreen> {
  String _alarmStatus = "Alarm not set";

  @override
  void initState() {
    super.initState();
    // 检查是否有已设置的周期性闹钟
    _checkAndSetAlarm();
  }

  @override
  void dispose() {
    // 取消闹钟
    PeriodicAlarm.cancel(alarmId: 1);
    super.dispose();
  }

  Future<void> _checkAndSetAlarm() async {
    bool isAlarmSet = await PeriodicAlarm.isAlarmSet(alarmId: 1);
    if (isAlarmSet) {
      setState(() {
        _alarmStatus = "Alarm already set";
      });
    }
  }

  Future<void> _setPeriodicAlarm() async {
    // 设置一个每秒触发一次的周期性闹钟
    bool result = await PeriodicAlarm.setAlarm(
      alarmId: 1,
      repeatInterval: Duration(seconds: 1),
      alarmCallback: () async {
        // 闹钟触发时的回调
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: Text("Alarm Triggered"),
              content: Text("This is a periodic alarm."),
              actions: <Widget>[
                TextButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text('OK'),
                ),
              ],
            );
          },
        );
      },
    );

    if (result) {
      setState(() {
        _alarmStatus = "Alarm set successfully";
      });
    } else {
      setState(() {
        _alarmStatus = "Failed to set alarm";
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Periodic Alarm Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              _alarmStatus,
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _setPeriodicAlarm,
              child: Text('Set Periodic Alarm'),
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,它允许用户设置一个每秒触发一次的周期性闹钟。当闹钟触发时,会显示一个对话框。

注意

  • PeriodicAlarm.setAlarm方法用于设置周期性闹钟。alarmId用于唯一标识闹钟,repeatInterval指定了闹钟的触发间隔,alarmCallback是闹钟触发时的回调函数。
  • PeriodicAlarm.cancel方法用于取消指定的闹钟。
  • PeriodicAlarm.isAlarmSet方法用于检查是否有已设置的闹钟。

由于periodic_alarm插件可能需要特定的平台(如Android和iOS)权限和配置,请务必参考插件的官方文档进行必要的配置。此外,由于后台执行和电池优化策略的限制,某些设备或操作系统版本可能会限制或禁止后台任务的执行,这可能会影响闹钟的触发。

回到顶部