【问题标题】:How do you use receiver (BroadcastReceiver) in a flutter plugin?如何在颤振插件中使用接收器(BroadcastReceiver)?
【发布时间】:2021-01-11 02:00:03
【问题描述】:

问题

我正在构建一个需要 Radar.io SDK 的一些功能的应用程序,因此我决定创建插件,以便在这个项目结束后我可以与 Flutter 社区的其他人共享该插件。问题是,我无法在此插件中接收事件。这对于插件很重要,因为为了接收诸如地理位置触发器和其他后台事件之类的事件,此接收器需要接收实时信息。

我已经成功地实现了他们的 SDK for 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 目录中查找并返回找不到数据路径的错误。这会导致应用程序终止。

为了解决这个问题,我发现可以通过编程方式设置接收器,所以我决定试一试。

在插件的主 Kotlin 文件中,我编写了以下几行以在 registerWithonAttachedToEngine 中执行。据我了解,这些基本上是 onStart 函数。 registerWith 是为了与旧设备兼容而保留的旧功能。

val myRadarReceiver = MyRadarReceiver()
val intentFilter = IntentFilter()
intentFilter.addAction("io.radar.sdk.RECEIVED")
ContextWrapper(this.context).registerReceiver(myRadarReceiver, intentFilter)

引用为MyRadarReceiver() 的类是SDK 中RadarReceiver 类的扩展,它扩展了BroadcastReceiver,这意味着这是我的广播接收器。这是课程:

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 中的一个函数能够执行,但终端上没有打印任何内容。没有错误,但没有收到任何内容。这让我想知道我是否错误地设置了意图,或者接收器是否写得不正确。我不知道设置意图的另一种方法,所以我决定以更简单的形式重写 MyRadarReceiver,如下所示:

public class MyRadarReceiver: BroadcastReceiver() {
  override fun onReceive(context: Context, intent: Intent) {
    println("works! Something was received")
  }
}

很遗憾,控制台上没有打印任何内容,所以我现在认为这与我的意图有关。

总结

我剩下要尝试的唯一解决方案是在应用程序中而不是在插件中编写接收器。这可能有效,但是,我希望在完成后与 Flutter 社区分享这个插件。 Radar 是一个非常强大的平台,将这个插件引入 Flutter 社区可能会产生显着的影响。

【问题讨论】:

  • 插件的manifest 标签中的package 属性是什么?
  • @Nitrodon 对于插件它是 package="agency.sparc.flutter_radar_io" 但对于示例应用程序它是 package="agency.sparc.flutter_radar_io_example"
  • 有没有办法让我从插件包中引用类?因为如果可以的话,也许我可以将接收器添加到应用程序 XML 文件中,然后插件将接收它。或者,也许我可以在插件 XML 中添加一些内容,但是当我这样做时,我会收到覆盖应用程序 android 标签的错误...Attribute application@label value=(flutter_radar_io_example) from AndroidManifest.xml:16:9-49 is also present at [:flutter_radar_io] AndroidManifest.xml:9:9-41

标签: android flutter kotlin broadcastreceiver flutter-plugin


【解决方案1】:

解决方案

在看到 Nitrodon 的评论后,我对问题有了不同的看法并找到了解决方案。我不确定为什么程序化接收器初始化不起作用,但是,这是我在 插件的 Android Manifest 中放入的内容。

<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 Manifest 冲突而引发错误。出于这个原因,您只需要在简单的应用程序标签中声明接收者,这些标签只包含io.flutter.app.FlutterApplication 的名称。我希望这对其他人有帮助!如果有人有什么要补充的,请做,但它终于奏效了!

【讨论】:

    【解决方案2】:

    Android 基础知识

    一个有用的资源是Broadcasts overview

    这取决于您是想在运行时注册广播接收器,还是在清单中静态声明它。阅读Dynamic Registration vs Static Registration of BroadcastReceiver。如果您想要启动接收器的意图,则必须静态声明它。如果您希望它仅在您的应用已经运行时监听,请在运行时注册它。

    这都是普通的 Android 东西。


    颤振细节

    在广播接收器中,不能保证 Flutter 应用程序、Flutter Engine 或 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 插件在广播接收器连接和分离时得到通知。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-02
      • 1970-01-01
      • 2021-01-08
      相关资源
      最近更新 更多