In a previous article, we've already explained why writing an application on Flutter is a beneficial idea. Now it's time to expand the topic and make a more detailed analysis of the platform.
We're ready to share our experience in exploiting this technology which we gained while working on a commercial mobile app. You'll learn about our impressions, about Flutter cons and pros, and much more. In other words, you'll find out how to use Flutter to your advantage.
Benefits of the Flutter framework
Flutter is by no means the only cross-platform solution but it is one of the first, good enough to be widely adopted because of its simplicity, fast work, and ease of interaction with native code. Flutter is truly an amazing mobile development tool.
Let us prove our point by listing the Flutter pros:
-
Programming language of Flutter. Flutter uses the Dart programming language which is very simple and clear. By the way, its syntax is similar to Java, and that’s a good thing for Android developers since such similarity greatly simplifies the process of learning Dart: in the end, all Android developers are somewhat familiar with Java. Of course, Dart is not Kotlin (to which Android experts have long been accustomed) but its syntax is less strict than Java's is, so writing in this language is rather pleasant. Speaking of iOS developers, they, too, admit that Dart is easy enough to work with.
-
Default tools. Also, we were pleased with a lot of tools working right out of the box. So, there is no need to have recourse to third-party libraries from the outset (although, there are plenty of them either).
-
Extensive documentation. Yes, the documentation is very detailed, with helpful examples, and most of the information can be obtained from there. It makes learning Flutter much easier.
-
Native interfaces. Of course, we could not help but appreciate the possibility of implementing iOS and Android native interfaces. If your user wants the interface to look exactly the same on both platforms, Flutter has everything to make it true.
-
Great features. There are many interesting features, and one of the coolest is Hot reload. And we sincerely hope it’ll only improve over time.
Some of the Flutter cons
Of course, we would distort the truth by saying that Flutter has no flaws. Any technology, especially a relatively new one (and Flutter IS rather new) has not only pros but also cons. And we’re ready to share our impressions of what we were unhappy with.
Issues with images
The first thing we didn't like about Flutter was the work with images. However, let's look at these issues for iOS and Android platforms separately.
Android & image problems
To make everything clear, we should approach the problem from different angles.
#1. Loading local images
The application we were working on forced us to use a large number of local png-images. The task seems to be extremely simple... but no, everything went awry from the very first stages of development (at least regarding the loading of local pictures; in many other aspects, as we’ve said, the process of building an app with Flutter pleased us).
To load local images, you can make use of AssetImage and Image.asset (follow the link to find more details). And while you’re dealing with pictures up to 200 kb., everything works perfectly. But using images larger than 1 MB to create a screen background leads to several problems (which appear immediately).
Primarily, If the background image is too heavy, then it'll be loaded asynchronously, which means the user will get negative impressions about the application when switching to this screen. Why? Because elements of the app screen will be displayed in the first place (buttons, text fields, etc.), and the background image will appear only after a while. Not exactly what the user is expecting, right?
Discussing other complications (concerning the work with pics) taking place when writing an application on Flutter, we can say we were displeased with the fact that the framework has no native SVG support. There is only a separate Plugin allowing to work with such images.
#2. Loading images by URL
To load images by URL, you can use either a special NetworkImage class or Image.network (). Also, there is a NetworkImageWithRetry (if you need a more advanced level).
These classes work just fine - but they do so only until you decide to use Firebase Crashlytics in your application. If you want to get all crashes into the console, you’ll have to enable the forceCrash flag which will stop your app in the usual way. But if difficulties arise during image loading, NetworkImage returns an error, which intercepts the crashlitics plugin and closes the application. You won't be able to wrap the widgets in try-catch. Moreover, your attempts to finalize the problem using standard class methods would be ineffective.
Our Android developers managed to solve the issue only by creating a class similar to NetworkImage and replacing the lines of code from throw to load the local placeholder.
iOS & image problems
Now let's consider how you should use Flutter and work with images in the case of the iOS platform. What pitfalls should you take into account?
#1. Loading local images
And again, about loading local pictures… Remember, we said what happens with the Android application if the background image is too heavy? When it comes to iOS, the problem is a bit different since there is no feeling of the image being loaded asynchronously. Though, when you open this screen, the entire interface seems to be going down, even on top devices.
We advise either to use only the color to fill the background screen, or to choose the lightest images possible.
#2. A slow working graphics editor
Another problem faced by iOS developers is a graphics editor. The fact is that it works rather slowly when a gradient is being imposed on an image with a higher resolution (we mean cases when the picture resolution is greater than that of the device's screen in width or height).
By the way, in Flutter, a LinearGradient object is responsible for working with the gradient.
GiFs
The problem is common to both platforms. The situation is quite simple: unlike native programming languages, Flutter doesn’t have a convenient native listener implementation to end gif-animation. The only option possible in the case of Dart programming language is the following sequence of actions.
So, you first need to figure out the number of frames in the gif animation. Then you should resort to the help of the resolve method to determine that the old frame of the ImageStream object has been replaced with a new one. Next, you must increase your counter by +1. As soon as your counter coincides with the total number of frames, the animation will be considered complete.
Another problem is the difficulty of replacing a gif image with a new animation without blinking and other undesirable effects (provided the new animation continues the old one). If you call setState (), a blink occurs between the disappearance of one gif picture and the display of another.
Layout
The most time-consuming part of learning Flutter is the layout.
First of all, let's say the layout is being created directly in the code. Simply put, we describe (in the code) each subsequent screen element (widget) inside the previous one (according to the nesting principle). And sometimes this or that widget is not displayed.
For example, if you paste Expand in OrientationBuilder, the compiler won't warn you beforehand, and you'll see the result, or rather its absence, only after launching the application (yes, the layout has no graphical interface).
In general, the interface itself is mainly built on Row and Column, which allows applications to look almost identical on completely different screens. But if you need to arrange the elements in a custom way, you have to use MultiChildLayout. The usual school geometry course will be enough to understand all this. However, you'll have to figure it out yourself, since there is very little information, other than official documentation (at least at the time of our writing).
Caching
Another item on the list of Flutter cons is a problem with caching.
Say, if you delete an image from a project and then build it, there is a chance that after you start the application, the program would display the picture anyway (since it will still be stored in the cache).
Therefore, you have to execute the flutter clean command in the terminal or call the Invalidate caches / Restart command in Android Studio (since Flutter didn’t provide the Clean build feature for Android Studio).
Firebase Cloud Messaging
Another issue concerns Firebase Cloud Messaging. If you use the library, then when you first start the application (after installing it), you won’t receive the token to get push notification messages.
The issue can be solved by the following code:
Stream<String> fcmStream = _firebaseMessaging.onTokenRefresh;
fcmStream.listen((token) {
If (token != null) {
// saveToken(token);
}
});
Some are also concerned about firebase cloud messaging pricing, but the cost issue is not directly related to the process of creating an app with Flutter.
Firebase Push Notification
Among the unpleasant moments that happened during the process of writing an application on Flutter was the experience of using the plugin named Firebase Push Notification.
The plugin is a wrapper over standard Android services for Firebase messaging and iOS classes. And when it comes to commercial apps, the biggest problem is that the Firebase Push Notification plugin doesn’t support parsing the data block when the application is removed from the tray (we’re speaking of the Android platform). In most cases, it makes the use of such a block completely useless.
On the other hand, the notification block is limited to only a few fields and can be automatically processed upon admission to the device, which is not always necessary. The proper solution to the problem is to copy the plugin’s classes and add them to your code (and recycling Android classes to your needs). And such advice will work in the case of other plugins too, for most of them are regular wrappers over standard classes written in native code and used in Flutter through Platform Channel.
Work with third-party libraries
And finally, we'd like to mention third-party libraries integration among Flutter's cons - or rather, problems during the process.
#1. Adding an extension to a project
Imagine you need to add an extension to a project (say, Notification Service Extension, Watch Extension, and so on). In such a case, Xcode is likely to generate an error during the build.
These errors occur only if your project contains third-party libraries. Alas, at the time of our writing, the issue is still open.
#2. The work of third-party libraries
In the process of writing an application on Flutter, you must keep in mind a lot of nuances, which can occur in the work of third-party libraries (especially regarding the iOS platform). The fact is some of them use outdated methods in objective-c, which leads to various problems. In addition, there are cases when not all the requirements of iOS guidelines are met. Here is a good example: using the image_picker library (0.5.0 + 3 version), we found no warnings about requesting permission to use the gallery with photo/video.
According to our experts, these problems of third-party libraries are caused by two reasons:
-
Most likely, such libraries were written by Android developers who are not familiar with the iOS requirements. Although, in theory, if the library is aimed at both platforms, at least one iOS developer and one Android developer should take part in its development.
-
Flutter is a relatively new framework. Over time, more stable and high-quality third-party libraries will probably appear.
#3. Application loading on TestFlight
There is another issue associated with the use of third-party libraries, which is important to consider when creating an app with Flutter. After downloading the application to TestFlight, you may receive an email from Apple (we mean in the case of using these libraries).
If you have no desire to receive such a letter, choose Pods before archiving the project (Pods is on the same level as your project in the hierarchy) in Xcode.
In the project editor, select the Build Settings tab and find the Debug Information Format field. Then you have to replace DWARF with dSYM File with DWARF in Release.
Another solution is to write a script, which is able to perform the above actions automatically each time before archiving or updating/installing new pods (since each time the application is started, Flutter executes the pod install command).
That's all the problems we encountered when working with Flutter... but if you want to know more about the framework, click here to visit the official Flutter website.
Summary
Summing up, we'd like to say that Flutter has great potential as a cross-platform technology. And we think its new versions are likely to have far fewer issues, which means it'll be possible to safely, quickly (and with pleasure) develop large full-featured projects. Even now, the benefits of Flutter framework surpass all the problems described.