Android Asset Delivery in Dotnet Maui - android

I have a .NET MAUI Project with a lot of assets (images) in the Resources\Images directory that shall be deployed to the Google Play Store. This means that the size of the generated aab package is way beyond the Google Play Store limit of 150MB.
(Message: Your App Bundle contains the following configurations where the initial install would exceed the maximum size of 150 MB...)
My current solution resizes the images to <= 150MB. I now saw that there is the possibility to generate separate files for the assets, which is called Play Feature Delivery.
From this sample project I get the following gradle file to create an install-time-package:
apply plugin: 'com.android.asset-pack'
assetPack {
packName = "install_time_asset_pack" // Directory name for the asset pack
dynamicDelivery {
deliveryType = "install-time" // delivery mode
}
}
My question is: Can this somehow be done with .NET MAUI? Is it possible to add some elements to the csproj-file to do this, just like for example for the keystore:
<PropertyGroup Condition="$(TargetFramework.Contains('-android')) and '$(Configuration)' == 'Release'">
<AndroidKeyStore>True</AndroidKeyStore>
<AndroidSigningKeyStore>..\myapp.keystore</AndroidSigningKeyStore>
<AndroidSigningKeyAlias>key</AndroidSigningKeyAlias>
<AndroidSigningKeyPass>SuperSecretPassword!</AndroidSigningKeyPass>
<AndroidSigningStorePass></AndroidSigningStorePass>
</PropertyGroup>
The characteristic of the app and the users makes it impossible to load the images at runtime, e.g. via https.

tl;dr I did not find any Maui answer at this time.
The best starting point looks like XamarinComponent/Android/GoogleAndroidVending.
HOWEVER that wraps a java library, and appears to use gradle, so TBD what knowledge is required to be able to build this, then adapt it for Maui.
The corresponding Xamarin.Forms doc is APK Expansion Files.
The Xamarin.Forms nuget source code and doc is at github XamarinComponents/Android/GoogleAndroidVending.
There is a Nuget link there, but that won't work in .Net Maui.
Until there is a Maui Nuget, it will be necessary to download the source code, and modify it. (If anyone does this, would be good to upload back to github. TBD where.)
App Startup is a bit different in .Net Maui, I did not investigate what might need to change.
In addition, there might be references to Xamarin namespaces that should change to Maui equivalents.
IMPORTANT: This c# code is a wrapper for a java library from Google. The project includes gradle references. TBD what the requirements are to build this.

If your APK is getting over 150Mb then I suspect Google and Apple (if you're making an iOS app) will be expecting you to host the image data in the cloud and pull it to the device on an 'as needed' basis so you're not clogging your users' device storage up unnecessarily. That type of static imagery should be stored in cache and not backed up (so you'll need to check if it exists and re-download if necessary).

Related

App size doubles after using Play Asset delivery in Unity

i just exported my game to use Play Asset delivery following this guide:
https://docs.unity3d.com/2021.1/Documentation/Manual/play-asset-delivery.html
in short
build app bundle enabled
split application binary also checked.
The exported aab size is 311mb and when uploading to google play it says:
base ----install_time ---30.1mb
UnityDataAssetPack ----install time ---264mb
But then when i download the app in any device, the file size is 846mb, more than double the expected size. Also it tries to download all at once, i thought that the dataassetpack was downloaded after the base one.
i'm using Unity 2021.1.16f1
Do you know any cause for this to happen, and how to fix it?
thank you very much!
You are comparing a "download size" to a "size on disk":
The size you see in the Play Console corresponds to the download size, which is compressed.
On the device, you see the size on disk where the data is stored uncompressed so it can be directly rendered without having to keep two copies of the same data (one compressed and one uncompressed), so that explains the discrepancy.
It seems that you have configured the modules to be install-time so they will be installed as part of the initial install. If you want them to be installed while the user is starting the game, you should configure them to be fast-follow. If you want to manually download them using the Play Core API, you should configure them to be on-demand. This is all explained in the page you linked in the Managing asset packs at runtime section.
That page also links to the Google documentation on the topic, which has a dedicated section for Unity -- which would be too long to copy here, so have a read and come back if you have more specific questions.
If you're only using Unity marking the AAB output type in the build settings, and not using Google's API to do your stuff via script, then it's correct. Unity has a bug when assembling bundles and will simply (at least) double the size of your app. Things will be doubled in your AAB, you'll see the stuff you had in streaming assets in split apks and also inside the base.apk. Unity's way is not reliable, it's quite wrong and Google's plain way for Unity also is not perfect, it will not work for every single project. I was able to get the hang of it, but in the end I wrote our own tool to create the asset packs, created our runtime implementation to use the API and also our build procedures to be called by our custom build class.
My suggestion is, squeeze the docs here https://developer.android.com/guide/playcore/asset-delivery/integrate-unity?language=api and build your custom solution.

how to build an APK and separate libraries that the app loads dynamically

The short summary is: How do I build an APK and separate libraries (by which I mean sets of classes (and ideally, resources too) in some form, such as JAR, AAR or DEX files), but not include those libraries in the APK; instead, the app loads them at run time?
Detail
So my main question is how to build such an app (e.g. Gradle configuration). How do I specify which classes go into which JAR or DEX files? Do I create an Android Studio module for each DEX file I want to end up with?
A closely related question is how the Java code should then load the external libraries and access their classes at run time. For the latter, I'm hopeful that the approach shown at accessing to classes of app from dex file by classloader would work.
I've tried the instructions at https://developer.android.com/studio/projects/android-library.html, but that builds an APK that does include the dependency library.
I've also tried Multidex (https://developer.android.com/studio/build/multidex.html), but that doesn't seem to leave the developer any control over which classes go in which DEX file, and furthermore, packages them all into a single APK. AFAICT there is no way to control the loading of these DEX files at run time.
Background
There's a possibility of the "X-Y problem" here, so I'd better explain the background.
I'm building an app for a client. It's not going to be distributed through an app store, so it won't have access to the normal mechanism for updates. Instead, the client wants the app to be able to update itself by downloading new components of itself to replace the old components, without a need to manually sideload a new APK. The primary motive here is that the updates have to be easy for non-technical users. If the app can control the update process, it can make it smooth and guide the user.
Moreover, the app will be used in areas where internet access is scarce and expensive, so the client wants to be able to issue app updates in smaller chunks (e.g. 2MB) rather than forcing the user to re-download the whole app to receive a small update.
One aspect of the requirements I should mention, in case it matters, is that the libraries to be loaded at run time are supposed to live on a microSD card. This can also help with distribution of updates without internet access.
The current status of the app is that it's about 50% written: That is, a couple of earlier versions have been released, but the app now needs to be modified (restructured) to meet the above requirements, as well as others.
This tutorial is a good start for external loading of DEX files.
Only three small files of source (MainActivity.java, LibraryInterface.java, LibraryProvider.java) and it copies secondary_dex.jar from the assets folder, into internal application storage [outdex/dex] (the internet is also stated as possible in the tutorial).
You have to build it with ant, because it uses custom build steps.
I tried it, it works fine. Worth a look.
custom class loading in Dalvik and ART
UPDATE
this code has been ported to Android Studio gradle (no need for ant).
https://github.com/timrae/custom-class-loader
Tested ok. Copies com.example.toastlib.jar from the SDcard into internal application storage [outdex/dex],(not assets folder).
( you must read the README.md file in the project to build it).
Q: How do I add an Activity, I cannot add it to the manifest ? A: Use
Fragments, they don't need entries in the manifest.
Q: A Jar with resources that is meant to be added to an existing
project needs to be able to merge its resources with the project's
own resources (R.). A: Hacks are available, Data file...Packaging Android resource files within a distributable Jar file
Q: The external file has wrong permissions. A: Import it.
Q: I need to add uses-permission. A: Use API23 you can programmatically add uses-permissions (but they still need to be declared in the Manifest, so the new permissions model is probably not much use to us).
This section is for more general users (#LarsH has more specific requirements about updates), The example above is 17kb apk and 1 kb jar. You could put the bulk of you code in the one-off jar, and updates would involve just loading an new Apk (and then importing the bulk code jar, to minimise the data transfer).
When the Apk gets too big, start again with a small Apk and everything migrated to another jar (import 2 jar's). You need to balance coding effort, user experience, maintainability, supportability, bandwidth, android rules, play store rules (if these words even exist ;O)).
NOTE Dalvik is discontinued
The successor of Dalvik is Android Runtime (ART), which uses the same bytecode and .dex files (but not .odex files), with the succession aiming at performance improvements transparent to the end users. The new runtime environment was included for the first time in Android 4.4 "KitKat" as a technology preview, and replaced Dalvik entirely in later versions; Android 5.0 "Lollipop" is the first version in which ART is the only included runtime.
You could try to build multiple apk's with the same sharedUserId and the same process.
This is the plugin mechanism used by Threema
Edit: More about Theema
Threema has one main app and two plugins:
main app: https://play.google.com/store/apps/details?id=ch.threema.app
QR-Code Plugin: https://play.google.com/store/apps/details?id=ch.threema.qrscannerplugin
Voicemessage Plugin: https://play.google.com/store/apps/details?id=ch.threema.voicemessageplugin
Doing so the main app does not need the permissions for accessing the camera or microphone

Unity games: Best practices for setting up a config file

I am working on a Unity game that uses AssetBundles and can be published to both iOS and Android devices. I also have three dev environments where I publish the builds for internal testing. To grab the files from the assetbundle server, I have five different base URLs to pull from, depending on the environment.
I want to externalize the base URL so that I don't have to keep making a new build for each environment. What would be the best practice to externalize config settings? Is there one?
If you want to be able to change the base URL without redeploying the project, I think your best shot is to use some intermediate URL.
You may require the bundle from some www.mygame.com/bundle/platform who will download the right file whenever needed.
You can also read the base URL from a classic file using Stream. You can then edit the file to change the URL without rebuilding the whole project.

How to distribute file collections as separated apk packages in android?

I have a small Android application that uses different sets of files (a couple of images, a small SQLite DB and a couple of XML files) depending on the specific task at hand.
I know I can include my files into the main application APK using resources or assets but I would be happy to distribute them in a separated APK.
How can I create a data-only APK file?
How can I distribute it? In particular, do I have to do anything special for a data-only package (for example for associating it to the main application package in some way)?
(I'm intentioned to give the user a link to the data package and ask him to install it. No automatic installation required.)
How can I install my files into the internal or into the external storage area of my application? Is it possible at all to install files into the internal storage area created by the main application installer? Do I have to set any particular permission for this?
My approach to this would be to create a wrapper app that's nothing but a content-provider and serves up the files per request by your main app. This would allow you to supply different data packages for the user -- you could even have your main app select between those relatively easily.
It looks like that the commonly accepted way to have the same application with different contents (or styles, or configurations) is to use an Android Library Project for the common code (that is: the whole application, the "engine", the "app framework") and a standard Android Application Project for the contents (that is: an application that actually contains just data). A little bit confusing, just because the "library" here is actually the whole "app", but this seems to be the way to go.
More in detail:
Create an Android Library Application and put into it as much code as you can (all of the non-changing stuff). Please note that this library cannot be launched and cannot be distributed alone. It must be included in a hosting application.
Create a standard Android Application. Include your library into this project. Put in /res and in /asset all of your data (files, XML, etc.).
Compile everything and distribute.
Repeat this cycle every time you need a different version. Different because of data, style, configuration or anything else. Publish the resulting app with a new name.
For what regards me, I'm not completely satisfied by this approach.
A possible alternative is preprocessing the source code with Ruby, Python, Perl, GIT, bash, Ant, Maven, Rake or any other tool that is able to read a file from here, make some change here and there, and write the file there.
The general outline is something like this:
Make a "template" application. Leave your /res and /assset empty.
Run a custom-made script. The script reads a configuration file, copy the /res and /asset files from your repository into the project /res and /asset directories, changes some Java source file and creates/changes some XML file.
Compile and distribute (with a new name, of course).
Using GIT or other SCMs, you just make a new branch for every new version and compile it. Not very elegant (because it can strongly interfere with the normal use of the SCM) but...
There are a few example of these approaches on the web. I'm not completely satisfied by them, either.
Frankly, what the Android ecosystem should offer to solve this problem is some kind of "in-app package manager". Something like the Eclipse Update Manager. This would allow us to use the same application framework to handle different scenarios.
As an alternative, a solid, officially-supported, template-based code-generation mechanism would be nice. Something in the spirit of "Software Production Line": https://en.wikipedia.org/wiki/Software_production_line . Have a look at fw4spl, for example: http://code.google.com/p/fw4spl/ .

how can I access SVN from an Android device

I've been trying to use SVN Kit to gain access to an SVN repository from an Android app.
Our project is supposed to check for changes to files and download them if they have changed, but still with the ability to rollback to previous versions if nessecary.
I set up a regular Java project, and had no problem using SVN Kit, I logged into the SVN server and retrived a list of the files stored there.
But when I tryed to do this from an Android project all hell broke loose. The VM run out of heap space, just trying to build it and Eclipse went down in sreaming flames mith comments like 'GC overhead limit exceeded'.
I get the impression that this is due to the diffrent type of virtural machine that Android uses, and the SVNKit jars are compiled for a diffrent type of VM.
This Guy claims to have got it working, with what looks like an older version of Android.
Now I have suggested that we use some kind of ftp server approach, uploading new versions of the files, perhaps with seperate files containing versioning information, but I have to explore this path before I write it off as a dead end, or at least suggest that to my boss!
anyu help or suggestions would be greatly appricated.
My answer may not be directly related to SVNKit but would actually try to address the original problem.
As I understand your use-case, you want to download files if they have changed and are trying to use SVN to do this with its update command. I would rather create a simple web-service which should return me the list of files with their checksums or md5Hash. Now I am assuming that only the relevant files are present on the server. Upon receiving the hashes, you can compare them with the hashes on the device and decide to update based on any difference. This approach will work for rollback too as you need to just replace the file on the server with old file and this would be treated as a new one.
As far as heap overflow and out of memory is concerned, they are mostly because of the limited heap space around 10MB.
I created a SVN client based on SVNKit it is available for free here : https://play.google.com/store/apps/details?id=com.valleytg.oasvnlite.android
I am not sure if that will work for your purpose or you have to build your own. If you are looking to build your own, svnkit will not work directly on the android platform. Some of the libraries used by SVNkit are not available on the Android platform.

Categories

Resources