xamarin / xamarin-macios

.NET for iOS, Mac Catalyst, macOS, and tvOS provide open-source bindings of the Apple SDKs for use with .NET managed languages such as C#
Other
2.48k stars 514 forks source link

Big size of final app/extension using Newtonsoft.Json in Xamarin.iOS #7250

Open artur-malendowicz-gain opened 5 years ago

artur-malendowicz-gain commented 5 years ago

Steps to Reproduce

  1. Create test iOS + watchOS project
  2. Build in release mode - .appex size around 45mb
  3. Add Newtonsoft.Json
  4. Build in release mode - .appex size around 115mb

Expected Behavior

App's/AppExtension's size should increase by not that much

Actual Behavior

Newtonsoft.Json weights around 600kb in .dll. After compiling in release mode (so probably AOT has something to do) app's/appextension's size increases by around 65mb.

Environment

Visual Studio Community 2019 for Mac
Version 8.3.4 (build 8)
Installation UUID: 556929dc-ef0e-4bec-9c85-fb17f1142b3b
    GTK+ 2.24.23 (Raleigh theme)
    Xamarin.Mac 5.16.1.24 (d16-3 / 08809f5b)

    Package version: 604000208

Mono Framework MDK
Runtime:
    Mono 6.4.0.208 (2019-06/07c23f2ca43) (64-bit)
    Package version: 604000208

Xamarin Designer
Version: 16.3.0.247
Hash: 52eac1a9e
Branch: remotes/origin/d16-3
Build date: 2019-10-03 23:04:28 UTC

NuGet
Version: 5.3.0.6192

.NET Core SDK
SDK: /usr/local/share/dotnet/sdk/3.0.100/Sdks
SDK Versions:
    3.0.100
    3.0.100-rc1-014190
    2.2.300
    2.2.204
    2.2.203
    2.2.106
    2.2.106-old copy
    2.1.701
    2.1.505
MSBuild SDKs: /Library/Frameworks/Mono.framework/Versions/6.4.0/lib/mono/msbuild/Current/bin/Sdks

.NET Core Runtime
Runtime: /usr/local/share/dotnet/dotnet
Runtime Versions:
    3.0.0
    3.0.0-rc1-19456-20
    2.2.5
    2.2.4
    2.1.13
    2.1.12
    2.1.9

Xamarin.Profiler
Version: 1.6.12.29
Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

Updater
Version: 11

Xamarin.Android
Version: 10.0.3.0 (Visual Studio Community)
Commit: xamarin-android/d16-3/4d45b41
Android SDK: /Users/artur.malendowicz/Library/Developer/Xamarin/android-sdk-macosx
    Supported Android versions:
        8.1 (API level 27)

SDK Tools Version: 26.1.1
SDK Platform Tools Version: 29.0.4
SDK Build Tools Version: 29.0.2

Build Information: 
Mono: mono/mono/2019-06@5608fe0abb3
Java.Interop: xamarin/java.interop/d16-3@5836f58
LibZipSharp: grendello/LibZipSharp/d16-3@71f4a94
LibZip: nih-at/libzip/rel-1-5-1@b95cf3fd
ProGuard: xamarin/proguard/master@905836d
SQLite: xamarin/sqlite/3.27.1@8212a2d
Xamarin.Android Tools: xamarin/xamarin-android-tools/d16-3@cb41333

Microsoft Mobile OpenJDK
Java SDK: /Users/artur.malendowicz/Library/Developer/Xamarin/jdk/microsoft_dist_openjdk_1.8.0.25
1.8.0-25
Android Designer EPL code available here:
https://github.com/xamarin/AndroidDesigner.EPL

Android SDK Manager
Version: 1.4.0.65
Hash: c33b107
Branch: remotes/origin/d16-3
Build date: 2019-10-08 23:36:20 UTC

Android Device Manager
Version: 1.2.0.116
Hash: d2b2af0
Branch: remotes/origin/d16-3
Build date: 2019-10-08 23:36:44 UTC

Apple Developer Tools
Xcode 11.1 (15405)
Build 11A1027

Xamarin.Mac
Xamarin.Mac not installed. Can't find /Library/Frameworks/Xamarin.Mac.framework/Versions/Current/Version.

Xamarin.iOS
Version: 13.4.0.2 (Visual Studio Community)
Hash: e37549bc
Branch: xcode11.1
Build date: 2019-10-07 22:43:23-0400

Xamarin Inspector
Version: 1.4.3
Hash: db27525
Branch: 1.4-release
Build date: Mon, 09 Jul 2018 21:20:18 GMT
Client compatibility: 1

Build Information
Release ID: 803040008
Git revision: 8da5857bc3d33e5667cacaab3bd1ab55375ed3e3
Build date: 2019-10-14 18:26:13+00
Build branch: release-8.3
Xamarin extensions: 61c91e660a01512a3b8187c749fd3bccc75a2bf4

Operating System
Mac OS X 10.15.0
Darwin 19.0.0 Darwin Kernel Version 19.0.0
    Wed Sep 25 20:18:50 PDT 2019
    root:xnu-6153.11.26~2/RELEASE_X86_64 x86_64

Enabled user installed extensions
Straight8's SpecFlow Integration 1.11.3.0

Build Logs

Example Project (If Possible)

Also reported in: https://github.com/JamesNK/Newtonsoft.Json/issues/2197

mandel-macaque commented 5 years ago

I can confirm the issue. @rolfbjarne any culprit that we know off? @lewurm maybe you might know more info.

mandel-macaque commented 5 years ago

No adding as a bug but more of a nice too have/enhancement.

artur-malendowicz-gain commented 5 years ago

Well, It’s a bit of blocker, as it's easy to exceed max app size limit. I had to switch to some small one file solution and I am not able to use core from my mobile app.

rolfbjarne commented 5 years ago

This is a well-known problem with Newtonsoft.Json, how it uses generics does not work well with AOT-compilation and the native code size ends up quite big.

The alternative is to use other Json libraries (I know some people have had success with https://github.com/facebook-csharp-sdk/simple-json for instance, but each use case is different).

artur-malendowicz-gain commented 5 years ago

@rolfbjarne

Well, it's bad, as even you as Microsoft suggests to use Json.NET pre core 3.0...

spouliot commented 5 years ago

Note that release builds of watchOS applications includes bitcode (large payload) which is submitted to Apple but is not part of the final application (as installed by users on devices)

artur-malendowicz-gain commented 5 years ago

@spouliot

But it's impossible to load it onto device if app weights 450mb...

spouliot commented 5 years ago

@artur-malendowicz-gain for end-users, Apple use bitcode to rewrite the application that is sent to the watch devices.

Locally you can use Debug (instead of Release). It makes things much faster when developing (building and deployment).

If you really want to use Release try adding --bitcode=marker to the Additional touch argument of the watch app project (been a while @rolfbjarne can likely confirm). That build should be smaller (closer to the Debug size) but can't be submitted to Apple.

artur-malendowicz-gain commented 5 years ago

@spouliot Ok, will try that.

DamianMehers commented 5 years ago

@artur-malendowicz-gain @spouliot Just as a small data point: a small new WatchOS app that I just submitted to Apple failed their checks "The size of watch application '/Payload/your.iOS.app/Watch/your.app' (82MB) has exceeded the 75MB size limit." ... I had to enable linking of everything to bring the size down, with the fun that entails in working out what breaks as a result. My only Watch app extension dependencies are Newtonsoft.Json and Xamarin.Essentials

DamianMehers commented 4 years ago

This is a well-known problem with Newtonsoft.Json, how it uses generics does not work well with AOT-compilation and the native code size ends up quite big.

The alternative is to use other Json libraries (I know some people have had success with https://github.com/facebook-csharp-sdk/simple-json for instance, but each use case is different).

@spouliot I just moved to SimpleJson from Newtonsoft.Json for a watch app and it made a massive difference: I no longer need to Link All, and it was very easy to move. Thanks for this pointer Sebastien.

It also makes a big difference to the develop/deploy/debug cycle and for real users when installing from the store.

ivanlabsii commented 4 years ago

The alternative is to use other Json libraries (I know some people have had success with https://github.com/facebook-csharp-sdk/simple-json for instance, but each use case is different).

In most cases this won't help. There are too many packages that depend on Newtonsoft Json. In the best case you would have to download their code swap out Json packages, cross fingers that you won't have the update package ever again and that it has full code on the github and license that allows this. So while this may help to someone it isn't acceptable in many if not in most of the cases.

ivanlabsii commented 4 years ago

A bit of ping-pong from the same bug on Newtonsoft's github:

 JamesNK commented 37 minutes ago
I don't know how Newtonsoft.Json uses generics that makes  the AOT size large. Someone who knows more about Xamarin would need to  investigate.

So if this is to be fixed in Newtonsoft (and that is the only solution that makes Xamarin for Apple Watch remotely usable as so many packages depend on Newtonsoft) the first step would be that @rolfbjarne explains on their github on the above issue what

how it uses generics does not work well with AOT-compilation and the native code size ends up quite big.

exactly means so that it may eventually be fixed.

mphill commented 4 years ago

@DamianMehers @ivanicin

Adding --interpretto the mtouch arguments on the extension seems to cut the app size down by about 20%. Curious if you would be willing to test this on an older branch of your code that used Newtonsoft.Json

DamianMehers commented 4 years ago

Is the interpret flag allowed released App Store apps? I’d assumed it was just for development. I’m afraid I’ve moved all my apps to SimpleJson

Edit: I saw @chamons note here and it looks like I may be wrong ... it seems like --interpret is for released apps. Good stuff! Although there is a note that it can make your apps larger, so there will be a tradeoff there.

chamons commented 4 years ago

Correct, the interpreter is allowed under the App Store rules, and multiple shipping apps have submitted it successfully.

It can make your app larger, but also smaller or the same size ironically enough. IL code is smaller than assembly on average, but we have to bundle in the interpreter when you enable it. It will obviously be significantly slower at runtime, but depending on your use case it can be minor or huge.

nickplee commented 4 years ago

Adding the --interpreter flag made a pretty drastic difference for a watch app I am working on, with Json.NET as a dependency.