“Digital 2019” report has shown very clearly the significance of the role of mobile devices in human life. Currently there are 5,11 billion unique mobile phone users around the world.  This means an increase of 100 million comparing to last year. Three billion 256 million of them use a smartphone as a social communication platform.

Source: wearesocial.com

On the basis of  the above data, we can conclude that a smartphone can successfully replace a PC. It is not surprising then that the mobile application market is booming. The forecasts for 2022 predict that users will spend 150 billion dollars to purchase mobile software (2017 data shows expenses of about 81 billion).

Taking this into consideration, the IT industry has to observe the market and search for new technologies, aiming at the optimization of the process of creating mobile solutions.

One of the fresh propositions is a promising framework based on Dart language. Obviously, we are talking about Flutter – a cross-platform proposition from Google.

Common UI and business logic

In theory, all frameworks intended for creating applications for many platforms boast about the possibility of using the same components for every system. In reality though, every platform has got a pre-defined set of native widgets, which should be connected with the use of suitable mapping.

Source: flutter.dev

Due to using a dedicated engine, an application written with the use of Flutter is not sensitive to frequent system updates of mobile platforms.

In comparison with its main competitor – React-Native,  rendering takes place without the need to compile the code written in Javascript to native modules.

Indeed, due to a bigger number of built-in functionalities, Flutter is a framework of a larger size. However, thanks to this, a programmer has got a significant part of predefined components ready to use.

The development of shared business logic is taking place on the basis of dedicated Dart language. Undoubtedly, it is a kind of inconvenience – but only seemingly. The language is, as it were, a compilation of already tested solutions, presented in a more approachable form.

The code below shows the comparison of Dart with the syntax of, popular nowadays, Typescript and Kotlin:

//dart

main() {
	
    String person;
    person = 'John';
    person = 'Sally';
    
    print(person);
    
    // single assignment
    final String car = 'Audi';
    
    // immutables
    const String car = 'Audi';
    
    // dynamic type
    dynamic actor = { 'name': 'Sylvester', 'surname': 'Stallone' };
    
    // lists
    List<int> furniture = ['table', 'chair', 'desk'];
    
    furniture.last;
    
}

// functions
divideByTwo(int val) {
	return val / 2; // use `~/` if you need to return integer
}

// higher order functions
sayHi(Function passedFunction) {
	return passedFunction('Hi everyone');
}
sayHi(print);


// Object Oriented Programming

main() {
	Widget fancyWidget = Widget(0, 1);
    Widget evenMoreFancyWidget = Widget.withBools(true, false);
}

class Widget{
	
    // using `_` means private values;
    Widget(_a, b);
    
    // named constructors
    Widget.withBools(_a, b);
}


// Async Programming (Future works the same as Promises in JS)

main() {
	
    Future displayWelcome() async {
    	return 'Welcome in async world';
    }
    
    inititateGreetings() async {
    	await displayWelcome();
    }
    
    initiateGreetings()
    	.then(print)
        .catchError();
}

// Stream Data Structure (for handling multiple async values)
main() async {
	vat items = Stream.fromIterable([1,2,3]);
    
    // looping over the object as it changes over time
    await for(int i in itmes) {
    	print('changed');
    }
    
    // or use listen();
    items.listen();
}
// typescript

export const main = () => {
	
    let person: string;
    person = 'John';
    person = 'Bob';
    
    console.log(person);
    
    // single assignment
    const car: string = 'Audi';
    
    // immutables
    Object.freeze(person);
    
    // dynamic type
    const actor: any = { 'name': 'Sylvester', 'surname': 'Stallone' };
    
    // lists
    const furniture: string[] = ['table', 'chair', 'desk'];
    
    furniture[furniture.length -1];
    
}

function divideByTwo(val: number) {
	return val / 2;
}

function sayHi(passedFunction: Function) {
	return passedFunction('Hi everyone');
}

sayHi(console.log);

export const main = () => {
	const fancyWidget = new Component(0, 1);
}

class Component {
	constructor(private a, public b){}
}


export const main = () => {
	
    async function displayWelcome() {
    	return 'Welcome in Async World';
    }
    
    async function initiateGreetings() {
    	await displayWelcome();
    }
    
    initiateGreetings()
    	.then(console.log)
        .catch()
}

// possible with rx.js library
export const main = () => {
	
    const items = Observable.from([1,2,3]);
    
    items.subscribe(console.log);
}
// kotlin

fun main() {
	
    var person: String = "John"
    person = "Sally"
    
    print(person)
    
    // single assignment
    val car: String = "Audi"
    
    // immutables
    val car2: String = "Bmw"
    
    // dynamic type
    val actor: Map<String, String> = mapOf(
    	"name" to "Sylvester",
        "surname" to "Stallone"
    )
    
    // lists
    val furniture: List<String> = listOf("table", "chair", "desk")
    furniture.last()

}

// functions
fun divideByTwo(value: Int):Int = value / 2

// higher order functions
fun sayHi(function: (String) -> Unit) {
	return function("Hi everyone")
}

fun test() {
	sayHi {
    	print(it)
    }
}

// Object Oriented Programming
fun test2() {
    val widget = Widget(a = 0, b = 1)
}

class Widget(private val a: Int, private val b: Int)

// Async Programming: Coroutines
suspend fun displayWelcome(): String {
    delay(100)
    return "Welcome in Async World"
}

fun test3() {
	GlobalScope.launch{
    	val token:String = displayWelcome()
        print(token);
    }
}

// Coroutines - Flow
fun items(): Flow<Int> = (1..3).asFlow()
	.onEach { delay(100) }
    .flowOn(Dispatchers.Default)
    
fun test4() {
	runBlocking {
    	items()
            .onEach { item -> println(item) }
            .collect()
    }
}

Saving time and resources

The development of a mobile application imposes frequent recompilation of the source code. There are simulators available, which allow for working with a virtual device, but such solutions are fallible and slow. Flutter meets such needs and allows for development with the use of a mobile devices simulator with hot-reload function, which can remember the current condition of a component. As a result, after recompilation, the programmer is forwarded to the same screen at which he declared the will to make the change. What is important, the prompt work of the mechanism is not influenced by the size of the application.

Another advantage of the compiler is the well thought-out error message mechanism. Exception occurrence does not mean critical error which blocks rendering the screen totally. If the error is lower in the component tree, the higher order widgets should still appear correctly on the screen.

An important argument is also the possibility of development with simultaneous simulation of a device with IOS and Android. However, a machine with MacOs systems turns out to be needed here.

Additionally, IDE plugin will allow for using accessible functions/variables, convenient debugging, formatting and navigation in the project.

The widget you want

The advantage of Flutter is also a wide range of ready to use and easy to modify widgets, based on commonly used Material-UI. Thanks to this it is possible to significantly reduce the time needed for screen design.

A childhood disease?

Flutter is a fresh solution. What speaks against it?

Apart from the screen design and facilities such as customizable widgets ready to use, the added plugins allow for the use of native functionalities of devices such as GPS signal reading and Bluetooth communication. Using them is based on a few simple steps. Let’s discuss it using the example of adding GPS service module.

The first step is the necessity to add a suitable extension. In order to use location module we need google_maps_flutter, location plugins.

The names of the above mentioned extensions must be added to „dependencies” section in pubspec.yaml file.

dependencies:
    google_maps_flutter: ^0.5.21+15
    location: ^2.3.5
    flutter:
    	sdk: flutter

The next step is to allow permission to our app to use location module and to assign IP key in order to be able to apply the position onto maps provided by Google (the procedure of getting an own IP key is available here). Following the example of an application with Android we add to the manifest in the file AndroidManifest.xml records:

<uses-premission android:name="android.permission.ACCESS_FINE_LOCATION" />

<application ...
	<meta-data android:name="com.google.android.geo.API_KEY"
    	android:value="AIazaasdfasdf_Sb-MCaasdfasgjhttybg3" />

The next step is the necessity to modify file build.gradle through adding records responsible for Google service permissions:

dependencies {
	classpath 'com.google.gms:google-services:4.2.0'
}

Let’s move to implementation. Our aim is to create a simple application displaying the current position of the device on the map. In main.dart file, which is the main project file, we place the component delivered with google_maps_flutter  file. The library contains a number of properties allowing for providing the displayed map with required features. The selection of the kind of displayed map is possible thanks to mapType parameter. Hybrid value means rendering the map with satellite image, with interactive points applied. InitialCameraPosition lets us set the initial display on the map.

OnMapCreated in turn, is a link to the method used during the user’s interaction with the application. This method should cause updating the position on the map.

Markers and circles parameters are responsible for graphic interpretation of the device location point and the circumference in which the device is located.

body: GoogleMap(
	mapType: MapType.hybrid,
    initialCameraPosition: initialLocation,
    markers: Set.of((marker != null) ? [marker] : []),
    circles: Set.of((circle != null) ? [circle] : []),
    onMapCreated: (GoogleMapController controller) {
    	_controller = controller;
    },
)

The next component is the button used for updating the position on the map.

floatingActionButton: FloatingActionButton(
	child: Icon(Icons.location_searching),
    onPressed: () {
    	getCurrentLocation();
    }
),

GetCurrentLocation method uses location extension and its accessible functionalities for communication with GPS module.

void getCurrentLocation() async {
	try {
    	Uint8List imageData = await getMarkers();
        var location = await _locationTracker.getLocation();
        
        updateMarkerAndCircle(location, iamgeData);
        
        if(_locationSubscription != null) {
        	_locationSubscription.cancel();
        }
        
        _locationSubscription = _locationTracker.onLocationChange().listen((newLocalData) {
        	if (_controller != null) {
            	_controller.animateCamera(CameraUpdate.newCameraPosition(new CameraPosition(
                bearing: 192.8934242312,
                target: LatLang(newLocatData.latitude, newLocalData.longitude),
                tilt: 0,
                zoom: 18.00
                )));
                updateMarkerAndCircle(newLocalData, imageData);
            }
        });
    } on PlatformException catch(e) {
        if (e.code == 'PERMISSION_DENIED') {
            debugPrint("Permission Denied");
        }
    }
}

UpdateMarkerAndCircle method is used for updating the location of the tag relative to the map and initiating change on the screen. It also allows for setting properties such as:

- marker rotation,

- whether the marker will always be rendered on the top layer (always on top),

- the position of the marker relative to the centre of the screen,

- graphical representation of the marker (any graphics, from a point up to the graphics of a car),

These are, however, details of a particular solution. The key aspect is the convenience of using GPS module which Flutter provides us with.

Mobile or WWW? Or perhaps both?

Google aims high. Rumor has it that Flutter wants to claim to be the first tool used for creating both mobile and web applications. The official documentation contains step by step instruction on how to prepare environment allowing for creating a WWW application.

It is a very bold vision, but by all means in line with the current needs of the market. Mobile and web applications, based on a single tool – this is every programmer’s dream.

Still, a long time will be needed to dethrone Javascript and tens of web frameworks.

Flutter for Business? Yes, but …

The choice of technology is the key element of planning an IT project. A product created for a big institution must be reliable, efficient in operation and easy to extend, with possibly low development costs.

The community gathered in forums dedicated to the development of this framework makes us assume that many developers are keenly interested in using it in their projects. Annual research done by Stack Overflow confirms that in 2019 Dart won the favour of programmers and has the second position in the “Most Loved” ranking, just after Javascript.

Source: https://insights.stackoverflow.com/survey/2019#most-loved-dreaded-and-wanted

What is more, the number of companies using the technology is increasing. These are, among others:

Alibaba and its advertising service „Xianyu”:

Source: https://www.chinainternetwatch.com/

Ebay and EbayMotors:

Source: https://www.ebay.com/

Groupon with „Groupon Merchants” service:

Source: https://www.groupon.com/merchant/article/groupon-merchant-app-gets-makeover

or Cinkciarz.pl

Source: https://cinkciarz.pl/o-nas/nasze-aplikacje/smartphone

The project of a Brasilian neobank NuBank is interesting from the perspective of banking institutions. Due to the character of its operation, the institution is entirely based on mobile solutions. Initially, the company based on creating dedicated solutions for IOS and Android.

The fast growing market imposes constant adjustment to the needs of customers and enforces offering of newer and newer products. Due to these challenges it is necessary to satisfy the user needs fast and minimize the cost, and maintain the consistency of the work of the application. React-Native was going to be the first choice which was supposed to introduce NuBank into the era of cross-platform solutions. Despite the fact that the product, based on the above mentioned technology, was successful, it didn’t solve basic problems because maintenance of a large application requires a team of programmers who are familiar with the technology used.

On the basis of the experience gained, first during the development of native applications and then while using React-Native, and finally creating the test version of the application with the use of Flutter, the team of programmers decided to use it to implement every new functionality.

Please find more details here, where you can find a detailed report of the analysis made by the team of NuBank.

Summing up, the simplicity of implementation and the speed at which the application works have prevailed. The perspective of a long-term support due to Google’s infrastructure also plays the vital role here.

The example of NuBank shows that well thought-out and well-designed cross-platform frameworks make sense and it is not a myth.

If you would like to read more posts about Flutter, do not hesitate to drop us a message. Also you can follow us on Twitter and LinkedIn to be up to date with new posts.