fluttercommunity / fluttercommunity/plus_plugins

[Bug]: iOS connectivity_plus retains callbacks in multi-FlutterEngine apps

オープン
#3,958 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
Dart
スター
1.9k
フォーク
1.3k
PR マージ指標
30日以内にマージされた PR はありません

説明

### Platform

iOS, in applications that register `connectivity_plus` on more than one `FlutterEngine` (for example, a long-lived main engine plus short-lived secondary engines).

### Plugin

connectivity_plus

### Version

7.3.1

### Flutter SDK

- Flutter 3.35.7 / Dart 3.9.2: production crash observed in our multi-engine host.

### Steps to reproduce

1. Create a long-lived FlutterEngine and register `connectivity_plus`.
2. Create a second, short-lived FlutterEngine and register the plugin there too.
3. Subscribe to `onConnectivityChanged` on the secondary engine.
4. Destroy or detach the secondary engine while a network callback is pending, then repeat the create/destroy cycle.

### Actual behavior

The iOS plugin retains callback chains after an engine is no longer usable:

- `ConnectivityPlusPlugin -> ConnectivityProvider -> connectivityUpdateHandler -> ConnectivityPlusPlugin`
- `PathMonitorConnectivityProvider -> NWPathMonitor -> pathUpdateHandler -> PathMonitorConnectivityProvider`

The callbacks are assigned as bound method references, which retain their owners. The plugin is also not published through the registrar, so Flutter cannot invoke `detachFromEngine(for:)` when the engine is deallocated.

In a multi-engine application this leaves stale providers and network callbacks associated with short-lived engines. A later callback can attempt to deliver an EventChannel event after that engine has exited, causing:

`Sending a message before the FlutterEngine has been run.`

The retained callback graph also prevents timely release of the plugin/provider.

### Expected behavior

Each FlutterEngine should own an independent plugin lifecycle. When an engine is detached or deallocated, its connectivity monitor and EventChannel sink should be released without affecting other engines, and no callback should target the detached engine.

### Proposed fix

1. Use weak captures for both callback edges.
2. Publish the plugin instance with `registrar.publish(instance)`.
3. Implement `detachFromEngine(for:)` to clear the event sink and stop the engine-owned monitor.

This keeps normal connectivity monitoring unchanged while making teardown safe for multi-FlutterEngine hosts.

### Code sample

```dart
final subscription =
Connectivity().onConnectivityChanged.listen((_) {});

// In a host application, dispose the secondary FlutterEngine while this
// subscription is active, then create another secondary engine.
```

### Logs

```text
Fatal Exception: NSInternalInconsistencyException
Sending a message before the FlutterEngine has been run.

-[FlutterEngine sendOnChannel:message:binaryReply:]
FlutterBinaryMessengerRelay
SetStreamHandlerMessageHandlerOnChannel
SwiftConnectivityPlusPlugin.connectivityUpdateHandler
```

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

iOS の connectivity_plus 実装から始め、ConnectivityPlusPlugin、PathMonitorConnectivityProvider、および engine の登録ライフサイクルに注目してください。issue に記載されている複数の FlutterEngine の作成、購読、デタッチ、破棄のサイクルを再現してください。各 engine が teardown 時に自身の event sink と connectivity monitor を解放し、callback がデタッチされた engine を対象にしなくなり、他の engine が引き続き正常に監視できれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
dart, flutter, swift
領域
mobile
issue の種類
バグ
難易度
3/5
見積もり時間
1〜2日
活発さ
静か
明瞭さ
明確に書かれている
初心者へのやさしさ
68/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。