preface

This article describes how to develop a Flutter plugin to listen for changes in the state of a mobile phone network. Note that this plugin is currently only available on Android.

use

Whenever the network state changes, the Builder method of NetworkListener is called to call back the network state through status.

NetworkListener(
  builder: (_,status){
    var networkStatuds = "";
    if (status == ConnectivityResult.none) {
      networkStatuds = "Network unavailable";
    }
    if (status == ConnectivityResult.has) {
      networkStatuds = "Network available";
    }
    returnText(networkStatuds); },)Copy the code

The effect

The principle of

Using StreamBuilder

The NetworkListener encapsulates a StreamBuilder that receives the Stream returned by the Native end to call back the network state. The code is as follows:

class NetworkListener extends StatelessWidget {
  const NetworkListener({
    required this.builder,
    Key? key}) : super(key: key);

  final  Widget Function(BuildContext context, ConnectivityResult connectivityResult) builder;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
      stream: NetworkStatusNotifier.getNetworkStatus(),
      builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
        if(snapshot.connectionState == ConnectionState.active && snapshot.hasData){
         return builder(context,snapshot.data);
        }

        returnbuilder(context,ConnectivityResult.none); }); }}Copy the code

How to make native return Stream

How do YOU make the Native end return Strea? First, you need to create an EventChannel in the onAttachedToEngine of the Native FlutterPlugin and use its setStreamHandler method to set what to call back to the DART side. The code is as follows, notice network_status_notifier_EC, which needs to correspond to the DART end.

// ...
private EventChannel eventChannel;

public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
  eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(),"network_status_notifier_ec");
  ConnectivityBroadcastReceiver connectivityBroadcastReceiver = new ConnectivityBroadcastReceiver(flutterPluginBinding.getApplicationContext());
  eventChannel.setStreamHandler(connectivityBroadcastReceiver);
}

// ...
Copy the code

On the DART side, an EventChannel is also created to receive the stream returned by Native

/// Connection status check result.
enum ConnectivityResult {
  /// has network.
  has,
  /// None: Device not connected to any network
  none
}

class NetworkStatusNotifier {

  static const EventChannel _eventChannel = EventChannel("network_status_notifier_ec");

  static Stream<ConnectivityResult>? _networkStatus;

  staticStream<ConnectivityResult> getNetworkStatus(){ _networkStatus ?? = _eventChannel.receiveBroadcastStream().map((satues) => parseResult(satues));return_networkStatus! ; }static ConnectivityResult parseResult(int i){
    switch(i){
      case 0:
        return ConnectivityResult.none;
      case 1:
        return ConnectivityResult.has;
      default:
        returnConnectivityResult.none; }}}Copy the code

How to Listen to the Network

The monitoring network has different implementations in different Android versions. This project uses the mode of monitoring broadcast to monitor the network status under Android N, while the mode of registration callback is used when the network status is larger than Android N. The code is as follows:


public class ConnectivityBroadcastReceiver  extends BroadcastReceiver
        implements EventChannel.StreamHandler{

    public ConnectivityBroadcastReceiver(Context context) {
        this.context = context;
        connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    }

    private Context context;
    private ConnectivityManager connectivityManager;
    // Callback result
    private EventChannel.EventSink events;
    public static final String CONNECTIVITY_CHANGE = "android.net.conn.CONNECTIVITY_CHANGE";
    private Handler mainHandler = new Handler(Looper.getMainLooper());
    private ConnectivityManager.NetworkCallback networkCallback;

    @Override
    public void onReceive(Context context, Intent intent) {
        if(android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            //
            if(networkInfo ! =null && networkInfo.isAvailable()) {
                // network is available.
                callbackNetworkStatus(1);
            } else {
                // network is unavailable.
                callbackNetworkStatus(0); }}}@Override
    public void onListen(Object arguments, EventChannel.EventSink events) {
        this.events = events;

        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            networkCallback =
                    new ConnectivityManager.NetworkCallback() {
                        @Override
                        public void onAvailable(Network network) {
                            sendEvent(1);
                        }

                        @Override
                        public void onUnavailable(a) {
                            sendEvent(0);
                        }

                        @Override
                        public void onLost(Network network) {
                            sendEvent(0); }}; connectivityManager.registerDefaultNetworkCallback(networkCallback); }else {
            context.registerReceiver(this.newIntentFilter(CONNECTIVITY_CHANGE)); }}@Override
    public void onCancel(Object arguments) {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            if(networkCallback ! =null) { connectivityManager.unregisterNetworkCallback(networkCallback); }}else {
            context.unregisterReceiver(this); }}private void callbackNetworkStatus(int status){
        if(events ! =null){ events.success(status); }}private void sendEvent(final int status) {
        Runnable runnable =
                new Runnable() {
                    @Override
                    public void run(a) { events.success(status); }}; mainHandler.post(runnable); }}Copy the code

The complete code

Github.com/obweix/flut…