A Complete Guide to Enhancing Flutter App Performance on Android and iOS

Diwe innocentDiwe innocent
6 min read

Flutter has become a powerful tool for building cross-platform applications, allowing developers to create stunning, high-performance apps for Android and iOS with a single codebase. However, as your app grows, you may face issues with larger app sizes, slower load times, and performance limitations. This article will walk you through effective techniques to optimize your Flutter app for Android and iOS.

Why Optimize?

An optimized app isn’t just about reducing size; it’s also about delivering faster load times, seamless navigation, and an overall better user experience. Optimization can improve:

  • Download and Installation Time: Smaller apps download faster and are more likely to retain users through the installation process.

  • Performance: Efficient resource management improves runtime performance, making apps smoother and more responsive.

  • User Retention: Optimized apps consume less memory and battery, providing a better experience that keeps users coming back.

Let’s get started with essential optimization techniques!


1. Reduce App Size by Removing Unused Code

Flutter automatically removes unused code via tree shaking, but you can go further by:

  • Avoiding oversized packages if you only need limited features.

  • Regularly auditing your pubspec.yaml to remove unnecessary dependencies.

  • Running flutter analyze to check for unused imports and code that may be safely removed.

Tree Shaking on Flutter

Tree shaking is enabled by default for production builds in Flutter, meaning unused code and libraries are removed automatically. But keeping your app lightweight by minimizing dependencies will reduce your reliance on this alone.

2. Optimize and Compress Image Assets

Images can be some of the largest contributors to app size, so consider:

  • Using SVGs: Vector graphics scale without losing quality and take up less space. Use the flutter_svg package to render SVGs.

  • Compressing Images: Use image compression tools like TinyPNG or ImageOptim to reduce file size without quality loss.

  • Asset Variants: For Android, create multiple versions of images (drawable-xxhdpi, drawable-xhdpi, etc.) to avoid excessive resizing on various screen resolutions.

Example:

dependencies:
  flutter_svg: ^1.0.0

3. Split APKs by ABI (Android)

On Android, splitting the APK by ABI (Application Binary Interface) is crucial. This creates APKs specific to different device architectures (like armeabi-v7a, arm64-v8a, x86, etc.), which reduces the app size for users by delivering only the required resources.

To enable ABI splits, add the following to your android/app/build.gradle file:

android {
    ...
    splits {
        abi {
            enable true
            reset()
            include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
            universalApk false
        }
    }
}

Alternatively, when building your app in release mode, you can use the command:

flutter build apk --split-per-abi

This will generate separate APK files for each ABI, reducing the app’s size for each specific device architecture.


4. Enable Proguard for Android

Proguard can minify, obfuscate, and optimize your code, which can significantly reduce APK size, especially if your app uses large libraries.

To enable Proguard, make sure to:

  • Set minifyEnabled true in android/app/build.gradle.

  • Customize the Proguard configuration to avoid removing necessary classes, particularly if you’re using complex libraries like Firebase.

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
    }
}

Here’s an example configuration in the proguard-rules.pro file to keep essential Flutter, Firebase, Agora, and native classes intact:

# Keep Flutter-related classes
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }

# Keep Agora RTC Engine classes
-keep class io.agora.** { *; }
-dontwarn io.agora.**

# Keep Firebase and Firestore classes
-keep class com.google.firebase.** { *; }
-keep class com.google.firestore.** { *; }
-keep class com.google.android.gms.** { *; }
-dontwarn com.google.firebase.**
-dontwarn com.google.firestore.**

# Keep all native methods
-keepclasseswithmembers class * {
    native <methods>;
}

# Keep all annotations
-keepattributes *Annotation*

# Keep all serializable classes
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# Keep all enum values
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# Keep the main entry point
-keep class com.example.myapp.MainActivity {
    public static void main(java.lang.String[]);
}

# Keep line numbers for debugging
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable

5. Remove Debug Information in Release Builds

For release builds, include the --release flag when building the app to strip out debug symbols and metadata. This reduces the app’s overall size significantly. Build a release version with:

flutter build apk --release
flutter build ios --release

This approach not only reduces size but also ensures that your app runs in a fully optimized environment.

6. Optimize for iOS with Bitcode

For iOS apps, Bitcode allows Apple to recompile your app and optimize it for each device. Bitcode is enabled by default in Xcode, but if you’ve disabled it, you can re-enable it in your project settings:

  1. Open your project in Xcode.

  2. Go to Build Settings > Build Options.

  3. Ensure that Enable Bitcode is set to Yes.

7. Enable iOS App Slicing

For iOS, App Slicing helps in reducing the app size by creating tailored versions of the app’s resources for different devices. This process automatically happens when you submit your app to the App Store, so there’s no extra setup required.

8. Use Minimal Packages

Carefully choose and limit the number of packages you include. Some packages are large and could bloat the app. Additionally, regularly audit your dependencies and replace heavy packages with lightweight alternatives or custom implementations where possible.

9. Use flutter build appbundle for Android

Google Play prefers Android App Bundles (AAB) over APKs for distribution, as they allow for dynamic delivery to users based on their specific device configuration, optimizing app size and download time.

Build an app bundle with:

flutter build appbundle

10. Profiling and Analyzing Your App’s Performance

Profiling your app’s performance helps identify resource-hungry sections of the code. Use Flutter’s performance profiling tools by running:

flutter run --profile

This command launches your app in profile mode, where you can monitor memory and CPU usage, frame rates, and more. Flutter’s DevTools can further help visualize and diagnose performance issues in real time.

Conclusion

Optimizing a Flutter app for Android and iOS requires some thoughtful strategies around resource management, code organization, and platform-specific configurations. By implementing these optimization techniques, you can reduce your app’s size, improve performance, and deliver a better user experience across both platforms.

Whether you’re building an MVP or a production-ready application, the above tips will help you get the most out of your Flutter app. Happy coding! 🚀

Feel free to share your thoughts or additional tips in the comments. Let’s keep building high-quality, efficient apps with Flutter!

0
Subscribe to my newsletter

Read articles from Diwe innocent directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Diwe innocent
Diwe innocent