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.94k stars 533 forks source link

The APK with .NET 7 Android is twice the size compared to compiling with Xamarin.Android. #8212

Closed fsaffioti closed 5 months ago

fsaffioti commented 1 year ago

Android application type

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

Affected platform version

.net 7 android

Description

I am upgrading my app from Xamarin.Android to .NET 7, but the APK/AAB size is twice as large as the one built with Xamarin.Android.

Building and archiving the APK with .NET 7 (dotnet publish myapp.csproj -f net7.0-android -c Release) or from VSMac 17 results in a size that is twice as large as the APK/AAB built and archived with Xamarin.Android 13.

how can i reduce apk/aab, in xamarin.android is 30mb in .net7 android is 65mb ?

Xamarin Android project configuration

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>8.0.30703</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{782BE5B1-8B1B-4D8F-B154-2C003ABA8504}</ProjectGuid>
    <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <TemplateGuid>{84dd83c5-0fe3-4294-9419-09e7c8ba324f}</TemplateGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>Myapp.Droid</RootNamespace>
    <AssemblyName>Myapp.Droid</AssemblyName>
    <FileAlignment>512</FileAlignment>
    <Deterministic>True</Deterministic>
    <AndroidApplication>True</AndroidApplication>
    <AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
    <AndroidResgenClass>Resource</AndroidResgenClass>
    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
    <TargetFrameworkVersion>v13.0</TargetFrameworkVersion>
    <AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
    <MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
    <MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
    <AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
    <AndroidUseAapt2>true</AndroidUseAapt2>
    <AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugSymbols>True</DebugSymbols>
    <DebugType>portable</DebugType>
    <Optimize>True</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <AndroidManagedSymbols>true</AndroidManagedSymbols>
    <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
    <AndroidLinkMode>SdkOnly</AndroidLinkMode>
    <EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
  </PropertyGroup>

vs .net7-android configuration

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net7.0-android</TargetFramework>
        <SupportedOSPlatformVersion>27</SupportedOSPlatformVersion>
        <OutputType>Exe</OutputType>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
        <ApplicationId>myapp.Android</ApplicationId>
        <ApplicationVersion>1</ApplicationVersion>
        <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
    </PropertyGroup>

    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
        <AndroidManagedSymbols>true</AndroidManagedSymbols>
        <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
        <AndroidLinkMode>SdkOnly</AndroidLinkMode>
        <EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
        <Optimize>True</Optimize>
    </PropertyGroup>

nuget packages used in main project

    <ItemGroup>
        <PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.6.1.3" />
        <PackageReference Include="Xamarin.AndroidX.Lifecycle.Common" Version="2.6.1.3" />
        <PackageReference Include="Xamarin.Firebase.Messaging" Version="123.1.2.2" />
        <PackageReference Include="Xamarin.AndroidX.Work.Runtime" Version="2.8.1.3" />
        <PackageReference Include="Xamarin.AndroidX.ConstraintLayout" Version="2.1.4.6" />
        <PackageReference Include="Xamarin.AndroidX.Lifecycle.Process" Version="2.6.1.3" />
        <PackageReference Include="Xamarin.Google.Android.Material" Version="1.9.0.2" />
        <PackageReference Include="Xamarin.AndroidX.Fragment" Version="1.6.0.1" />
        <PackageReference Include="Xamarin.Controls.SignaturePad" Version="3.0.0" />
        <PackageReference Include="Xamarin.AndroidX.Navigation.Fragment" Version="2.6.0.1" />
    </ItemGroup>

nuget packages used in submodules projects

    <ItemGroup>
        <PackageReference Include="Microsoft.Toolkit.Mvvm" Version="7.1.2" />
        <PackageReference Include="Xamarin.Essentials" Version="1.7.7" />
    </ItemGroup>
    <ItemGroup>
        <PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.6.1.3" />
        <PackageReference Include="Xamarin.AndroidX.RecyclerView" Version="1.3.0.3" />
        <PackageReference Include="Xamarin.Google.Android.Material" Version="1.9.0.2" />
        <PackageReference Include="Com.Airbnb.Android.Lottie" Version="4.2.2" />
        <PackageReference Include="System.Reactive" Version="6.0.0" />
        <PackageReference Include="Refractored.GifImageView" Version="2.0.0" />
        <PackageReference Include="Mindscape.Raygun4Net" Version="5.6.0" />
    </ItemGroup>
    <ItemGroup>
        <PackageReference Include="Xamarin.AndroidX.Camera.Camera2" Version="1.2.3.1" />
        <PackageReference Include="Xamarin.AndroidX.ConstraintLayout" Version="2.1.4.6" />
        <PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.6.1.3" />
        <PackageReference Include="Xamarin.Google.Android.Material" Version="1.9.0.2" />
        <PackageReference Include="Xamarin.AndroidX.Camera.View" Version="1.2.3.1" />
        <PackageReference Include="Xamarin.AndroidX.Camera.Lifecycle" Version="1.2.3.1" />
    </ItemGroup>

    <ItemGroup>
        <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
    </ItemGroup>
    <ItemGroup>
        <PackageReference Include="SQLiteNetExtensions" Version="2.1.0" />
        <PackageReference Include="NLog" Version="5.2.2" />
        <PackageReference Include="libphonenumber-csharp" Version="8.13.16" />
        <PackageReference Include="Microsoft.AppCenter.Crashes" Version="5.0.2" />
        <PackageReference Include="Microsoft.AppCenter.Analytics" Version="5.0.2" />
        <PackageReference Include="Xamarin.Essentials" Version="1.7.7" />
        <PackageReference Include="SkiaSharp" Version="2.88.3" />
        <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
    </ItemGroup>

runtimeconfiguration.json

{
  "runtimeOptions": {
    "tfm": "net7.0",
    "frameworks": [
      {
        "name": "Microsoft.NETCore.App",
        "version": "7.0.0"
      },
      {
        "name": "Microsoft.Android",
        "version": ""
      }
    ],
    "configProperties": {
      "Microsoft.Extensions.DependencyInjection.VerifyOpenGenericServiceTrimmability": false,
      "System.AggressiveAttributeTrimming": true,
      "System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization": false,
      "System.Diagnostics.Debugger.IsSupported": false,
      "System.Diagnostics.Tracing.EventSource.IsSupported": false,
      "System.Globalization.Invariant": false,
      "System.Net.Http.EnableActivityPropagation": false,
      "System.Net.Http.UseNativeHttpHandler": true,
      "System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
      "System.Reflection.NullabilityInfoContext.IsSupported": false,
      "System.Resources.ResourceManager.AllowCustomResourceTypes": false,
      "System.Resources.UseSystemResourceKeys": true,
      "System.Runtime.InteropServices.BuiltInComInterop.IsSupported": false,
      "System.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHosting": false,
      "System.Runtime.InteropServices.EnableCppCLIHostActivation": false,
      "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false,
      "System.StartupHookProvider.IsSupported": false,
      "System.Threading.Thread.EnableAutoreleasePool": false,
      "System.Text.Encoding.EnableUnsafeUTF7Encoding": false,
      "Xamarin.Android.Net.UseNegotiateAuthentication": false
    }
  }
}

Steps to Reproduce

dotnet publish myapp.csproj -f net7.0-android -c Release

Did you find any workaround?

no

Relevant log output

No response

jonathanpeppers commented 1 year ago

This is very similar to: https://github.com/dotnet/maui/issues/9453#issuecomment-1217003859

Google Play splits up app bundles per architecture. Are you comparing the numbers Google Play shows for your app?

Alternatively, you can build for one architecture as mentioned at the link above. It will give you a rough idea of what will happen on Google Play. Let us know your results from doing this, thanks!

ghost commented 1 year ago

Hi @fsaffioti. We have added the "need-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

fsaffioti commented 1 year ago

@jonathanpeppers thanks for quick response and your help is really appreciated

Actually, I was mostly comparing the APK (the AAB is slightly smaller than the APK) and I wasn't looking at the APK size on Google Play. Instead, I was considering the APK size on Appcenter with our current settings, as we distribute the app through Appcenter to QA.

for the app in Xamarin.Android on Google play and Appcenter <AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
apk is 34 MB aab is 30 MB

for the app in .net7 Android with dotnet publish myapp.csproj -f net7.0-android -c Release -r android-arm64 AotAssemblies && AndroidEnableProfiledAot blank apk 33.8 MB aab 30 MB

for the app in .net7 Android with dotnet publish myapp.csproj -f net7.0-android -c Release -r android-arm64 and AndroidEnableProfiledAot =false && AotAssemblies blank apk 53.8 MB aab 50 MB

for the app in .net7 Android with with dotnet publish myapp.csproj -f net7.0-android -c Release and AndroidEnableProfiledAot =true && AotAssemblies blank apk 68.7 aab 64.4

for the app in .net7 Android with with dotnet publish myapp.csproj -f net7.0-android -c Release and AndroidEnableProfiledAot =false && AotAssemblies blank apk 140.4 aab 136.1

for the app in .net7 Android with dotnet publish myapp.csproj -f net7.0-android -c Release -r android-arm64 AotAssemblies=false && AndroidEnableProfiledAot blank apk 30.2 MB aab 26.8 MB

Summarize with android-arm64 yes i have the same size probably the default in xamarin.android is just one ABI

then i have noticed with AndroidEnableProfiledAot =true the APK/AAB is very large but documentation says exactly the contrary . image

what's the different between AotAssemblies && AndroidEnableProfiledAot ? Should both be true for production? should both be blank?

jonathanpeppers commented 1 year ago

We try to set the best defaults for you, where you can just leave the settings blank. Release builds by default will be:

For your numbers above, make sure you compare a Xamarin.Android & .NET 7 app with the same values for AotAssemblies and AndroidEnableProfiledAot. Then AndroidSupportedAbis=arm64-v8a is the equivalent of -r android-arm64.

gabsamples6 commented 1 year ago

@jonathanpeppers just want to say that same app - the Maui version has less code

I have looked at all the properties that are set and I cannot spot a difference. There is definetely an issue there...

Any suggestions on what properties I should set to minimize size of the app apart from AOT?

jonathanpeppers commented 1 year ago

@gabsamples6 are these numbers from Google Play? Or are you compiling a single architecture to estimate?

The comment above explains further: https://github.com/xamarin/xamarin-android/issues/8212#issuecomment-1647889490

microsoft-github-policy-service[bot] commented 1 year ago

Hi @fsaffioti. We have added the "need-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

gabsamples6 commented 1 year ago

@jonathanpeppers these are not google play because we cannot ship the maui app till critical bugs are fixed :)..

We use Azure Pipeline to deploy to appcenter (for dev -uat etc) and those are taken from appcenter...

Interestingly - this is something I wanted to ask and I googled but could not find the answer and would be grateful.

in Xamarin forms we could set <AndroidSupportedAbis>armeabi-v7a;arm64-v8a</AndroidSupportedAbis> in maui there is no UI that I can see to set the architectures

So now I am not sure what architecture I am building... is it something that I have to define in the pipeline and how - since there is no UI or do I just amend the csproj file manually?

We want to get to the bottom of this on why the Maui app size is nearly double.. and fix whatever we are doing wrong..

Appreciate your input

jonathanpeppers commented 1 year ago

Yes, as mentioned here:

It is the RuntimeIdentifier(s) property. By default it is RuntimeIdentifiers=android-arm;android-arm64;android-x86;android-x64.

If you want to compare sizes Xamarin vs .NET 7, build each one for a single architecture like ARM64. This gives you an idea before submission to Google Play (final source of truth).

gabsamples6 commented 5 months ago

There is no doubt at all that a Maui app is way bigger than a xamarin one