【Flutter/connectivity_plus】ネットワーク状況を監視する
通信を行う iOS/Android アプリを Flutter で開発しています。
インターネットに接続されていない場合にメッセージを表示したかったため、ネットワーク状況を監視するパッケージを利用したので、備忘録として残します。
今回作成したサンプルアプリケーション
要約
- ネットワーク状況の監視には
connectivity_plus
パッケージを使用する -
ConnectivityResult
を状態として保持する -
StreamSubscription
を利用して、状態として保持しているConnectivityResult
を監視する - 保持している状態に応じて表示する
Widget
を切り替える -
ConnectivityResult
はモバイル通信(mobile)や Wi-Fi 通信(wifi)などがある
connectivity_plus パッケージを追加する
connectivity_plus
を利用することで、ネットワーク状況を取得することができます
通常のパッケージ利用と同様の手法で、flutter pub add connectivity_plus
をコマンドラインなどで実行するか、pubspec.yaml
の dependencies に記述を追加してパッケージを導入します
サンプルコード
以下のようにネットワーク状況に応じて表示する Widget
を切り替えるだけの簡易的なアプリケーションを作成します
- ネットワークにつながっているとき
- 通常の画面(
connectivity_sample
と表示するだけの画面)を表示
- 通常の画面(
- ネットワークにつながっていないとき
- 通常の画面操作をすることができないようにアラートを表示する
main.dart
コード全文
import 'package:flutter/material.dart';
import 'package:flutter_connectivity_sample/src/connectivity_sample.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Connectivity Sample',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(
title: 'Flutter Connectivity Sample'
),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key, required this.title});
final String title;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(title),
),
body: const ConnectivitySample(
child: Center(
child: Text(
'connectivity sample',
),
),
)
);
}
}
connectivity_sample.dart
コード全文
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_connectivity_sample/src/not_connection.dart';
class ConnectivitySample extends StatefulWidget {
const ConnectivitySample({
super.key,
required this.child
});
final Widget child;
State<ConnectivitySample> createState() => _State();
}
class _State extends State<ConnectivitySample> {
ConnectivityResult connectionStatus = ConnectivityResult.none;
final Connectivity connectivity = Connectivity();
late StreamSubscription<ConnectivityResult> connectivitySubscription;
void initState() {
super.initState();
initConnectivity();
connectivitySubscription = connectivity.onConnectivityChanged.listen(updateConnectionStatus);
}
void dispose() {
connectivitySubscription.cancel();
super.dispose();
}
Future<void> initConnectivity() async {
late ConnectivityResult result;
try {
result = await connectivity.checkConnectivity();
} on PlatformException catch(_) {
return;
}
if (!mounted) {
return;
}
updateConnectionStatus(result);
}
Future<void> updateConnectionStatus(ConnectivityResult result) async {
setState(() {
connectionStatus = result;
});
}
Widget build(BuildContext context) {
return connectionStatus == ConnectivityResult.none
? const NotConnection()
: widget.child;
}
}
not_connection.dart
コード全文
import 'package:flutter/material.dart';
class NotConnection extends StatelessWidget {
const NotConnection({
super.key
});
Widget build(BuildContext context) {
return const AlertDialog(
title: Text("not connection"),
content: SizedBox(
width: 200,
height: 200,
child: Text("network error."),
),
);
}
}
ConnectivityResult を状態として保持する
ConnectivityResult
を状態として保持します
enum で none
, mobile
, wifi
などのステータスがあります
今回は none
のみの使用ですが、モバイル通信と Wi-Fi 通信の違いで処理を分けたい場合(表示する画像の画質を変えるなど)は活用できそうです
ConnectivityResult connectionStatus = ConnectivityResult.none;
Future<void> updateConnectionStatus(ConnectivityResult result) async {
setState(() {
connectionStatus = result;
});
}
StreamSubscription を用いて ConnectivityResult を監視する
StreamSubscription
を用いて、State
として保持している ConnectivityResult
を監視します
void initState() {
super.initState();
initConnectivity();
connectivitySubscription = connectivity.onConnectivityChanged.listen(updateConnectionStatus);
}
Future<void> updateConnectionStatus(ConnectivityResult result) async {
setState(() {
connectionStatus = result;
});
}
StreamSubscription についてはこちら
State に応じて表示する Widget を切り替える
State
に応じて、表示する Widget
を切り替えるようにします
今回は NotConnection
というダイアログを用意しています
Widget build(BuildContext context) {
return connectionStatus == ConnectivityResult.none
? const NotConnection()
: widget.child;
}
main.dart の Widget に追加する
connectivity_sample.dart
には child
として Widget
を渡せるようにしています
親 Widget
から ConnectivitySample
を呼び出し、その child
プロパティにネットワークにつながっている状態で表示したい Widget
を渡します
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(title),
),
body: const ConnectivitySample(
child: Center(
child: Text(
'connectivity sample',
),
),
)
);
}
実際の動作画面
ネットワークにつながっているとき
ConnectivityResult.none じゃないとき
通信をきる
ネットワークにつながっていないとき
ConnectivityResult.none のとき
再び通信を ON にすれば元の画面に戻ります
参考
パッケージ
実装について
Stream について
サンプルアプリケーション
さいごに
今回は表示する Widget
を切り替えることでネットワークにつながっていないときはアプリ自体の利用を制限するような実装ですが、一部機能の制限などをしたい場合は状態管理の方法に Riverpod
を利用して状態だけを切り出すなど、もう少し工夫が必要そうです
また、connectivity_plus
は iOS/Android のほか、他のプラットフォームにも対応しているパッケージなので、Web アプリや iOS/Android 以外のネイティブアプリに同様の仕組みを実装したい場合にも役立つことがわかりました
以上です
ここまで読んでいただきありがとうございました!
Discussion