Flutter Errors Example

→ Defining custom PlatformOperationExceptions

 

The latest version of all the official Flutnet samples can be found in the official GitHub repository: https://github.com/flutnet/samples/

 

Overview

This example will be focused about what Flutnet offers to handle Xamarin errors on Flutter code. The only thing you need to is to extend the PlatformOperationException class with the information you want. This type of classes are the only supporting inheritance during $ flutnet pack  procedure.

Remember to fill the class with properties of supported types or PlatformData.

 

 

We will define a PlatformService called LoginService that will provide one PlatformOperation:

  1. public SessionInfo Login ( string username, string password, bool forceHandleError )

one PlatformOperationException:

  1. LoginException to transport the error from Xamarin to Flutter

two PlatformData:

  1. SessionInfo that incapsulate session information
  2. LoginErrors (enum) with specific login error code

 

The method will return the SessionInfo information, with a session token string.

In case of failure the method will launch a LoginException, with an associated LoginErrors in form of enum.


Create the project

Create a project named "FlutnetErrors" using the Flutnet Console.

The generated project structure will contain the Visual Studio solution (FlutnetErrors.sln) and a set of Xamarin and Flutter projects:

  • Xamarin
    • FlutnetErrors.Android (Xamarin.Android application)
    • FlutnetErrors.iOS (Xamarin.iOS application)
    • FlutnetErrors.ServiceLibrary (.NET Standard class library)
  • Flutter
    • flutnet_errors (Flutter module → it's the main Flutter project where you develop the UI)
    • flutnet_errors_bridge (Flutter package → it will contain auto-generated Dart code that defines the communication layer between Flutter and Xamarin).

Define the ServiceLibrary (PlatformService, PlatformOperations, etc.)

In the *.ServiceLibrary project we need to define the LoginService, like discussed before.

LoginService.cs

using Flutnet.ServiceModel;

namespace FlutnetErrors.ServiceLibrary
{
    //  enum to describe the error
    [ PlatformData ]
    public enum LoginErrors
    {
        InvalidUsername,
        InvalidPassword,
        InvalidUsernameAndPassword,
    }
    //  custom error class (will be exposed to Flutter)
    public class LoginException : PlatformOperationException
    {
        public LoginErrors Error { get; set; }
    }
    //  Session information
    [ PlatformData ]
    public class SessionInfo
    {
        public string Token { get; set; }
        public DateTime LastLogin { get; set; }
    }

    // This service class will be exposed to Flutter
    [ PlatformService ]
    public class LoginService
    {
        // Perform a fake login, returning the session information to flutter.
        [ PlatformOperation ]
        public SessionInfo Login(string username, string password, bool forceHandleError)
        {

            // This emulate a not handled exception
            if (forceHandleError)
            {
                throw new InvalidOperationException("Login method ended bad!");
            }

            // Here you can call your web API to check the credentials
            bool userOk = username == "pippo";
            bool passwordOk = password == "password";

            // The LoginException extend FlutterException, so will be handled and passed directly to flutter UI module,
            // so you can manage directly from Flutter. This is provided by the flutnet.sdk framework

            if ( ! userOk && ! passwordOk )
                throw new LoginException()
                {
                    Error = LoginErrors.InvalidUsernameAndPassword
                };

            if( ! userOk )
                throw new LoginException()
                {
                    Error = LoginErrors.InvalidUsername
                };

            if ( ! passwordOk )
                throw new LoginException()
                {
                    Error = LoginErrors.InvalidPassword
                };

            // Login OK
            DateTime now = DateTime.Now;
            SessionInfo info = new SessionInfo()
            {
                LastLogin = now,
                Token = $"#{now.Ticks}",
            };
            return info;
        }       
    }
}


Build ServiceLibrary project

By default the ServiceLibrary project is configured to execute the $ flutnet pack command in the post-build event.

The procedure will update the "flutnet_errors_bridge" package with all the required Dart code for managing the communication between Flutter and Xamarin.


Configure the FlutnetBridge Mode

Depending on your development preferences, you could use a specific FlutnetBridge mode:

In order to set the FlutnetBridge mode, just edit the following methods:

  • App.cs → ConfigureFlutnetBridge(FlutterEngine) in Xamarin.Android app
  • ViewController → ViewDidAppear(bool) in Xamarin.iOS app
  • main.dartmain() in Flutter module

Xamarin.Android

App.cs → ConfigureFlutnetBridge(FlutterEngine)

#if (DEBUG)
  _bridge = new FlutnetBridge(flutterEngine, AppContext, FlutnetBridgeMode.PlatformChannel);
#else
  ...
#endif

 

Xamarin.iOS

ViewController.cs → ViewDidAppear(bool)

#if (DEBUG)
  _bridge = new FlutnetBridge(this.Engine, FlutnetBridgeMode.PlatformChannel);
#else
  ...
#endif

 

Flutter

main.dart 

 

import 'package:flutter/material.dart';

import 'package:flutnet_errors_bridge/flutnet_bridge.dart';

 

void main() {

  // Configure the bridge mode for debug

  FlutnetBridgeConfig.mode = FlutnetBridgeMode.PlatformChannel;

  runApp(MyApp());

}


Develop your user interface in Flutter

// Import the login service and related types

import 'package:flutnet_errors_bridge/flutnet_errors/service_library/login_service.dart';

import 'package:flutnet_errors_bridge/flutnet_errors/service_library/session_info.dart';

import 'package:flutnet_errors_bridge/flutnet_errors/service_library/login_exception.dart';

import 'package:flutnet_errors_bridge/flutnet_errors/service_library/login_errors.dart';

....

  // Reference to the xamarin login service

  final LoginService _loginService = LoginService("login_service");

 

  String _token;

 

  void _login(

    BuildContext context,

    String username,

    String password,

    bool forceError,

  ) async {

    // Login using xamarin  service

    try {

      _token = null;
 

      // Perform the login operation in Xamarin: this may generate some error

      SessionInfo sessionInfo = await _loginService.login(

        username: username,

        password: password,

        forceHandleError: forceError,

      );
 

      setState(() {

        _token = sessionInfo.token;

      });
 

      // Show snackbar with success message

      showSnackbar(context, "Login succeed with token $_token", ErrorLevel.Ok);
 

    } on LoginException catch (ex) {

      // Here we have capture a specific exception from xamarin

      switch (ex.error) {

        case LoginErrors.InvalidUsername:

          showSnackbar(context, "Invalid username", ErrorLevel.Warning);

          break;

        case LoginErrors.InvalidPassword:

          showSnackbar(context, "Invalid password", ErrorLevel.Warning);

          break;

        case LoginErrors.InvalidUsernameAndPassword:

          showSnackbar(

              context, "Invalid username and password", ErrorLevel.Warning);

          break;

      }

    } on PlatformOperationException catch (pe) {

      showSnackbar(context, "$pe", ErrorLevel.Bad);

    } on Exception catch (ex) {

      showSnackbar(context, "$ex", ErrorLevel.Bad);

    }

  }

 

....


Build the Flutter project

Before running the Xamarin app, you need to build your Flutter module project ("flutnet_errors" in our case).

In order to do this, open the terminal from Visual Studio Code and run the following commands:

  • $ flutter build aar --no-profile
  • $ flutter build ios-framework --no-profile (only if you're on macOS)

Once the build is finished, you should be able to run your Xamarin app with Flutter as user interface.


Register the PlatformService

In order to expose the service to Flutter, you need to register an instance of this service on the FlutnetRuntime by specifying a proper, unique name ("login_service" in this case).

The registration must be done before the FlutnetBridge initialization. This occurs in the following methods:

  • App → ConfigureFlutnetRuntime() in Xamarin.Android app
  • ViewController → ViewDidAppear(bool) in Xamarin.iOS app

// Initialize the Flutnet environment
FlutnetRuntime.Init();

// Register the service
FlutnetRuntime.RegisterPlatformService(new LoginService(), "login_service");

...