Up to this year, options for mobile cross-platform development were somehow limited and applications were made with one or another JavaScript framework (ex. Cordova, Ionic, React Native) or working with Xamarin (based on C#).
“And Now for Something Completely Different”: Flutter
In February 2018, Google announced that Flutter is ready for beta program and started to actively advertise to use it to build production apps. Since that time we could see 2 other beta versions of Flutter. And more: at Google I/O they announced that they are planning to release its first stable product next year.
Differences:
Language
The main difference from other cross-platform frameworks is that Flutter is based on Dart language. Dart was created by Google initially as a replacement for JavaScript – they still suggest using Dart with their web framework – Angular. Dart is similar to some of the most popular languages like Java, C++ or C#. It can be compiled to JavaScript and native ARM or x86 code, is optimized for dealing with a lot of short-lived objects, has built-in support for asynchronous computation in the form of Futures and Streams and more.
Example:
import 'dart:math';
int nextRandom(int maxValue) {
return Random().nextInt(maxValue);
}
main() {
var max = 10;
for (var i = 0; i < 10; i++) {
print("Next random value = ${nextRandom(max)}");
}
}
Native rendering
Unlike other solutions, Flutter applications do not depend on platform native UI controls. Instead, they use Skia 2D graphic engine to draw every UI control directly to the screen. It has two major benefits: first – UI performance is better than in other cross-platform solutions because there is no bottleneck in form of bridge between UI state build from Dart and native UI controls; second – you have full control over the UI look-and-feel, your UI controls would be rendered the same, both on Android and iOS.
Main features:
Widgets! Widgets everywhere!
Flutter UI is built with usage of a modern react-style framework, which takes inspiration from React. Every part of the screen is built using widgets within widgets within widgets. Because the main app layout (toolbars, navigation etc.) is a widget, you can even wrap that inside other widgets and make it look look like an app within an app. Widgets are used extensively to decorate inner widgets with properties, for example there is Padding
widget that adds some space around its child, GestureDetector
makes the child widget react to user interactions and so on.
Widgets come in two flavors: stateless and stateful. Stateless widgets are the simplest blocks - their only reason is to render itself properly. Stateful widgets have a state that impacts on how they would build their inner widgets tree. They are parts of the UI that would be rendered again whenever their state would change.
import 'package:flutter/material.dart';
void main() {
runApp(HelloWidget());
}
class HelloWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Material(
color: const Color.fromARGB(255, 250, 105, 60),
child: Container(
alignment: Alignment.center,
child: const Text(
'Hello world!',
style: TextStyle(color: Colors.white),
textDirection: TextDirection.ltr,
),
),
);
}
}
Hot reloading
Flutter applications can be built in two ways: compiled (contains platform-specific native code only) and interpreted. In interpreted mode the application contains the whole Dart VM to run Dart source code. That makes it possible to switch the code while the application is running. Even more, the application can often keep its state through code reload making small updates possible in just a matter of seconds. It is really beneficial when you are learning or just playing with the code – you can check if your current solution works as expected or you still need to change something.
Material Design support
Flutter is packed with a lot of Material Design-style widgets and they are available right off the bat – you don’t need to use any external library to make your application’s UI compatible with Material Design. But if you want to use iOS UI components then it is almost as easy as using Material ones – Flutter is provided with package:cupertino
containing widgets styled in iOS way.
Testing
Flutter is provided with an easy-to-use testing framework. Basically you can write all necessary tests using build-in test frameworks. Package package:test
contains API for unit testing your business logic, package:flutter_test
allows to test a single widget without running application and integration tests are also possible using API provided in package:flutter_driver
. You don’t need any external tools or libraries to run all tests you may need. Below is a demo of what a widget test may look like.
import 'package:flutter_test/flutter_test.dart';
import 'package:example/main.dart';
void main() {
testWidgets('Hello world smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const HelloWidget());
// Verify that correct text has been displayed.
expect(find.text('Hello world!'), findsOneWidget);
});
}
Summary
Pros:
- easy to learn, rich language,
- fast development,
- easy testing (even UI testing),
- single codebase for Android and iOS,
- rich documentation.
Cons:
- still in beta – there is over 3000 issues registered on Flutter’s GitHub repository and codebase is changing rapidly,
- not so many examples,
- not many plugins – some features may not be easy to implement.
Flutter is definitely a good option for building production ready apps – you can see here that some companies use it in production applications. If you are interested in more information then go to official documentation – you can find there a lot of examples and guides about Flutter.