Preface

We are working on a network application. The requirements of the app were as follows:

  • Network speed information. i.e. upload and download speed, ISP details, network usage statistics of the device, network type details, etc.
  • Silent background push notifications for the real-time statistics of the current device network statistics.

These 2 were the main requirements of the application including persistent notifications. The main inspiration for the application was taken from ‘Internet Speed Meter Lite’, available on Google Play Store.

Problem statement

There were 2 major problems with the application requirements. The persistent notification portion from the requirement seemed to be one of them. There are many available plugins for push notifications. The 3 major ones that we tried were:

  1. Flutter local notification
  2. Awesome notification
  3. Elegant notification
Inadequate Push Notification and Speed Test Functionality

The easiest and fastest way to achieve persistent notifications functionality could be achieved by the awesome_notification plugin. We tried the other 2 as well, but the issue couldn’t be resolved with any of the 3. These 3 were the most voted and used amongst the available packages. The limitation seemed to be coming from dart/flutter. Nowhere in the documentation of the packages was the feature required at hand available. There were ways to achieve different notification types and edit the notification types as well, but there was no way to achieve silent background notification.

The second hiccup for the app is the speed test itself. There is only one plugin available for Flutter that measures real-time network speed data, internet_speed_meter. The package allows the user to set a listener to capture the network speed changes and the app can use the information as required. The drawback is that the plugin only measures the download speed.

Also, the response from the function provided by the plugin to measure the network speed is a string value that contains both the numeric value as well as the rate, i.e. 283kbps, 1.2mbps, 4mbps, etc. This means the response has to be manually checked and split into numeric and the rate that comes attached with the numeric value. This is a whole nother issue on its own. The fact that the response is only string, requires the application to have a function dedicated to parsing the response according to the speed rate. This causes lag in showing the real-time speed data.

We tried using the flutter_internet_speed_test package as an alternative. However, the problem with this package is that there is no real-time speed measurement available. The package provides functions to measure all the network information like ISP details, and upload and download speeds.

But it’s not a real-time speed measurement. The measurement is done using the servers of Fast.com and speedtest by Ookla. The speed is measured for a fixed amount of time and the rate is calculated based on the bytes downloaded and uploaded in that duration. This is not a real-time rate speed test, it’s just an average. This is great for measuring the speed of the network, but not for monitoring the real-time speed.

Silent background notification implementation

The following were the steps used for the notification handler service created. 

Notification handler initialization:

The initialize() function creates an instance of notification to be used throughout the app. The function also asks for permissions required for the notification to be available. 

static initialize() async {

    allowed = await AwesomeNotifications().isNotificationAllowed();

    permission =  (await storage.read(key: notificationPerm)).toString() == 'true';

    if (!allowed) {

      await Permission.notification.request().then((value) {

        allowed = value.isGranted;

      });

    }

    if (!permission) {

      AwesomeNotifications()

          .requestPermissionToSendNotifications()

          .catchError((e) {

        permission = false;

      });

      permission = true;

    }

    if (permission) {

      AwesomeNotifications().initialize(

          null, //  custom icon, should be left null for default flutter icon

          [

            NotificationChannel(

              channelGroupKey: 'network_info_channel_key',

              channelKey: 'network_info_channel',

              channelName: 'Network Info Notifications',

              channelDescription: 'Notification channel for Network Info',

              onlyAlertOnce: true,

              channelShowBadge: false, // flag to show custom icon as badge in the status bar

              playSound: false, // flag to play sound on notification

              enableVibration: false, // flag for vibration for notification

              enableLights: false, // flag to enable lights for notification (for devices that support)

              defaultPrivacy: NotificationPrivacy.Private,

              importance: NotificationImportance.None,

            )

          ],

          channelGroups: [

            NotificationChannelGroup(

              channelGroupKey: 'network_info_channel_group',

              channelGroupName: 'Network Info group',

            )

          ],

          debug: true, // show logs if debug mode

      );

    }

    storage.write(key: notificationPerm, value: permission.toString());

    storage.write(key: notificationEnabled, value: allowed.toString()); 

}

Showing Persistent Notification:

The display() function triggers a notification with the notification settings initialized in the initialization() function.

static Future display(

      {required model.NotificationModel notificationModel}) async {

    try {

      if ((await storage.read(key: notificationEnabled)).toString() == 'true' &&

          (await storage.read(key: notificationPerm)).toString() == 'true') {

        AwesomeNotifications().createNotification(

            content: NotificationContent(

          id: -1,

          criticalAlert: false,

          channelKey: 'network_info_channel',

          autoDismissible: true, 

// dismiss the notification automatically, requires duration for timeout if set to true

          locked: true,

          displayOnForeground: true, 

// flag to trigger notification while app is active

          displayOnBackground: true, 

// flag to trigger notification while app is minimized or closed

          title: 'Network Info',

          body: notificationModel.body,

          category: NotificationCategory.Event,

        )); }

    } catch (e) {

      debugPrint('>> error on showing notification: $e');

    }

  }

Realtime speed measure as background service:

The speedTest() function triggers a listener which listens to changes for network speed of the device and pushes for notification.

// continuous speed data

  speedTest() {

    debugPrint('>> listener for network speed value changes');

    speedCheck =

        internetSpeedMeterPlugin.getCurrentInternetSpeed().listen((event) {

      currentSpeed(event);

      if (backgroundState.value) {

        speedCheck.cancel();

        } else {

        debugPrint('>> speed: ${currentSpeed.value}');

        NotificationModel notificationModel = NotificationModel(

            title: 'Network Info',

            body: 'Download Rate: $event',

            payload: event);

        NotificationService.display(notificationModel: notificationModel);

      } }); }

 These are the codes using the awesome_notification package to achieve the goal. Apparently, there is no specific parameter or module present in the package, or in any other packages, that can trigger a silent background notification. 

Speed test detail

Real-time speed test:

// continuous speed data

  speedTest() {

    debugPrint('>> listener for network speed value changes');

    speedCheck =

        internetSpeedMeterPlugin.getCurrentInternetSpeed().listen((event) {

      currentSpeed(event);

      if (backgroundState.value) {

        speedCheck.cancel();

        } else {

        debugPrint('>> speed: ${currentSpeed.value}');

        NotificationModel notificationModel = NotificationModel(

            title: 'Network Info',

            body: 'Download Rate: $event',

            payload: event);

        NotificationService.display(notificationModel: notificationModel);

      }

    });

  }

An alternative approach using another plugin:

await internetSpeedTest.startTesting(

        onCompleted: (TestResult download, TestResult upload) {

      dailyStat.value.unit = SpeedUnit.kbps.toString();

      dailyStat.value.unit = SpeedUnit.kbps.toString();

      dailyStat.value.networkUsage.wifiDownload =

          download.unit == SpeedUnit.mbps

              ? download.transferRate

              : download.transferRate / 1000;

      dailyStat.value.networkUsage.wifiUpload = upload.unit == SpeedUnit.mbps

          ? upload.transferRate

          : upload.transferRate / 1000;

    }).catchError((onError) {

      debugPrint(onError.toString());

    });

This plugin provides all the information regarding internet speed. The units and the actual rate, but not the real-time data.

Conclusion

After hours of scouring the internet forums on Stackoverflow and Reddit, and posting for help in the forums, there were no responses and discussions regarding this particular issue. It seems that either Flutter/dart doesn’t support the features at hand or there are no plugins/packages that can achieve said features. There is an Android application for reference of what the features in use feel like and the application is Internet Speed Meter Lite.

Unfortunately, the application was developed in the very early stages of Android and doesn’t seem to be using Flutter. Also, it’s only available in Android, so it is possible that the features in discussion cannot be achieved using Flutter, at least with the feature updates and packages available to date. 

We have decided to move along with the development using Android native for now and will update you on the situation as the development progresses.

Want to create mobile applications for your business? Book a call right now.

CTA - Mobile Application Development Service Page