如何在 flutter 插件中使用接收器 (BroadcastReceiver)?
How do you use receiver (BroadcastReceiver) in a flutter plugin?
问题
我正在构建一个需要 Radar.io SDK 的一些功能的应用程序,所以我决定创建插件,以便在这个项目结束后我可以与 Flutter 社区的其他人共享插件.问题是,我无法在此插件中接收事件。这对插件很重要,因为为了接收诸如地理定位触发器和其他背景事件之类的事件,此接收器需要接收实时信息。
我已经成功地在他们的 SDK 中为 Android(使用 Kotlin)实现了每个功能,参见此处 https://radar.io/documentation/sdk,但是,当事件发生时,接收器没有被调用。我知道设备正在被跟踪,因为在 Radar.io 仪表板中更新了位置,但是,当发生各种事件时,接收器根本没有执行。
我试过的
以下是文档告诉您如何在清单中注册接收器。
<receiver
android:name=".MyRadarReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="io.radar.sdk.RECEIVED" />
</intent-filter>
</receiver>
这适用于标准应用程序,但是,当我在清单中注册接收器时,应用程序不会在接收器所在的插件目录中查找。相反,它会在应用程序 android 目录和 returns 中查找找不到数据路径的错误。这会导致应用程序终止。
为了解决这个问题,我发现可以通过编程方式设置接收器,所以我决定试一试。
在插件的主 Kotlin 文件中,我编写了以下要在 registerWith
和 onAttachedToEngine
中执行的行。据我了解,这些基本上是 onStart 功能。 registerWith
是为了与旧设备兼容而保留的旧功能。
val myRadarReceiver = MyRadarReceiver()
val intentFilter = IntentFilter()
intentFilter.addAction("io.radar.sdk.RECEIVED")
ContextWrapper(this.context).registerReceiver(myRadarReceiver, intentFilter)
引用为 MyRadarReceiver()
的 class 是 SDK 中 RadarReceiver
class 的扩展,它扩展了 BroadcastReceiver
意味着这是我的广播接收器。这是 class:
public class MyRadarReceiver: RadarReceiver() {
override fun onEventsReceived(context: Context, events: Array<RadarEvent>, user: RadarUser) {
println("test: " + "an event was received")
}
override fun onLocationUpdated(context: Context, location: Location, user: RadarUser) {
println("test: " + "location was updated")
}
override fun onClientLocationUpdated(context: Context, location: Location, stopped: Boolean, source: Radar.RadarLocationSource) {
println("test: " + "client location updated")
}
override fun onError(context: Context, status: Radar.RadarStatus) {
println("test: " + status)
}
override fun onLog(context: Context, message: String) {
println("test: " + message)
}
}
当我在模拟设备上开始后台跟踪时,我希望 MyRadarReceiver
中的功能之一能够执行,但终端没有打印任何内容。没有错误,但是什么也没有收到。这让我想知道我是否错误地设置了意图,或者 Receiver 是否写得不正确。我不知道另一种设置意图的方法,所以我决定以更简单的形式重写 MyRadarReceiver,如下所示:
public class MyRadarReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
println("works! Something was received")
}
}
不幸的是,控制台上没有打印任何内容,所以我现在相信这与我的意图有关。
总结
我唯一要尝试的解决方案是在应用程序而不是插件中编写接收器。这可能有效,但是,我希望在完成后与 Flutter 社区分享这个插件。 Radar 是一个非常强大的平台,将此插件引入 Flutter 社区可能会产生巨大的影响。
解决方案
在看到 Nitrodon 的评论后,我对问题有了不同的看法并找到了解决方案。我不确定为什么程序化的 Receiver 初始化不起作用,但是,这是我在 插件的 Android 清单中输入的内容。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.youorganization.yourproject">
<application
android:name="io.flutter.app.FlutterApplication">
<receiver
android:name=".MyRadarReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="io.radar.sdk.RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
您不能向应用程序标签添加 android 标签或任何其他内容,否则会因与应用程序的 Android 清单冲突而抛出错误。因此,您只需要在简单的应用程序标签中声明接收器,该标签只包含 io.flutter.app.FlutterApplication
的名称。我希望这可以帮助别人!如果有人有什么要补充的,请补充,但它终于起作用了!
Android 基础知识
有用的资源是 Broadcasts overview。
这取决于您是想在 运行 时注册您的广播接收器,还是在清单中静态声明它。阅读 Dynamic Registration vs Static Registration of BroadcastReceiver。如果您想要启动接收器的意图,则必须静态声明它。如果您希望它仅在您的应用已经 运行ning 时收听,请在 运行 时间注册它。
这都是正常的 Android 东西。
Flutter 细节
在广播接收器中,您无法保证 Flutter 应用程序、Flutter 引擎或 DartVM 运行正在运行。如果你想 运行 Flutter,你需要生成一个 Isolate。
flutterEngine = new FlutterEngine(context, null);
DartExecutor executor = flutterEngine.getDartExecutor();
backgroundMethodChannel = new MethodChannel(executor.getBinaryMessenger(), "your channel name");
backgroundMethodChannel.setMethodCallHandler(this);
// Get and launch the users app isolate manually:
executor.executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());
然后,您可以通过调用通知插件/Flutter 应用程序:
// Even though lifecycle parameter is @NonNull, the implementation `FlutterEngineConnectionRegistry`
// does not use it, because it is a bug in the API design. See https://github.com/flutter/flutter/issues/90316
flutterEngine.getBroadcastReceiverControlSurface().attachToBroadcastReceiver(this, null); // This is the class you are in, the broadcast receiver
当您即将完成广播接收器执行时:
flutterEngine.getBroadcastReceiverControlSurface().detachFromBroadcastReceiver();
这将确保 BroadcastReceiverAware
插件在附加和分离广播接收器时得到通知。
问题
我正在构建一个需要 Radar.io SDK 的一些功能的应用程序,所以我决定创建插件,以便在这个项目结束后我可以与 Flutter 社区的其他人共享插件.问题是,我无法在此插件中接收事件。这对插件很重要,因为为了接收诸如地理定位触发器和其他背景事件之类的事件,此接收器需要接收实时信息。
我已经成功地在他们的 SDK 中为 Android(使用 Kotlin)实现了每个功能,参见此处 https://radar.io/documentation/sdk,但是,当事件发生时,接收器没有被调用。我知道设备正在被跟踪,因为在 Radar.io 仪表板中更新了位置,但是,当发生各种事件时,接收器根本没有执行。
我试过的
以下是文档告诉您如何在清单中注册接收器。
<receiver
android:name=".MyRadarReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="io.radar.sdk.RECEIVED" />
</intent-filter>
</receiver>
这适用于标准应用程序,但是,当我在清单中注册接收器时,应用程序不会在接收器所在的插件目录中查找。相反,它会在应用程序 android 目录和 returns 中查找找不到数据路径的错误。这会导致应用程序终止。
为了解决这个问题,我发现可以通过编程方式设置接收器,所以我决定试一试。
在插件的主 Kotlin 文件中,我编写了以下要在 registerWith
和 onAttachedToEngine
中执行的行。据我了解,这些基本上是 onStart 功能。 registerWith
是为了与旧设备兼容而保留的旧功能。
val myRadarReceiver = MyRadarReceiver()
val intentFilter = IntentFilter()
intentFilter.addAction("io.radar.sdk.RECEIVED")
ContextWrapper(this.context).registerReceiver(myRadarReceiver, intentFilter)
引用为 MyRadarReceiver()
的 class 是 SDK 中 RadarReceiver
class 的扩展,它扩展了 BroadcastReceiver
意味着这是我的广播接收器。这是 class:
public class MyRadarReceiver: RadarReceiver() {
override fun onEventsReceived(context: Context, events: Array<RadarEvent>, user: RadarUser) {
println("test: " + "an event was received")
}
override fun onLocationUpdated(context: Context, location: Location, user: RadarUser) {
println("test: " + "location was updated")
}
override fun onClientLocationUpdated(context: Context, location: Location, stopped: Boolean, source: Radar.RadarLocationSource) {
println("test: " + "client location updated")
}
override fun onError(context: Context, status: Radar.RadarStatus) {
println("test: " + status)
}
override fun onLog(context: Context, message: String) {
println("test: " + message)
}
}
当我在模拟设备上开始后台跟踪时,我希望 MyRadarReceiver
中的功能之一能够执行,但终端没有打印任何内容。没有错误,但是什么也没有收到。这让我想知道我是否错误地设置了意图,或者 Receiver 是否写得不正确。我不知道另一种设置意图的方法,所以我决定以更简单的形式重写 MyRadarReceiver,如下所示:
public class MyRadarReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
println("works! Something was received")
}
}
不幸的是,控制台上没有打印任何内容,所以我现在相信这与我的意图有关。
总结
我唯一要尝试的解决方案是在应用程序而不是插件中编写接收器。这可能有效,但是,我希望在完成后与 Flutter 社区分享这个插件。 Radar 是一个非常强大的平台,将此插件引入 Flutter 社区可能会产生巨大的影响。
解决方案
在看到 Nitrodon 的评论后,我对问题有了不同的看法并找到了解决方案。我不确定为什么程序化的 Receiver 初始化不起作用,但是,这是我在 插件的 Android 清单中输入的内容。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.youorganization.yourproject">
<application
android:name="io.flutter.app.FlutterApplication">
<receiver
android:name=".MyRadarReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="io.radar.sdk.RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
您不能向应用程序标签添加 android 标签或任何其他内容,否则会因与应用程序的 Android 清单冲突而抛出错误。因此,您只需要在简单的应用程序标签中声明接收器,该标签只包含 io.flutter.app.FlutterApplication
的名称。我希望这可以帮助别人!如果有人有什么要补充的,请补充,但它终于起作用了!
Android 基础知识
有用的资源是 Broadcasts overview。
这取决于您是想在 运行 时注册您的广播接收器,还是在清单中静态声明它。阅读 Dynamic Registration vs Static Registration of BroadcastReceiver。如果您想要启动接收器的意图,则必须静态声明它。如果您希望它仅在您的应用已经 运行ning 时收听,请在 运行 时间注册它。
这都是正常的 Android 东西。
Flutter 细节
在广播接收器中,您无法保证 Flutter 应用程序、Flutter 引擎或 DartVM 运行正在运行。如果你想 运行 Flutter,你需要生成一个 Isolate。
flutterEngine = new FlutterEngine(context, null);
DartExecutor executor = flutterEngine.getDartExecutor();
backgroundMethodChannel = new MethodChannel(executor.getBinaryMessenger(), "your channel name");
backgroundMethodChannel.setMethodCallHandler(this);
// Get and launch the users app isolate manually:
executor.executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());
然后,您可以通过调用通知插件/Flutter 应用程序:
// Even though lifecycle parameter is @NonNull, the implementation `FlutterEngineConnectionRegistry`
// does not use it, because it is a bug in the API design. See https://github.com/flutter/flutter/issues/90316
flutterEngine.getBroadcastReceiverControlSurface().attachToBroadcastReceiver(this, null); // This is the class you are in, the broadcast receiver
当您即将完成广播接收器执行时:
flutterEngine.getBroadcastReceiverControlSurface().detachFromBroadcastReceiver();
这将确保 BroadcastReceiverAware
插件在附加和分离广播接收器时得到通知。