dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.91k stars 526 forks source link

App size is too large in Release mode with several native binded libraries #8530

Open espritm opened 9 months ago

espritm commented 9 months ago

Android application type

.NET Android (net7.0-android, etc.)

Affected platform version

VSMac 17.6.3 (build 421)

Description

I am rewritting a native Android and iOS application into a single MAUI application. This application uses 4 main native libraries, that I have binded successfully.

Those native libraries has many dependancies, sush as com.vonage:webrtc which is a 200MB aar for instance.

For iOS, the final Release ipa is 210Mb, versus 50MB with the one built in native with Swift and xCode. For Android, the final Release apk is 400MB, versus 90MB with the one build in native with Java and Android Studio.

In Debug, apk size is 49MB... And the limit to publish an app to the Play Store is 200MB.

How can I reduce the size please ? Is it an issue with binded library ? I really need to go under 200MB, else it is a show stopper :x After months of binding, I cannot believe it.

I've tried to follow those advices https://devblogs.microsoft.com/dotnet/dotnet-7-performance-improvements-in-dotnet-maui

Steps to Reproduce

Use the following repo to compare build size https://github.com/espritm/MAUI.Binding_Libraries_App_Size_Perfs

It is a sample MAUI app with a dependency to one of the 4 main library I have binded (ESignature). Building the app without the dependency gives a 9MB apk. Building the app with the dependency in Debug gives a 28MB. Building the app with the dependency in Release gives a 84MB.

Did you find any workaround?

No, I cannot publish to the store because of the apk size.

Relevant log output

No response

jpobst commented 9 months ago

Have you actually tried uploading your application to Google Play?

My guess is you are actually creating an .aab instead of an .apk, since Google Play no longer accepts .apk packages. An .aab contains code and files for all architectures instead of just one. Google then creates an architecture-specific .apk for each architecture your application supports. The .apk that Google creates must be under 200 MB, but the .aab you upload should be able to be bigger.

For example, with com.vonage:webrtc, there are 4 copies of libwebrtc.a, each are about ~50 MB:

All four of them will be in the .aab, but only one will be in each architecture-specific .apk Google creates.

jonathanpeppers commented 9 months ago

Another way to estimate what the size would be on Google Play, is to build for a single architecture with dotnet build -c Release -r android-arm64 -p:AndroidPackageFormat=apk and see what the resulting .apk is.

This application uses 4 main native libraries, that I have binded successfully.

Is there also a lot of Java/Kotlin code? One difference in Android Studio is they use r8 by default, while we don't do that yet. You can opt into this by setting AndroidLinkMode=r8.

espritm commented 9 months ago

Thanks a lot for your responses, and sorry for my late answer. I have had to fix a lot of issues with my AAB to be able to submit it to PlayStore..

I've built the project with the following command line dotnet build -c ReleasePROD -r android-arm64 -p:AndroidPackageFormat=apk -f:net7.0-android

I've switched on the R8 code shrinker and the result apk is now 328MB (400MB without R8 option).

Now I've built the AAB with the following command line dotnet publish -f:net7.0-android -c:Release

The AAB is now 253MB (264MB without R8 option).

I've tryied to upload this 253MB AAB file to the PlayStore but it told me the app was containing Debugs stuff.

By setting false, the AAB was 232MB, and accepted to upload to the PlayStore.

In the PlayStore Console, in the App Bunble Explorer, I open the uploaded aab and navigate to Download tab. The size of the Signed Universal Apk is 259MB. The size of the APK per specific device is also displayed, and it varies between 169 and 172MB. So I think it is OK for now I may be able to publish. Thanks !

But still the native Java/Kotlin app is 95MB with the same libraries, and much more source code lines (90k vs 65k with MAUI). Any other options I should investigate to reduce the size please ?

jonathanpeppers commented 9 months ago

If you want us to investigate the size of your app, can you share it?

You could also list the contents of the C# vs Java/Kolin app with a tool like 7-zip (7z l) or apkdiff.

jonathanpeppers commented 9 months ago

Oh you also mentioned your app is a MAUI application. How does the size compare if it is a plain .NET 8 Android app? That is closer to a Java/Kotlin project.

MAUI is not currently trimmable and it contributes to app size quite a bit:

https://github.com/dotnet/maui/issues/18658

espritm commented 8 months ago

I created a new Android Application .Net 7 and add reference to the 4 binded libraries. The archive apk size is 96MB. I created a new MAUI Application .Net 7 and add the reference to the 4 binded libraries. The archive apk size is 106MB. The difference is not as much as I would have expected, and does not encourage me to spend time to migrate my whole project to the plain .Net Android app instead of MAUI app, and then to maintain two projects for Android and iOS.

I would be happy to share the app with you and work together to understand and find how to enhance the app size with native binded libraries. Can we use a private channel like Microsoft Support to share files ? In all cases thank you for your time !

I tried to use apkdiff between the nativ Java app and the MAUI app. Here is the summary

Summary:
  + 175 780 143 Other entries 1606,59% (of 10 941 220)
  +   1 942 016 Dalvik executables 10,59% (of 18 334 384)
  +  27 906 608 Shared libraries 15,51% (of 179 909 824)
  + 147 782 320 Package size difference 154,76% (of 95 488 821)

And here is a selection of the heaviest libraries of the two apk. I have not copied full logs. We can observe the pspdfkit libraries have the same size in both apps (native and MAUI), as well as opentok, sqlcipher, and others proprietary libraries. The classes.dex files are almost the same size. I see the skiasharp library in the MAUI app which is quite heavy, but required for our app. Nativ java app

  -   2 033 324 classes3.dex *1
  -   2 329 056 lib/armeabi-v7a/libsqlcipher.so *1
  -   2 394 580 lib/armeabi/libsqlcipher.so *1
  -   2 870 000 resources.arsc *1
  -   3 645 152 lib/arm64-v8a/libsqlcipher.so *1
  -   3 753 784 lib/x86_64/libsqlcipher.so *1
  -   3 965 220 lib/x86/libsqlcipher.so *1
  -   4 802 700 lib/armeabi/libmodpdfium.so *1
  -   4 802 700 lib/armeabi-v7a/libmodpdfium.so *1
  -   5 367 744 lib/arm64-v8a/libmodpdfium.so *1
  -   5 544 036 lib/x86/libmodpdfium.so *1
  -   5 720 000 lib/x86_64/libmodpdfium.so *1
  -   5 779 004 lib/mips/libmodpdfium.so *1
  -   7 875 780 lib/armeabi-v7a/libopentok.so *1
  -   8 101 692 classes.dex *1
  -   8 199 368 classes2.dex *1
  -  11 625 776 lib/arm64-v8a/libopentok.so *1
  -  14 351 248 lib/armeabi-v7a/libpspdfkit.so *1
  -  14 362 964 lib/x86/libopentok.so *1
  -  14 734 888 lib/x86_64/libopentok.so *1
  -  20 018 080 lib/arm64-v8a/libpspdfkit.so *1
  -  21 189 608 lib/x86_64/libpspdfkit.so *1
  -  21 323 652 lib/x86/libpspdfkit.so *1

MAUI app

  + 140 795 075 base/root/assemblies/assemblies.blob *2
  +  21 323 652 base/lib/x86/libpspdfkit.so *2
  +  21 189 608 base/lib/x86_64/libpspdfkit.so *2
  +  20 018 080 base/lib/arm64-v8a/libpspdfkit.so *2
  +  16 027 792 base/lib/x86_64/libopentok.so *2
  +  15 149 320 base/lib/x86/libopentok.so *2
  +  14 351 248 base/lib/armeabi-v7a/libpspdfkit.so *2
  +  13 597 976 BUNDLE-METADATA/com.android.tools.build.obfuscation/proguard.map *2
  +  12 619 984 base/lib/arm64-v8a/libopentok.so *2
  +  10 021 200 base/lib/x86_64/libSkiaSharp.so *2
  +   9 219 448 base/lib/x86/libSkiaSharp.so *2
  +   8 670 872 base/lib/armeabi-v7a/libopentok.so *2
  +   8 594 128 base/dex/classes.dex *2
  +   8 372 896 base/dex/classes2.dex *2
  +   7 993 472 base/lib/arm64-v8a/libSkiaSharp.so *2
  +   6 106 504 base/lib/armeabi-v7a/libSkiaSharp.so *2
  +   3 965 220 base/lib/x86/libsqlcipher.so *2
  +   3 753 784 base/lib/x86_64/libsqlcipher.so *2
  +   3 645 152 base/lib/arm64-v8a/libsqlcipher.so *2
  +   3 603 932 base/assets/Font Awesome 6 Pro-Thin-100.otf *2
  +   3 450 264 base/lib/x86_64/libmonosgen-2.0.so *2
  +   3 343 396 base/lib/x86/libmonosgen-2.0.so *2
  +   3 309 376 base/dex/classes3.dex *2
  +   3 074 432 base/lib/arm64-v8a/libmonosgen-2.0.so *2
  +   2 936 200 base/assets/Font Awesome 6 Pro-Regular-400.otf *2
  +   2 904 473 base/resources.pb *2
  +   2 455 010 base/root/assemblies/assemblies.x86_64.blob *2
  +   2 454 261 base/root/assemblies/assemblies.arm64_v8a.blob *2
  +   2 434 179 base/root/assemblies/assemblies.x86.blob *2
  +   2 433 973 base/root/assemblies/assemblies.armeabi_v7a.blob *2
  +   2 383 868 base/assets/Font Awesome 6 Pro-Solid-900.otf *2
  +   2 329 056 base/lib/armeabi-v7a/libsqlcipher.so *2
  +   2 290 184 base/lib/x86_64/libxamarin-app.so *2
  +   2 272 440 base/lib/armeabi-v7a/libmonosgen-2.0.so *2
  +   2 147 184 base/lib/arm64-v8a/libxamarin-app.so *2
  +   1 687 240 base/lib/arm64-v8a/libHarfBuzzSharp.so *2
  +   1 679 312 base/lib/x86_64/libHarfBuzzSharp.so *2
  +   1 675 060 base/lib/armeabi-v7a/libxamarin-app.so *2
  +   1 674 784 base/lib/x86/libxamarin-app.so *2
  +   1 595 964 base/lib/x86/libHarfBuzzSharp.so *2
  +   1 206 908 base/lib/armeabi-v7a/libHarfBuzzSharp.so *2
jonathanpeppers commented 8 months ago

For the second apkdiff output, it looks like you are comparing an app bundle for 4 architectures. Did you mean to compare a single-architecture .apk instead?

The number of .so files and classes*.dex files are native and Java code respectively. I don't see how MAUI or .NET Android impacts the size of these files.

Are you able to share the .apk files you are comparing?

espritm commented 8 months ago

Thank you for your answer and your analyze. I have created an appcenter repo to provide apks : https://appcenter.ms/users/maxime.esprit-gmail.com/apps/Analyze-apk-size The 5.4.3.10 is the MAUI application, whereas the 3.5.6.2 is the native Java Kotlin application.