如何使用 Flutter 让后台应用每天下午 2 点打开一个对话框?
Posted
技术标签:
【中文标题】如何使用 Flutter 让后台应用每天下午 2 点打开一个对话框?【英文标题】:How to make a background app open a dialog box every day at 2pm with Flutter? 【发布时间】:2021-09-25 07:22:57 【问题描述】:我希望应用在每天下午 2 点打开一个对话框,即使用户正在执行其他操作并且此时当前不在应用界面中。
如何使用 Flutter 做到这一点,使其同时适用于 android 和 ios?
我在想这样的方法:
timer = Timer.periodic(Duration(seconds: 60), (Timer t) => checkTime());
每分钟检查一次是否在 14:00:00 到 14:00:59 之间,方法类似于 flutter run function every x amount of seconds,但这似乎是一种资源浪费:可能有更好、更自然的方式在精确的时间在后台唤醒应用程序?
问题:如何使用 Flutter 让应用在每天下午 2 点显示对话框,即使用户正在执行其他操作/在另一个应用中?
注意:如果设备的屏幕关闭(即用户没有使用手机),下次打开屏幕时应显示对话框。
【问题讨论】:
Android 平台不允许从后台为在 Android 10 或更高版本上运行的应用程序打开活动。见developer.android.com/guide/components/activities/…。理想的情况是使用 AlarmManager Service Api 或 JobScheduler 或 WorkManager Api 来安排通知。 感谢@NikhilJain!您能否发布一个带有示例代码的答案,展示如何使用 Flutter(Android + iOS)做到这一点? 虽然我没有在 Flutter 上尝试过,但你可以参考这个链接 - medium.com/@fuzzymemory/… 。如果您遇到任何问题,请告诉我。 @Basj 发布了一个答案,让我知道它是否符合您的要求。 【参考方案1】:我的解决方案是使用 workmanager
(当前版本 0.4.1) 颤振包来实现您正在寻找的要求。由于它由 Flutter 社区团队 维护,我们可以期待长期支持。
根据他们的文档
Flutter WorkManager 是 Android's WorkManager 和 iOS' performFetchWithCompletionHandler 的包装器,有效地实现了无头 在后台执行 Dart 代码。
这对于运行定期任务特别有用,例如定期获取远程数据。
Android 工作管理器会根据其运行的版本的操作系统级别自动处理后台进程。
来到 iOS, 根据他们的文档,此包用于执行后台操作的功能已被弃用。但Flutter 社区团队已准备好根据 GitHub 存储库中的comment 在即将发布的版本中推送替换。所以升级到最新版本将帮助您解决这个问题。
初始化main()
内的wrokmanager
Workmanager().initialize(
callbackDispatcher, // The top level function, aka callbackDispatcher
isInDebugMode:
true // If enabled it will post a notification whenever the task is running. Handy for debugging tasks
);
然后像下面这样安排任务
Workmanager().registerOneOffTask("1", "simpleTask_1",
initialDelay: Duration(seconds: 15));
Workmanager().registerPeriodicTask("102", "simplePeriodicTask_1",
initialDelay: Duration(seconds: 15),
frequency: Duration(minutes: 15)); // Set your 2 PM frequency here.
请参阅documentation and setup,了解有关计划任务的可用选项。
并定义一个callbackDispatcher
,它必须是静态函数或***函数,才能根据文档作为 Flutter 入口点进行访问。
//Defined outside main()
void callbackDispatcher()
Workmanager().executeTask((task, inputData)
print(
"Native called background task: callbackDispatcher"); //simpleTask will be emitted here.
createNotify(); // Created a local notification to make sure everything works in background - In your case show alert here.
return Future.value(true);
);
// your main() goes here
不显示通知,而是推导出您的逻辑以显示警报弹出窗口。
编辑 1:
在 cmets 中回答您的问题
您如何检查程序仅在每天 14:00:00 左右运行一次 下午?
计划的工作存储在内部管理的 SQLite 数据库中,WorkManager 负责确保此工作持续并在设备重启后重新计划。而且这会被执行多次,直到被手动取消。
除此之外,出于开发目的,您可以设置最小间隔并验证一次,例如 1 小时。工作经理支持的最小间隔为 15 分钟。即使您将时间设置为低于该阈值时间,也会将 15 分钟设置为默认值。
您的代码似乎会定期运行,但不会以 具体时间。
目前还不支持开箱即用。但我们可以在调度任务时利用初始延迟。计算当前时间与您要触发的时间之间的时间差。 例如,如果我想在 9 点安排一些任务并且在安排任务时可以执行以下操作 当应用程序在 7 点打开时,将初始延迟设置为两个小时。 请参考与此相关的*** answer。
还有,用这个方法,你确定不会自动关闭吗 由操作系统来节省电池?
根据 WorkManager doc,执行将在我们指定的时间间隔内发生。由于WorkManager 会受到操作系统电池优化的影响,例如打盹模式e,我们需要注意执行可能会延迟但不会取消。
最后一件事:后台进程能否在没有用户的情况下启动弹出窗口 相互作用? (其他答案提到这实际上是不可能的)。谢谢 又来了!
对我来说,这是最棘手的部分。从技术上讲,如果没有来自后台的用户操作,我们就无法显示 UI。因为,UI 需要 context
基于它显示给用户。所以来到dart
点,可能很难显示您正在寻找的一些警报弹出窗口。但是如果你只想显示某种信息,你可以试试FlutterToast
,因为它会从后台显示给用户。
编辑 2
当应用程序未打开时,您寻求显示警报的要求称为 Draw over other apps,据我猜测,它仅适用于 Android因为 iOS 中没有这样的功能。
您可以参考这个package 在颤振中根据您的要求显示警报。将WorkManager
与此包实现结合起来以实现您想要的结果。我没有尝试过这个包,但如果你遇到任何问题,请告诉我。
编码愉快!!
【讨论】:
感谢您的回答。您如何检查程序仅在每天下午 14:00:00 左右运行一次?您的代码似乎会定期运行,但不会在特定时间运行。另外,使用这种方法,您确定它不会被操作系统自动关闭以节省电池吗? (因为它一直运行只是为了执行小时检查)。最后一件事:后台进程可以在没有用户交互的情况下启动弹出窗口吗? (其他答案提到这实际上是不可能的)。再次感谢! 请参考我的 EDIT 1 在我对您问题的回答中。 @Basj【参考方案2】:TL、DR:使用alarm_manager_service。它可以在特定时间安排任务,如果需要,可以在从该开始时间设置的持续时间后重复。
您计划在主应用程序中包含完整代码。问题是,不能保证应用程序不会被 Android 操作系统关闭。借助电源管理功能(打瞌睡),该应用程序可能会在数小时内被杀死。最近的 android 版本为用户提供了明确的控制权。用户将不得不原谅这个应用程序的电源优化(禁用电池优化)。即便如此,RAM 管理可以在危急情况下杀死应用程序。这是预期的行为。
现在,关于在前台显示界面:Android 似乎也阻止了侵入性应用行为,例如在用户与其他 Activity 交互时将 Activity 带到前台会阻碍用户。见https://developer.android.com/guide/components/activities/background-starts。它还列出了例外情况,您可以借此实现这一目标。 (我知道 Facebook/messenger 过去常常这样做以及各种后台活动,即使在不尊重建议的情况下杀死任务后也是如此。但我们大多数人都讨厌 FB 应用程序过于侵入性,并且给了我不道德的印象)。
为了检查一天中的特定时间而连续运行应用程序肯定是浪费资源。
因此,除了主 GUI 应用程序代码之外,您还必须注册 background service。 Dart 应用程序作为隔离运行。 You can create a separate isolate 用于除了用户与之交互的主 GUI 之外的后台服务。现在,即使主 GUI 隔离关闭,后台服务也可以运行。
在执行这些操作时,您还需要修改 android 清单文件。我可以为您指出一些线索: 使用alarm_manager_service 在设定的时间安排后台任务。然后可以回调以执行活动并显示对话框或唤醒应用程序。
另一个:workmanager
Read this quick and to the point summary 作为自述文件描述以了解 android OS 中的现有场景。这实际上总结了我通过无数 developer.android 文章阅读的所有内容。
示例代码:
您可以使用警报管理器将任务安排在特定时间,也可以在从开始时间设置的持续时间后重复执行 ~> 从某天下午 2 点开始,每 24 小时定期重复一次。
使用 alarm_manager 的代码给出here 作为答案(解决方案1)。
【讨论】:
谢谢@MelvinCalvin。 “该应用程序可能会在数小时内被杀死”,为了清楚起见,您是在说一般情况还是仅在我的代码示例中使用timer
的情况?为了完整起见,您能否提供一个示例代码来说明您将如何做到这一点?
另外,alarm_manager_service
似乎对于计划在 x 秒、分钟或小时内运行的任务很有用。这不完全是我需要的。相反,我希望在每天的准确时间(例如下午 14:00:00)显示一个对话框。
我也面临这个麻烦。我的主应用程序使用一个计时器,该计时器旨在从用户开始运行到用户停止。因为,我的应用程序很轻,所以我没有费心为定期服务创建背景隔离,这在您的情况下是理想的。但是我必须在安装后通过更改应用程序的节电设置来使其工作。否则,在退出、切换应用程序或屏幕锁定几分钟后,它会一直关闭。这只会保存应用程序,直到发生内存紧急情况,此时操作系统有权强制关闭应用程序。就是这种情况(无论使用定时器
我无法共享工作代码,因为我仍在努力制作另一个使用后台隔离的应用程序。 Dart 应用程序作为隔离运行。您可以为后台服务创建后台隔离。这就是我建议您以使计划正确有效地运行的方法。在这一点上,我只有文章和讨论要分享,我正在阅读以使其发挥作用。
好的@MelvinCalvin!如果您找到解决方案,请发布更新:)【参考方案3】:
我也有过类似的需求,而且画在其他应用上的需求是一件很困难的事情。
但我找到了一个可以接受的解决方案,使用 flutter_local_notifications 包。您可以安排定期通知,并且可以启用“fullScreenIntent”。这个链接应该有帮助:https://pub.dev/packages/flutter_local_notifications#full-screen-intent-notifications
它并不完美,但为了完美,您必须使用 PlatformChannels 编写本机代码:
https://flutter.dev/docs/development/platform-integration/platform-channels
【讨论】:
【参考方案4】:如果您的目标是为 iOS 设备用户自动打开应用程序。好吧,那是不可能的。我不确定 Android 是否也可以。
您可能希望创建一个在 14:00 推送的通知,询问用户是否要打开对话框。
这是 FlutterFire 中通知的文档链接:Notifications
以及 Flutter 小部件的文档(您需要 Xcode):Develop an iOS 14 Widget in Flutter with SwiftUI
【讨论】:
我认为这是可能的,因为例如 Facebook 应用程序能够显示“聊天头”,即使您在 FB 应用程序中不,例如,如果您是在设备桌面上:example。那么显示一个对话框应该是可能的吧? “你可能想创建一个通知在 14:00 推送,询问用户是否要打开对话框。”:你如何使用 Flutter 做到这一点,这样它就可以在 iOS 和 Android 上运行@PierreJanineh? 在 Facebook 应用程序之外的哪里可以看到聊天头像? 如果您希望始终在主屏幕上显示数据,可以使用小部件扩展。 感谢@PierreJanineh 的更新。您是否有一个用于通知的 Flutter 代码示例,一旦单击该通知,就会打开一个带有输入的对话框?以上是关于如何使用 Flutter 让后台应用每天下午 2 点打开一个对话框?的主要内容,如果未能解决你的问题,请参考以下文章