如何使用 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 做到这一点,使其同时适用于 androidios

我在想这样的方法:

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 WorkManageriOS' 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 点打开一个对话框?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过后台服务每天在android中的特定时间重复通知

如何从应用程序后台录制视频:Android

如何在后台使用 Flutter Method Channel(应用最小化/关闭)

如何在 Flutter 中创建服务以使应用始终在后台运行?

如何在 Flutter 应用程序的后台运行代码?

我需要让我的应用程序总是在后台运行。