I have a android application hosted separately(not on Play Store), for updating app i have to download complete apk and then install even for small changes and bug fixes.
Is there any way to implement differential update mechanism in my app similar to Google play Store(Smart Update Mechanism)
If your questions is "is there an API that does this all for me?", then the answer is no.
If however you are asking, "What design do I need to implement to do this?", then in outline you need to:
send info from the client, so that it identifies which version is currently installed
send the delta between the currently installed version and the new down to the client (in whatever format you deem appropriate - you could just use the output of bsdiff for example which is a version of diff that handles binary files)
read the currently installed apk as a simple binary file, and apply the delta to produce a new binary apk file in a temporary location
install the new apk from the temporary location
clean up the temporary location
It's easy to see how this all works smoothly for the Google Play app's case, where the app executing this code is not the app that is being updated. However it can be got to work for updating yourself - after all Google Play also has the need to update itself!
The concept that you need to know is "Delta Update":
https://en.wikipedia.org/wiki/Delta_update
You must calculate the differences between new and old APK files and generate a Patch file in server-side:
https://en.wikipedia.org/wiki/Diff_utility
https://www.w3.org/TR/NOTE-gdiff-19970901
https://www.chromium.org/developers/design-documents/software-updates-courgette
Then download the patch file in Android client and merge it with the old APK to generate the new one.
Install the new APK...
As far as I know, even when you update an app from the Google Play Store, you are downloading a complete APK, even if the update is just to change a single string in your app.
However, I can think of a way (that I have not tried) to update an app differentially. It will be require a server (from which your app will download the new data/update). You will have to write a code in your app that processes the update from the server and replaces the specified resources (values, strings, links, etc) in your app. You won't be able to change the app logic or semantics, but at least the data can be changed.
In conclusion, I think Angry Birds Transformers does something like this (as it keeps telling me it is downloading new data from the servers). But Subway Surfers require you to download a new APK from Play Store in order to get the new resources for every city their tour visits.
Related
I need to use old version of apk and i wonder if there is a way to change respond from website that is hardcoded into app. App connect with some website and there is path with websiteurl/update/project.manifest/ It is simple plain text which contains some strings and app compare response with installed files.
JSON file contain string "Version_id: 12.5.3" which is newest app version. I need to spoof version to match old apk before update as app lost important function and devs removed functions for export data. I tried to manual edit response with http toolkit but it doesnt come as response it is downloaded right from url and compared with installed version. Hope somone have some idea, I tried editing apk so it shows as newer version but app check hash and closes with error.
Try edit external website plaintext, any MITM way. Modified response json match old apk version and allow to use without update.
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).
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.
I want to migrate my android app (~40 MB of the base apk) that uses an .obb file (~70 MB) to the Android App Bundle format. I know for sure that the resources inside the .obb file will be updated less frequently than the base part. Therefore, there is no need for the users to download a full app (40 + 70 = 110 MB) on each app update but only the changed part (~40 MB).
What can I use after the migration to provide the same experience (update only changed part) to the end users?
Ideally, these unchanged resources should be accessible through the AssetManager like they are located within the assets directory.
For now, I found the Play Asset Delivery feature that allows moving some resources to a separate module to deliver it to devices at different times (install time / right after the download / when needed).
I've implemented an install time module logic and tested it via the internal + alpha tests. Throughout the testing, I found out each app update forces Google Play to download the full app (~110 MB) instead of the changed part (~40 MB). I do not know whether this situation will change when I release an app to the "available for everyone" track and I could not find the information about it either. Therefore, the answer "an install time module will not be redownloaded if unchanged; here is the documentation describing this: <link>" is fully acceptable and is one of the most welcoming ones.
tldr; Yes, in production, the download size will be smaller.
When you publish an app to production (whether APK or App Bundle), Play will generate patches of your app between this version and the previous versions of your app, so that your users only download the difference between the two versions. The consequence is that if you don't modify the content of a dynamic module, users will still receive updates for the unchanged modules but the download size will be very small.
Note that in practice, it is possible that the first couple of users downloading the update may still get the full size.
Has anyone tried using market apk expansion downloader library (available as an add-on) for downloading large files on android <= 2.2? The source code is a bit difficult to understand and I was not able to figure out how it can be used for downloading any large files in general. Are there any alternatives for downloading large files on lower android devices(apart from writing my own DownloadService which I wouldn't prefer doing if there is something already available).
I have not tried to use it but the docs do state the the expansion downloader library is compatibile with API Level 4, taken from the docs:
Note: By default, the Downloader Library requires API level 4, but the
APK Expansion Zip Library requires API level 5.
I completely agree that the source code is difficult to follow, however it was designed in such a way to be fault tolerant to network issues.
I think you can take the sample and roll with that, however I found it was very difficult to test.
We ended up going with our own in the end (using an Arbitrary server) to host the downloads.
I do not believe there are any alternatives, however the downloader library does have a few gems. For instance the Expansion Zip Library can be used independently of the Downloader Library and is a great way to read content directly from the zip.
The only challenge would be writing your own downloader service and performing a CRC check.
Seems like API 4 or >
The expansion API is used for "permanent" file extensions to your application, they don't want you to move them or delete them or even unpack them etc. but use them in place, it's unclear what would happen if you did but I suspect a lot of odd side effects.
You also don't have direct control of when this file is downloaded, it has to be associated in the market and then it happens automatically unless for some reason it "fails" in which case when your app starts you are expect to initiate the process manually and then you need to use the Download Libary, else it's automagic as my 3 year old says.
From your post you may be looking for a way to get large files (more than one) and do what you want with them, if so this is not a good method to do that since every time you add a new file via the market it would tell your users you have an updated version and overwrite the older file (though you can use the patch extension to avoid that if you are updating the original but that only moves it back one step)
All of that is here what expansions files are for and how to use them
If you just want a method to get large files using your own server take a look at the support package and specifically the loader and loader manager. They also say they are making source code to the extension library downloader and zip file manager available but I haven't bothered to check that yet.