Android Alarm Manager在Flutter项目应用中无法工作

21

错误 我在我的 Flutter 应用程序中安装了 Android Alarm Manager 插件。我尝试使用插件的示例代码,但在控制台中出现错误。

请建议如何使 Android Alarm Manager 插件正常工作。 如何将 Dart 的 android_alarm_manager 集成到应用程序中,以便用户在所选时间表达到时收到警报?

我使用来自以下链接的代码: https://github.com/flutter/plugins/tree/master/packages/android_alarm_manager

main.dart

import 'dart:isolate';
import 'package:android_alarm_manager/android_alarm_manager.dart';
import 'package:flutter/material.dart';
    
void printHello() {
  final DateTime now = DateTime.now();
  final int isolateId = Isolate.current.hashCode;
  print("[$now] Hello, world! isolate=${isolateId} function='$printHello'");
}

void main() async {
  final int helloAlarmID = 0;
  await AndroidAlarmManager.initialize();
  runApp(MaterialApp(home: Application()));
  await AndroidAlarmManager.periodic(const Duration(minutes: 1), helloAlarmID, printHello);
}

class Application extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(),
    );
  }
}

Application.java:

package io.flutter.plugins.androidalarmmanagerexample;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
    
public class Application extends FlutterApplication implements PluginRegistrantCallback {
    @Override
    public void onCreate() {
        super.onCreate();
    
        AlarmService.setPluginRegistrant(this);
    }

    @Override
    public void registerWith(PluginRegistry registry) {
        GeneratedPluginRegistrant.registerWith(registry);
    }
}               

当我运行这段代码时,它会在控制台打印以下错误:

E/flutter ( 6831): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: PlatformException(error, Attempt to invoke interface method 'void io.flutter.plugin.common.PluginRegistry$PluginRegistrantCallback.registerWith(io.flutter.plugin.common.PluginRegistry)' on a null object reference, null)
E/flutter ( 6831): #0      JSONMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:149:7)
E/flutter ( 6831): #1      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:302:33)
E/flutter ( 6831): <asynchronous suspension>
E/flutter ( 6831): #2      AndroidAlarmManager.initialize (package:android_alarm_manager/android_alarm_manager.dart:76:10)
E/flutter ( 6831): <asynchronous suspension>
E/flutter ( 6831): #3      main (package:alarmdemo/main.dart:12:29)
E/flutter ( 6831): <asynchronous suspension>
E/flutter ( 6831): #4      _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:189:25)
E/flutter ( 6831): #5      _rootRun (dart:async/zone.dart:1124:13)
E/flutter ( 6831): #6      _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter ( 6831): #7      _runZoned (dart:async/zone.dart:1516:10)
E/flutter ( 6831): #8      runZoned (dart:async/zone.dart:1500:12)
E/flutter ( 6831): #9      _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:180:5)
E/flutter ( 6831): #10     _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:300:19)
E/flutter ( 6831): #11     _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
E/flutter ( 6831): 
E/flutter ( 6831): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: MissingPluginException(No implementation found for method AlarmService.initialized on channel plugins.flutter.io/android_alarm_manager_background)
E/flutter ( 6831): #0      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:300:7)
E/flutter ( 6831): <asynchronous suspension>
E/flutter ( 6831): #1      _alarmManagerCallbackDispatcher (package:android_alarm_manager/android_alarm_manager.dart:49:12)
E/flutter ( 6831): #2      _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:189:25)
E/flutter ( 6831): #3      _rootRun (dart:async/zone.dart:1124:13)
E/flutter ( 6831): #4      _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter ( 6831): #5      _runZoned (dart:async/zone.dart:1516:10)
E/flutter ( 6831): #6      runZoned (dart:async/zone.dart:1500:12)
E/flutter ( 6831): #7      _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:180:5)
E/flutter ( 6831): #8      _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:300:19)
E/flutter ( 6831): #9      _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
E/flutter ( 6831): 

这是我的更新代码:

main.dart:

void printHello() {
  final DateTime now = new DateTime.now();
  final int isolateId = Isolate.current.hashCode;
  print("[$now] Hello, world! isolate=${isolateId} 
      function='$printHello'");
}

void main() async {
  runApp(MaterialApp(home: Application()));
}
    
class Application extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Center(
          child: RaisedButton(
            child: Text('Hello'),
            onPressed: () {
              runAlarm();
            },
          ),
        ),
      ),
    );
  }

  void runAlarm() {
    AndroidAlarmManager.oneShot(
      Duration(seconds: 10),
      0,
      printHello,
      wakeup: true,
    ).then((val) => print(val));
  }

  static void alarmTest() {
    print("test");
  }
}

它不会在控制台打印任何错误,但是它会打印以下两行:

E/AlarmService(11943): Fatal: failed to find callback
I/AlarmService(11943): AlarmService has not yet started.

我还尝试过初始化闹钟管理器,但它会将错误打印到控制台:

void runAlarm() {
  AndroidAlarmManager.periodic(
    Duration(seconds: 10),
    0,
    printHello,
    wakeup: true,
  ).then((val) => print(val)).catchError((e) {
    print(e);
  });
}
错误:
E/flutter ( 6831): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: PlatformException(error, Attempt to invoke interface method 'void io.flutter.plugin.common.PluginRegistry$PluginRegistrantCallback.registerWith(io.flutter.plugin.common.PluginRegistry)' on a null object reference, null)
E/flutter ( 6831): #0      JSONMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:149:7)
E/flutter ( 6831): #1      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:302:33)
E/flutter ( 6831): <asynchronous suspension>
E/flutter ( 6831): #2      AndroidAlarmManager.initialize (package:android_alarm_manager/android_alarm_manager.dart:76:10)
E/flutter ( 6831): <asynchronous suspension>
E/flutter ( 6831): #3      main (package:alarmdemo/main.dart:12:29)
E/flutter ( 6831): <asynchronous suspension>
E/flutter ( 6831): #4      _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:189:25)
E/flutter ( 6831): #5      _rootRun (dart:async/zone.dart:1124:13)
E/flutter ( 6831): #6      _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter ( 6831): #7      _runZoned (dart:async/zone.dart:1516:10)
E/flutter ( 6831): #8      runZoned (dart:async/zone.dart:1500:12)
E/flutter ( 6831): #9      _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:180:5)
E/flutter ( 6831): #10     _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:300:19)
E/flutter ( 6831): #11     _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
E/flutter ( 6831): 
E/flutter ( 6831): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: MissingPluginException(No implementation found for method AlarmService.initialized on channel plugins.flutter.io/android_alarm_manager_background)
E/flutter ( 6831): #0      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:300:7)
E/flutter ( 6831): <asynchronous suspension>
E/flutter ( 6831): #1      _alarmManagerCallbackDispatcher (package:android_alarm_manager/android_alarm_manager.dart:49:12)
E/flutter ( 6831): #2      _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:189:25)
E/flutter ( 6831): #3      _rootRun (dart:async/zone.dart:1124:13)
E/flutter ( 6831): #4      _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter ( 6831): #5      _runZoned (dart:async/zone.dart:1516:10)
E/flutter ( 6831): #6      runZoned (dart:async/zone.dart:1500:12)
E/flutter ( 6831): #7      _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:180:5)
E/flutter ( 6831): #8      _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:300:19)
E/flutter ( 6831): #9      _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
E/flutter ( 6831): 

enter image description here


哪个错误?请添加错误信息。 - Ashvin solanki
问题中的错误已更新。 - Manpreet Kaur
让我检查一下... - Rahul Arora
你的配置正确吗?https://github.com/flutter/flutter/issues/26526 - Ashvin solanki
我使用 android_alarm_manager: ^0.4.1+2。 - Manpreet Kaur
显示剩余2条评论
6个回答

15
我自己解决了这个问题,经过几个小时的奋斗(但感觉时间很长!)。突破口是当我实际克隆了包含android_alarm_managerFlutter插件Github存储库,并查看了示例代码以及在IDE中的布局方式,而不是查看在线的孤立文件。
如果您不熟悉Android Java开发,那么Readme并没有非常清楚地说明要做什么,但是当您查看工作示例代码时,就会变得清晰明了。
您需要将他们在示例目录中提供给您的Application.java文件放入到您的实际项目中,与您现有的MainActivity.java文件位于同一文件夹中。内容应该如下所示:
package io.flutter.plugins.androidalarmmanagerexample;

import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugins.androidalarmmanager.AlarmService;

public class Application extends FlutterApplication implements PluginRegistrantCallback {
  @Override
  public void onCreate() {
    super.onCreate();
    AlarmService.setPluginRegistrant(this);
  }

  @Override
  public void registerWith(PluginRegistry registry) {
    GeneratedPluginRegistrant.registerWith(registry);
  }
}

关于需要放置这个文件的位置,他们的示例看起来是这样的,但你的可能在类似于<你的项目目录>/android/app/src/main/java/com/example/<你的项目名称>的地方:

The Application.java file goes in the same folder as your MainActivity.java

完成此操作后,您必须更新Application.java的第一行中的软件包名称,从package io.flutter.plugins.androidalarmmanagerexample;更改为与您的项目使用的软件包匹配(请参见现有MainActivity.java的第一行)。如果您不这样做,gradle将无法找到它,什么也做不了!
现在,您可以按照Readme中的建议添加权限等内容:

像往常一样将此插件导入您的项目后,在<manifest></manifest>标签内的AndroidManifest.xml中添加以下内容:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

接下来,在<application></application>标签内添加:
<service
    android:name="io.flutter.plugins.androidalarmmanager.AlarmService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="false"/>
<receiver
    android:name="io.flutter.plugins.androidalarmmanager.AlarmBroadcastReceiver"
    android:exported="false"/>
<receiver
    android:name="io.flutter.plugins.androidalarmmanager.RebootBroadcastReceiver"
    android:enabled="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"></action>
    </intent-filter>
</receiver>

最后一部分让我最困惑。听起来他们很含糊,但如果之前你做的每件事都完全正确,那么这实际上就是你需要做的。

这必须反映在应用程序的AndroidManifest.xml中。例如:

    <application
        android:name=".Application"
        ...

只需要将android:name更改为.Application,这意味着它现在将利用我们之前添加的Application.java文件。

就是这样!希望你现在可以运行你的应用程序了。


感谢您的回复。我尝试了这个答案,但是在我定义在Application.java文件中的闹钟服务上出现了错误。我也分享了Application.java类的代码和错误信息。 - Manpreet Kaur
抱歉,我不知道如何帮助你。我很幸运能让它在我的设备上工作,因为我对Android开发并不是很了解!实际上,看着你的截图,AlarmService显示为红色,这似乎是因为没有导入它,可能是因为它没有安装。我建议你从这方面开始调查。 - pipedreambomb
最好将Application.java代码包含在答案中,而不是引用它。直到我看到Sen Sokha的答案中的实际代码,我才意识到其重要性。也许还可以将名称更改为MyApplication,以使链接更清晰,即名称由您自己选择。 - Bill99
@Bill99,我已经按照你的建议将Application.java文件的内容添加到我的答案中。我将名称保留为文档中的原样,特别是因为我自己对此了解不够,无法可靠地重命名我不需要的东西!这里有点像神秘崇拜编程,但它确实有效。 - pipedreambomb
无法解析符号“AlarmService”。在导入语句中无法解析“androidalarmmanager”。怎么办? - TimSim

5

问题: 未处理的异常: MissingPluginException(No implementation found for method AlarmService.initialized on channel plugins.flutter.io/android_alarm_manager_background)

原因: 闹钟回调需要访问其他Flutter插件,包括闹钟管理器插件本身,因此需要教会后台服务如何初始化插件。由于AlarmManager使用单独的隔离区域,因此在计划代码中使用的任何插件都需要单独为AlarmManager进行初始化。

解决方法: 在Application.java中注册闹钟管理器插件,代码如下;(解决了官方Flutter存储库的问题#21969)

import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugins.androidalarmmanager.AlarmService;
import io.flutter.plugins.androidalarmmanager.AndroidAlarmManagerPlugin;

public class Application extends FlutterApplication implements PluginRegistrantCallback {
  @Override
  public void onCreate() {
    super.onCreate();
    AlarmService.setPluginRegistrant(this);
  }

  @Override
  public void registerWith(PluginRegistry registry) {
    // GeneratedPluginRegistrant.registerWith(registry);
    AndroidAlarmManagerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.androidalarmmanager.AndroidAlarmManagerPlugin"));
  }
}

*注意: 如果您在项目中使用了其他插件,您也需要将它们全部添加到您的 Application.java 文件中。

public class Application extends FlutterApplication implements PluginRegistrantCallback {
  @Override
  public void onCreate() {
    super.onCreate();
    AlarmService.setPluginRegistrant(this);

  }

  @Override
  public void registerWith(PluginRegistry registry) {
    // GeneratedPluginRegistrant.registerWith(registry);

    //add AndroidAlarmManagerPlugin plugin register  if you work with arlarm
    AndroidAlarmManagerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.androidalarmmanager.AndroidAlarmManagerPlugin"));

    //add PathProviderPlugin plugin register  if you work with Access Path Device
    PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin"));

    //add SqflitePlugin plugin register  if you work with sqflite
    SqflitePlugin.registerWith(registry.registrarFor("com.tekartik.sqflite.SqflitePlugin"));

    //add PermissionHandlerPlugin plugin register  if you work with permission handler
    PermissionHandlerPlugin.registerWith(registry.registrarFor("com.baseflow.permissionhandler.PermissionHandlerPlugin"));

    //add SharedPreferencesPlugin plugin register  if you work with share preferences
    SharedPreferencesPlugin.registerWith(registry.registrarFor("io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin"));

    // something else...

  }
}

我遇到了一个问题,GeneratedPluginRegistrant.registerWith(registry),因为我的一些插件需要活动上下文。AndroidAlarmManagerPlugin.registerWith 解决了我的问题。 - kdy
当我尝试使用这个时,我遇到了与sharedpreference相关的问题,在Flutter代码中我正在使用sharedpreference,出现错误没有找到实现。 - shahana kareen
@shahanakareen 请再试一次 flutter clean & flutter run - Sen Sokha
如果您仍然有错误,请在Application.java中提到您使用的所有通道插件,如下所示:SharedPreferencesPlugin.registerWith(registry.registrarFor("io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin")); - Sen Sokha

2

您没有初始化闹钟对象和回调处理程序。

等待 AndroidAlarmManager.initialize();

当应用程序开始运行时,会发生以下情况:

 void main() async {
    runApp(MaterialApp(home: Application()));
 }

这个应用程序会运行并为您绘制用户界面。当您点击按钮时,将调用以下方法:

最初的回答:

AndroidAlarmManager.oneShot(
   Duration(seconds: 10),
   0,
   printHello,
   wakeup: true,
)

这个函数只是在指定的延迟时间后安排一个回调。但由于没有注册回调处理程序,所以会失败。也就是说,在超时后,它找不到“任何人”来运行“printHello”。

编辑:

您还需要覆盖一个方法来帮助插件在创建时注册自己。

创建一个如下所示的新文件:


yourapprootfolder/android/app/src/main/java/io/flutter/plugins/androidalarmmanagerexample/Application.java

在.java文件内,放入以下内容:

最初的回答

package io.flutter.plugins.androidalarmmanagerexample;

import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugins.androidalarmmanager.AlarmService;

public class Application extends FlutterApplication implements PluginRegistrantCallback {
  @Override
  public void onCreate() {
    super.onCreate();
    AlarmService.setPluginRegistrant(this);
  }

  @Override
  public void registerWith(PluginRegistry registry) {
    GeneratedPluginRegistrant.registerWith(registry);
  }
}

最初的回答
或者在Kt文件中:
package io.flutter.plugins.androidalarmmanagerexample;

import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugins.androidalarmmanager.AlarmService;

class Application : FlutterApplication(), PluginRegistrantCallback {
      override fun onCreate() {
        super.onCreate();
        AlarmService.setPluginRegistrant(this);
      }

      override fun registerWith(registry: PluginRegistry) {
        GeneratedPluginRegistrant.registerWith(registry);
      }
}

谢谢您的回答。我更新了我的代码,但仍然出现错误。 - Manpreet Kaur
这应该是一个新的错误。更新的答案是:不要盲目地复制插件并期望它可以工作,也许尝试理解它。 - 0xCCY
我之前使用过这段代码。正如你所提到的,这段代码被放置在Application.java类中,但是该文件会出现错误,并且无法获取某些AlarmService。我应该如何更改清单文件中的android:name?-@CheunYee - Manpreet Kaur
Java应用程序必须放置在Android的构建文件夹中,它不会被编译为Flutter。该插件有点复杂,因为需要在后台调用一些内容。清单文件可以在android/src/main中找到。 - 0xCCY
我更新了我的问题,并附上了屏幕截图,其中显示在AlarmService上出现错误,并提示AlarmService未解决的引用。-@CheunYee - Manpreet Kaur
显示剩余2条评论

1

您是否在AndroidManifest.xml中引用了您的Application?顺便说一下(我建议使用不同的名称,以避免与Android的Application产生混淆,例如MyFlutterApplication)。

请注意,在插件文档中指出:

这必须反映在应用程序的AndroidManifest.xml中。例如:

<application
    android:name=".Application"
    ...

欲了解更多信息,请参见Android开发者元素文档


1

我有同样的问题。只需打开Android项目。执行Gradle同步。接下来,执行“构建 -> 清理项目”和“构建 -> 重新构建项目”。


0

如果您只为Android开发此应用程序,则可以创建每个给定时间间隔运行的本机前台/后台服务。然后,使用平台通道,您可以从Dart调用服务,无论是在button点击时每次运行还是使用shared prefrence在主页的initState()中调用本机服务。正如您所知,一旦启动本机服务,它将在每个给定的时间间隔(例如1分钟或24小时)后自动调用自身。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接