Possible to reduce the size of iOS extensions in Xamarin? - xamarin

I would like to add several extensions into my iOS application but it seems that once I do, I quickly exceed the 100Mb limit that Apple places on Over-The-Air downloads.
com.apple.usernotifications.content-extension
com.apple.usernotifications.service
com.apple.ui-services
Document picker extensions
Each bare bones extension results in a 6Mb addition to my application.
Since the Xamarin runtime is presumably embedded into each instance, is there any way I can share this runtime among the various extensions?
Is this available as a mtouch compiler flag?
What other options do I have?
Right now I'm asked to add 11 Extensions, and I'm already at 70MB and I haven't even started coding or adding assets yet.

The most important rule about reducing app size for Xamarin.iOS is still valid:
Enable the managed linker for all assemblies (and all extensions).
Additionally Xamarin.iOS will automatically create a single embedded framework for the Mono runtime which will be used by the app and all extensions (you can check this by verifying that yourapp.app/Frameworks/Mono.framework exists).
Also make sure you don't set the deployment target to anything lower than 8.0 (for the main app) unless you really need it (because if you set the deployment target to anything below 8.0 we have to embed the Mono runtime into the main executable, because iOS 7 does not support embedded frameworks).
Unfortunately we're currently not able to share any of the AOT-compiled code from the base class libraries (nor your own code), so for instance mscorlib.dll (and all the AOT-compiled native code) is included both the app and every extension, but this will change in a future release (I'm implementing it right now).

Related

Clarifying the "Bundle assemblies into native code" option for xamarin

I'm considering the option "Bundle assemblies into native code" in the properties of my xamarin android project as below:
which has the description
bundles assemblies into a native shared library. This option protects
managed assemblies from examination or tampering by embedding them in
native binaries.
This seems like a great option to me. It makes my code harder to reverse engineer, and makes my apk file smaller as well. However, clearly there are reasons that this option isn't checked by default in Visual Studio.
The three cons I can guess at are:
compile time,
ability to run a profiler (which seems like a dead loss for xamarin
anyway)
potentially that this way of operating might affect error reporting
if you're using some kind of utility like AppCenter.
I'm curious to know what the actual cons might be, and if there is a compelling reason not to have this option as the status quo?
Perhaps as the official document says,there are two limitations.
This option requires an Enterprise license
This option is only available when Use Fast Deployment is disabled
But without Fast Deployment, Xamarin.Android has to build an APK every time there’s change in your project, regardless of size or scope. This feature allows “side-loading” of .NET assemblies to enable a much better experience.

How to exclude standard but unused libswift*.dylib's from macOS app bundle and reduce bundle size

When I build my simple menubar cocoa application written in Swift 4 with Xcode 9, a lot of libswift*.dylib libraries are linked/downloaded/embedded into .app bundle,into Frameworks folder as seen below:
I am only using import Cocoa and import Foundation in my project, and some #objc functions as selector to timer functions. I really don't think my very simple menubar app would need some 3D rendering Metal library functions or any SwiftOnoneSupport, so I would like them to be removed from the .app bundle. (Same libraries are also included in the helper app for launch at login feature, which makes even the helper app over 10 MB)
I would have thought Xcode would just copy whatever is neccessary by default actually. Some similar questions were asked here and here but I don't think there is a fulfilling and up-to-date answer to both.
What I have tried so far
I set ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES to NO in Build Settings. It doesn't seem to have any effect.
I set LINK_WITH_STANDARD_LIBRARIES to NO in Build Settings. It ruined everything and couldn't make it build even though I tried to add some frameworks(Cocoa, Foundation) on my own under Linked Frameworks and Libraries section.
Simply put, it's not possible to exclude the standard libraries that Swift automatically includes with an app and expect it to work. Currently any application created with Swift bundles its own version of the Swift Dynamic Library. Swift doesn’t live on the OS, rather it lives within each app bundle. What this means is that any app that is using Swift 4.1 for example bundles in the Swift 4.1 Dynamic Library (containing the 4.1 ABI), and so forth.
One of the things on the Swift project roadmap is to eventually have ABI Stability. If Swift becomes ABI Stable, Swift will live within the OS and it’s ABI will be compatible with every version of Swift.
From iOS v12.2 ABI[About] Stability for iOS is on. That is why your target will not include Swift standard library[About] because it is a part of OS

Reduce apk size in xamarin.forms

I am consuming Web Api services in my app. Though it is app with small functionality such as registration and login then also the size of the release was firstly 55 MB then i searched a bit then i got it down to 22 MB.
My settings are
Linking- SDk assemblies only.
i have tried every other thing such as Deselect Shared Runtime.
Select Pro guard, Generate one package, all type of linking but did not get desired result.
Am i missing something or the app size will be 22 MB.
please suggest a solution
(Copied from : https://montemagno.com/how-to-keep-your-android-app-size-down)
Linking Your Libraries
Xamarin applications use a “linker” in order to reduce your app size.
You can browse through the documentation and find out how this works,
but to simplify things, it uses static analysis to your app to remove
assemblies and types that are not used in your app to bring down your
app size. This is for any Xamarin app, so you should also try this out
in your iOS app because it can reduce your app size in a default
“Hello, World” application from 16MB down to 2.9MB! There are three
settings that you can supply from the projects settings:
Don’t Link will do just that, it won’t link anything and you will be left with All of Mono, mscorlib, Xamarin.Android, and a bunch of
other stuff:
Link SDK assemblies only is your safest bet and should be your default as it will only attempt to strip things out of Xamarin.Android
and any of your third party libraries will not be touched. However, to
really bring down your app size you should try out Link All
Assemblies, as it will investigate everything and bring down your
app size. Be sure to FULLY test your app as it is possible that the
linker may be agressive and strip out something you need, and if that
is the case you can actually use a [Android.Runtime.Preserve] flag or
set a linkskip in your MSBuild to ensure that not all of your
libraries get linked.
So employing this practice with my Bike Now app, which uses Json.NET,
Android Support v4, v7, Google Play Services, and Xamarin.Insights, we
can compare and contrast the app size when we build our app to support
all three ABIs (we will talk about this next!).
Don’t Link: 40.7MB
Link SDK Assemblies Only: 18.7MB
Link All Assemblies: 13MB
As you can see linking correctly can make a huge impact, but we can do
even better!
2. Splitting your APKs
On Android, there are ABIs (Application Binary Interfaces) that you
can support when you ship your application. The most used will be the
armeabi-v7a, however there are still tons of devices that support and
run the old armeabi ABI and even x86 devices as well. So to ensure
your app is reaching the most users you most likely have come into the
project settings and selected every single ABI (I know I do!).
However, for every ABI that you select you are actually bundling a
separate libmonodroid and sgen with your app. Don’t believe me then
rename your .apk to .zip and take a look in the lib folder:
This of course makes sense as you would need a different version of
monodroid and sgen that supports that ABI. The issue is that you now
have all of these libraries bundle into a single APK and your users
will be downloading all of them! The solution for any Android
developer (even Java devs) is to simply split up your APKs and upload
all of them to Google Play! This way you have a smaller app size
across all three APKs. You can do this now with a simple check in your
project options:
Now, instead of just a single APK to upload I have three with
different and smaller sizes (note it will take longer to create your
packages):
armeabi-v7a: 10.2MB
armeabi: 10.3MB
x86: 10.4MB
Notes:
You may need to close XS after selecting check box and ensure this
flag is set in your csproj:
true
Additionally, your new APKs will be in your /bin/Release folder and
will be marked with Signed in their file name.
Keep your users happy and keep down that app size with these quick tips.
Refer to these links:
https://learn.microsoft.com/en-us/xamarin/android/deploy-test/building-apps/build-process
https://montemagno.com/how-to-keep-your-android-app-size-down/
https://forums.xamarin.com/discussion/113229/what-is-the-ideal-apk-size-from-xamarin-forms-and-how-to-reduce-it-without-force-close
To reduce APK file size you need to use ProGuard with visual studio. It will remove all unused code, resources and shrink files, classes, variables names to very short name.
How to use ProGuard you see my another stackverflow question How to use ProgGuard with Xamarin forms.
Another option use linking Android project's properties, use Sdk and User assembly option. It some time remove code which we are actuary using so need to be careful.

How to find code targeting an SDK version of Xamarin iOS at compile time

My app is built against iOS 11 SDK but the deployment target is set to 9.3. So, the app builds but if I don't see that there's a code that use a method only available on iOS 11 (or a version above 9) and I run it on an iOS version 9 the app crashes. So, is there a way to get all the code incompatibility with a certain version of iOS?
** Edit: New answer after reading title more carefully.
Xamarin iOS does not appear to define anything automatically for the deployment target.
If you must do it at compile time, you can define your own symbols in the compiler settings. For example you can define IS_IOS_10_OR_GREATER, then just change that for different projects.
The official advice from Xamarin is to make the determination at run time since the version of iOS you're running on is what determines capabilities. You can use conditions around code using:
UIDevice.CurrentDevice.CheckSystemVersion(11, 0)
UIDevice.CurrentDevice.SystemVersion
Another option is to create an interface and have different implementations depending on the above method calls, then select which implementation accordingly. Ioc would be very useful for this.

install app on mac with shared libraries outside bundle

I am working on a Qt app with some library dependencies, for which I will have to make an installer.
From everything I read, seems like the best way is to make a bundle app with all library dependencies, and the required Qt frameworks, inside myapp.app/Contents/Frameworks
There are other applications created in parallel... that will get to be deployed on mac as well. They will have the same library dependencies and will be built using the same Qt version.
In that case it makes sense for the libraries and Qt to be installed OUTSIDE the bundle... so both (all) apps have access without having multiple copies of the same libraries.
Does that seem reasonable - and do-able with mac osx concept of bundle islands ? And how would I create such an installer that places libraries outside the app bundle ?
The simplest method of deploying Qt for OS X is to use the macdeployqt command line tool, and you have identified correctly that the normal method is to place the frameworks inside the app bundle, but multiple apps will each have copies of the frameworks.
It is reasonable to suggest moving the Qt frameworks to a separate, external location and linking to that instead. However, you will need to manage the framework carefully, especially when it comes to providing updates and be aware that if the framework is removed or altered, all your applications will fail to load. This, however is the same for any framework dependent application.
The thing to consider is where to place the framework. Normally, external frameworks reside in /Library/Frameworks, but if we all start to use that for Qt, problems may occur when your app is installed and another developer installs their app's frameworks with a different version of the libraries.
Apple defines various 'key directories' for applications and initially, the most likely location would appear to be the "Application Support Directory", but the documentation states that this is for: -
any type of file that supports the app but is not required for the app to run
This location is often used for support files, such as templates for the user to select.
If your application is to be deployed via the Apple Store, I wouldn't be surprised if it is rejected if you use this location. However, you're not using the Apple Store, then you could deploy the frameworks here.
If the Apple Store is your method of deployment, then /Library/Frameworks is probably the only place acceptable for the Qt framework to reside, with the possibility of the problems I've mentioned above.
Alternatively, consider just how many applications you're developing and is it really an issue to bundle the frameworks multiple times against the advantages that it brings, such as allowing the user to cleanly remove the application and all of its dependencies, as well as reducing problems of the framework being altered or removed accidentally?
If you choose to move them externally, you can refer to the answer to this question, which comprehensively explains how to make installer packages, after having updated your binary dependencies on the frameworks with the install_name_tool, as outlined here.

Resources