Flutter - How to reduce App Size on Device

8,686

My answer is based on Official document,


Apart From these, you need to enable proguard to reduce the size of apk as well as it prevents the app reverse engineering. In Flutter,

To make your app as small as possible, you should enable shrinking in your release build to remove unused code and resources.

By default, Flutter does not obfuscate or minify the Android host. If you intend to use third-party Java, Kotlin, or Android libraries, you might want to reduce the size of the APK or protect that code from reverse engineering.

Follow this link to enable progaurd in your app,

Step 1: Step 1 - Configure Proguard Create a /android/app/proguard-rules.pro file and add the rules listed below.

## Flutter wrapper
-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.**  { *; }
-dontwarn io.flutter.embedding.**

Step 2: Enable obfuscation and/or minification

android {

    ...

    buildTypes {

        release {

            signingConfig signingConfigs.release

            minifyEnabled true
            shrinkResources true// to shrink your image resource read more at https://developer.android.com/studio/build/shrink-code
            useProguard true// enables progaurd

            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        }
    }

Note: Use Proguard only in production apk.

Also, read Why does my app size on device differ than the APK or Play store size


An app depends on native libs too and most native libraries are android framework libraries that are available on the device also, so they won't get bundled in the apk/aab. But these libs will be included in the odex files and hence expands its size when installed.

Question: What is the possible prevention?

Answer: Minimize resource use from libraries

If a library was designed for a server or desktop, it can include many objects and methods that your app doesn’t need. To include only the parts of the library that your app needs, you can edit the library's files if the license allows you to modify the library. You can also use an alternative, mobile-friendly library to add specific functionality to your app.

Note: code shrinking can clean up some of a library's unnecessary code, but it might not be able to remove some large internal dependencies.

Also read Steps mentioned here

https://developer.android.com/topic/performance/reduce-apk-size#reduce-code

Share:
8,686
questionasker
Author by

questionasker

I'm Web, Unity3D & Flutter Developer. I love to share my ideas at my web, please visit my website for any tutorial related to marketing, programming, docker, linux, etc

Updated on December 16, 2022

Comments

  • questionasker
    questionasker over 1 year

    My App Bundle Download Size in Google PlayStore is around 23 MB:

    enter image description here

    But Why after installed, the App Size on Disk raises significantly to 83 MB:

    enter image description here

    enter image description here

    Any Idea why this happens, because:

    1) Flutter's assets file (images, sound & fonts) on projects only around 11 MB

    2) Size of Flutter Source Code (.dart) on disk only 1.4 MB

    3) Android Native Resource/icon (Res) only around 800 KB

    regarding flutter's plugin i use below:

    dependencies:
      flutter:
        sdk: flutter
      flutter_localizations:
        sdk: flutter
      angles: ^1.0.1
      app_settings: ^1.0.5
      archive: ^2.0.8
      cached_network_image: ^1.1.1
      carousel_slider: ^1.3.0
      cron: ^0.2.1
      crypto: ^2.0.6
      cupertino_icons: ^0.1.2
      date_format: ^1.0.5
      device_id: ^0.1.3
      dio: ^2.0.0
      easy_alert: ^0.0.2
      localstorage: ^2.0.0
      audioplayers: ^0.13.1
      path_provider: ^1.1.0
      esys_flutter_share: ^1.0.2
      flutter_compass: ^0.3.2
      flutter_html: ^0.9.6
      flutter_local_notifications: ^0.8.2
      flutter_offline: ^0.2.4+1
      flutter_swiper: ^1.1.6
      flutter_xlider: ^2.4.5
      font_awesome_flutter: ^8.2.0
      geolocator: ^5.0.1
      google_maps_flutter: ^0.2.0
      google_sign_in: ^4.0.1+1
      http: ^0.12.0+2
      libcalendar: ^0.2.0
      location : ^2.3.0
      numberpicker: ^1.0.0
      pigment: ^1.0.3
      rxdart: ^0.21.0
      shared_preferences: ^0.5.1+1
      shimmer: ^1.0.0
      unicode: ^0.1.0
      url_launcher: ^5.0.2
      validate: ^1.6.0
      vibrate: ^0.0.4
      after_layout: ^1.0.7+2
      draggable_scrollbar: ^0.0.4
      flutter_web_browser: ^0.11.0
      flutter_youtube: ^1.1.6
      google_api_availability: ^2.0.1
      indexed_list_view: ^0.0.5
      permission_handler: ^3.1.0
      queries: ^0.1.4
      rect_getter: ^0.0.1
      scroll_to_index: any
      sqflite: ^1.1.5
      tuple: ^1.0.2
      xml2json: ^3.0.3
      firebase_messaging: ^5.1.6
      firebase_analytics: ^3.0.2
      firebase_core: ^0.4.0+3
      firebase_auth: ^0.11.1+6
      firebase_admob: ^0.9.0+1
      firebase_in_app_messaging: ^0.0.1+3
      superellipse_shape: ^0.1.5
      device_info: ^0.4.0+2
      in_app_purchase: ^0.2.0+6
      sentry: any
      system_info: ^0.1.1
      highlighter_coachmark: ^0.0.3
      volume: ^0.1.0
      admob_flutter: ^0.3.2
      bubble_tab_indicator: "^0.1.4"
      material_design_icons_flutter: ^3.0.3289
      scoped_model: ^1.0.1
      flutter_slidable: ^0.4.9
      kiwi: ^0.1.0
      flutter_markdown: ^0.2.0
      flutter_downloader: ^1.2.1
      native_ads: ^0.2.0  
      onesignal_flutter: ^2.0.0
    

    Any Idea How to reduce App On Size?

    Thank You in Advance...

    UPDATE

    If I set minifyEnabled = true and shrinkResources = true (as suggested by Ravinder Kumar) in my build.gradle then it will generate a very long error, here's the log:

    == Building for Android ==

    ... ( I cut the error log because of very long, but full log can bee seen here: https://www.dropbox.com/s/jy92d1lmj9pgb6d/full_flutter_error_log.txt?dl=0 )

    Note: the configuration keeps the entry point 'io.flutter.plugins.googlesignin.GoogleSignInPlugin$Delegate$3 { void onComplete(com.google.android.gms.tasks.Task); }', but not the descriptor class 'com.google.android.gms.tasks.Task'

    Note: the configuration keeps the entry point 'io.flutter.plugins.inapppurchase.Translator { java.util.HashMap fromSkuDetail(com.android.billingclient.api.SkuDetails); }', but not the descriptor class 'com.android.billingclient.api.SkuDetails'

    Note: the configuration keeps the entry point 'io.flutter.plugins.inapppurchase.Translator { java.util.HashMap fromPurchase(com.android.billingclient.api.Purchase); }', but not the descriptor class 'com.android.billingclient.api.Purchase'

    Note: the configuration keeps the entry point 'io.flutter.plugins.inapppurchase.Translator { java.util.HashMap fromPurchasesResult(com.android.billingclient.api.Purchase$PurchasesResult); }', but not the descriptor class 'com.android.billingclient.api.Purchase$PurchasesResult'

    Note: there were 7 references to unknown classes.

         You should check your configuration for typos.
    
        (http://proguard.sourceforge.net/manual/troubleshooting.html#unknownclass)
    

    Note: there were 3 references to unknown class members.

         You should check your configuration for typos.
    

    Note: there were 242 unkept descriptor classes in kept class members.

         You should consider explicitly keeping the mentioned classes
    
         (using '-keep').
    
         (http://proguard.sourceforge.net/manual/troubleshooting.html#descriptorclass)
    

    Note: there were 68 unresolved dynamic references to classes or interfaces.

         You should check if you need to specify additional program jars.
    
         (http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
    

    Warning: there were 25 unresolved references to classes or interfaces.

            You may need to add missing library jars or update their versions.
    
            If your code works fine without the missing classes, you can suppress
    
            the warnings with '-dontwarn' options.
    
            (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)
    

    Warning: there were 2 unresolved references to library class members.

            You probably need to update the library versions.
    
            (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedlibraryclassmember)
    

    Warning: Exception while processing task java.io.IOException: Please correct the above warnings first.

    Thread(Tasks limiter_1): destruction Running Gradle task 'bundleRelease'... 690.7s (!)

    ************************************************************************>******************* The Gradle failure may have been because of AndroidX >incompatibilities in this Flutter app. See "https : //goo.gl / CP92wY" for more information on the problem and >how to fix it. ************************************************************************>******************* Gradle task bundleRelease failed with exit code 1

    Build failed :| Failed to build for Android

    btw, below is my proguard-rules.pro:

    #Flutter Wrapper
    -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 class com.baseflow.** { *; }
    #-keep class com.chartboost.** { *; }
    
    -dontwarn com.google.common.base.**
    -keep class com.google.common.base.** {*;}
    -dontwarn com.google.errorprone.annotations.**
    -keep class com.google.errorprone.annotations.** {*;}
    -dontwarn com.google.j2objc.annotations.**
    -keep class com.google.j2objc.annotations.** { *; }
    -dontwarn java.lang.ClassValue
    -keep class java.lang.ClassValue { *; }
    -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
    -keep class org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement { *; }