I'm trying to understand if it is possible to split an Android App into two parts (installed from one APK). I looking into this to install one part on the Device memory and the other part on the SD-CARD. The two parts belong together and should not be installed separately.
Note: I need to separate not only resources, but also activities, so APK Expansion Files not a solution, because not provide such functionality.
I think it will be possible. Can you try following approach?
Create two apps
In the Manifest file of first APK, you should have an Activity that is of MAIN and LAUNCHER category. This way your app will be visible in the Launcher list
You should not have any Activity of MAIN and LAUNCHER category in 2nd APK, but you know which Activity you have to open as Launcher Activity of second app as it's your own app. This way your second app will never show up in Launcher list of apps
Put 2nd APK in assets folder of first APK
Whenever your main app wants to use contents from 2nd app, install 2nd app from assets folder (as mentioned here) with setting the install location on SDCard like this: android:installLocation="preferExternal" and then launch your desired activity of second app
I've not tried this yet but theoretically seems legit.
Let me know if this works. Thanks!
APK Expansion Files
Google Play currently requires that your APK file be no more than 100MB. For most applications, this is plenty of space for all the application's code and assets. However, some apps need more space for high-fidelity graphics, media files, or other large assets. Previously, if your app exceeded 100MB, you had to host and download the additional resources yourself when the user opens the app. Hosting and serving the extra files can be costly, and the user experience is often less than ideal. To make this process easier for you and more pleasant for users, Google Play allows you to attach two large expansion files that supplement your APK.
Google Play hosts the expansion files for your application and serves them to the device at no cost to you. The expansion files are saved to the device's shared storage location (the SD card or USB-mountable partition; also known as the "external" storage) where your app can access them. On most devices, Google Play downloads the expansion file(s) at the same time it downloads the APK, so your application has everything it needs when the user opens it for the first time. In some cases, however, your application must download the files from Google Play when your application starts.
Downloading the Expansion Files
In most cases, Google Play downloads and saves your expansion files to the device at the same time it installs or updates the APK. This way, the expansion files are available when your application launches for the first time. However, in some cases your app must download the expansion files itself by requesting them from a URL provided to you in a response from Google Play's Application Licensing service.
The basic logic you need to download your expansion files is the following:
When your application starts, look for the expansion files on the shared storage location (in the Android/obb// directory).
If the expansion files are there, you're all set and your application can continue.
If the expansion files are not there:
Perform a request using Google Play's Application Licensing to get your app's expansion file names, sizes, and URLs.
Use the URLs provided by Google Play to download the expansion files and save the expansion files. You must save the files to the shared storage location (Android/obb//) and use the exact file name provided by Google Play's response.
Source
Your app could just check wether the sd card is currently available ("plugged-in") or not. If it is available your app works like normal and if the sd card is not available the app would automatically quit / show a pop-up / launch different activities / whatever.
Yeah, it's possible. But with a caveat, it would be possible to install both apps separately, since both of them should be uploaded to the store. You just need to use a lot of intents.
You'll need to handle all communications between both apps using intents. That means, everything the first app needs must be asked using an intent to the second app, and failing to find the other app within the device should trigger an intent to the play store. This way, you'll have two apps working like one. Keep in mind, the user is still going to determine where to install your app, but as christian-strempfer pointed, the SD card can be set as the preferred target.
If the purpose of this is saving space, you should make your resources (images, sounds, etc) dynamic. Since all of those are just files inside the apk, you could easily replace them with files from the SD-Card. You just need to upload them somewhere and download them after the app is installed. That way, you could provide the exact versions of each asset and remove them when you need. You could learn which screens are most used and remove the assets for the ones you use less. Etc.
You can, but not for your reason. Multiple APKs are just to ensure your app works for multiple devices - not to divide up its total size between internal memory and SD card.
Multiple APK Support
Although we encourage you to develop and publish a single APK that
supports as many device configurations as possible, doing so is
sometimes not possible. To help you publish your application for as
many devices as possible, Google Play allows you to publish multiple
APKs under the same application listing. Google Play then supplies
each APK to the appropriate devices based on configuration support
you've declared in the manifest file of each APK.
By publishing your application with multiple APKs, you can:
Support different OpenGL texture compression formats with each APK.
Support different screen configurations with each APK.
Support different platform versions with each APK.
Currently, these are the only device characteristics that Google Play
supports for publishing multiple APKs as the same application.
Maybe is this what you want?
APK Expansion Files
If you're just looking for a way to keep application resources on the external drive, Harry's answer will be useful.
Otherwise it's not possible to split one app installation into two parts. You can use the android:installLocation manifest attribute to define where you want to install it and you can even force it to only install internally on the device, but there is no option to split it.
Alternatives
Two Apps
You create two separate two apps and check on start of any of them, if the other one is installed. If not, you ask the user to install the other one and forward the user to the app store.
One app checks the external storage
I don't know your use case, but from your comments it sounds like you're looking for the wrong solution.
The application I'm thinking about has one part that I want always to be available (install on device memory) and one part that the user may make unavailable (temporary) by removing the SD-CARD. Also when the user decides to move the app to or from the SD-CARD, the part that I want installed in device memory should always stay there.
You can just check if the external storage is available and block certain activties if it's not. If you want to make sure, it's the same SD card you can create a UUID on first run and save it both internally and externally. If they match it's the correct SD card.
Conclusion
Your solution probably is too complicated and you should look for alternatives.
You can create two different launching activities from one APK by defining two MAIN LAUNCHER entries in Manifest.xml
<activity android:name=".ChooserActivity"
android:label="Auth Firebase">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".GoogleSignInActivity"
android:label="Auth Google"
android:installLocation="preferExternal">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
this will create two entry points for an app, two different launcher icons one named "Auth Firebase" and other named "Auth Google" both will open different activities.
Related
I have an app which contains 3rd party apk's for users to download and install on their Android phones. But I would like to have a mechanism through which my users can open those apk's inside my app itself without the need to download them separately on their phones. Is it possible?
That will not be a good choice as keeping those apk files inside your application will increase size of your own application. One good approach to put those apk files on your own server and give a download link in the application for each apk.
I'm expecting suggestions for the concept related to APK Expansion Files in Android.
Google Play currently requires that your APK file be no more than 50MB. For most applications, this is plenty of space for all the application's code and assets. However, some apps need more space for high-fidelity graphics, media files, or other large assets. Previously, if your app exceeded 50MB, you had to host and download the additional resources yourself when the user opens the app. Hosting and serving the extra files can be costly, and the user experience is often less than ideal. To make this process easier for you and more pleasant for users, Google Play allows you to attach two large expansion files that supplement your APK.
Does apple give any support like this?
In my case I have 180MB audio file, I don't want to keep that with app resource. After installation I want this download from APPLE store.
I can able to keep this in my server and download when app opens first time, but I would like to know is there any other way to supplement for iPA.
Thanks InAdvance.
The maximum size of your ipa could be up to 2GB. For sizes upper than 50mb will be downloaded through WiFi or from iTunes. ipa less than that could also be downloaded through 3G network.
Try to make your app size as minimum as possible as users don't really like apps with larger size..
Well there's no thing here in iOS like APK Extension Files in Android.. Everything is your one single ipa which is compressed form of your binaries and resources.
Apple doesn't offer a facility for this specific use case.
You'll have to download the content when your app starts for the first time. Remember to store it in the caches directory or set the "do not backup" flag on the files. This is according to Apple's guidelines and required for app review. If you store it in the Caches directory, iOS may decide to delete the data when disk space is low, so be prepared to download it again if it doesn't exist when your app starts.
Unless you're using in-app purchases and targetting iOS 6 users only, you'll have to host it on your own servers. In-app purchases cannot be free.
I have some very large (650MB) content files (video, audio) in about 4 different locales.
I want to use APK Expansion Files but they do not seem to support localization.
It seems we can have seperate application listings in Google Play as long as they have different application names (app listing filtered per locale).
What I do not understand is, if you upload the same application (in seperate application listings, same binary, same version), how does the device know where to get the expansion files from?
For instance, suppose I have 2 localized applications with seperate application listings:-
My App (UK) + Expansion File (UK)
My App (DE) + Expansion File (DE)
If the application I upload for both listings is the same binary, same version, I can't see how Google Play will know how to associate the app installed, with either of those listings?
This problem occured to me during testing whilst setting up 2 listings for DE and UK with the same draft APK.
Does anyone have any experience with this and is there a recommended approach? Any advice would be much appreciated.
Thanks in advance.
In order for you to upload it as two seperate listings, each application needs to have a different package name. Otherwise when you try to upload the second one, you'll get an error.
When you upload an APK, you also upload the expansion file, which is then associated with that particular APK (via package name). The device gets the expansion file from Google Play, which tracks that association.
All that said, there are disadvantages to uploading two identical APK's- Your ratings will be split across two apps, for instance, and ranking will suffer since neither one will get as many ratings as if you only had one APK covering both situations.
My app requires a lot of image resources, so I've had to package them into an expansion file. I've got this working fine when I manually copy the expansion file to my emulator's shared storage. What's unclear to me is the whole download process.
In Google's (often frustrating) documentation, it says:
On most devices, Google Play downloads the expansion file(s) at the same time it downloads the APK, so your application has everything it needs when the user opens it for the first time. In some cases, however, your application must download the files from Google Play when your application starts.
My app will be free with a single expansion file. Can I actually rely on the expansion file being downloaded with the app? Or must I implement the downloader service to ensure that the expansion file is downloaded when the app starts?
What are the circumstances under which the expansion file would not be downloaded with the apk? I suppose that the user might erase or remove the shared storage volume onto which the expansion file was originally copied, so that might be a case I'd have to worry about.
Tell me I can be lazy! Come on! And then someone link to this question on a blog post lamenting the laziness of app developers. OK, OK, I won't get all defensive. I just want to understand the mechanics here, and yes I would rather avoid the extra headaches of implementing the downloader service. I'm not a full-time Android developer, and I've got other things to do!
Thanks
The play store will attempt to download the expansion files but network connections fail or time out etc
You should check the files are available when your app starts and manually download them if they are not.
If you don't allow for this eventuality then some users will be unable to use your app unless it will work without the expansion pack.
My guess is that the contents of .apk package are extracted somewhere, and the application is registered at some directory so that the application launcher or whatever can find it. But is that all? If that is the case, is the original manifest.xml read every time the app is launched or it gets pre-processed into some other form?
Disclaimer: This answer is now 10 years old 🎉. While overall probably still accurate, details have definitely changed (ART instead of Dalvik, dynamic vs. static permissions, etc). Take it with a grain of salt!
Some basics
The .apk-file
An .apk-file is not magical at all. It's just a bundle of files which represent the content of an Android application. If you open it in a archive-tool (like 7Zip), you can browser and extract it's contents.
Android is Linux
The basic Android-System is a Linux system. Android uses a custom Linux kernel with some extra functionality on power-saving and some speed-improvements. The internal storage of an Android device is formatted with the YAFFS2-filesystem, which fully features the Linux-like access-concepts.
The used file-system might differ by manufacture or Android-Version. Newer devices often use ext3, while Samsung uses it's own file-system: RFS
This is one important aspect of the Sandbox-system, which is used by Android.
Compiling applications
What happens to the .java-files?
First, they are compiled by the normal Java compiler. After they are compiled (to .class-files), the dx-tool from the Android SDK then converts/transpiles those "normal" java-classes into Dalvik-Bytecode.
This "special" java-code is then interpreted by the DVM (Dalvik Virtual Machine), which is based on the opensource JRE-implementation Apache Harmony.
Update: In newer versions of Android, the convert/transpile step can be skipped when jack is used. This way, the .java files are directly compiled into the .dx format.
Also, since version 4.4 (KitKat) Android has the new ART runtime, which officially replaced Dalvik in Android 5 (Lollipop).
What happens to the resources i put into the /asset-directory?
Android offers the /assets-directory to add some binary raw-files (e.g. a SQLite Database). Files which are put into this directory are not compiled or optimized.
If you put your files into this directory, this is the kind of behavior you would expect from Android.
What happens to the resources i put into the /res/raw-directory?
Like the /assets-directory, you can also put binary (or other) raw-files in here (e.g. HTML-files for the Help-page). These files are compiled/optimized (if possible).
What happens to the Manifest and the other XML-files?
The Android-Manifest and also the other XML-files (Layouts, Strings, etc.) are stored and "compiled" into a binary XML-format. This is a speed-optimization.
The Sandbox
From Android OS point of view, a single Application owns:
it's own process,
it's own OS-User (like on Linux),
it's own DVM,
it's own place in the heap and
it's own place on the filesystem.
So yes, every Android app has it's own user which has the proper rights to access it's place in the internal storage (which is protected by standard Linux filesystem rights-management) and it's own DVM-process (which can't be accessed from outside of the application).
To give the application the possibility to leave the Sandbox (e.g. to connect to the Internet), the permissions declared in the Android Manifest are used.
Steps during the installation
So from the above explanations, it should be clear what happens when an Android-Application is installed:
The new user for the Application is created.
With this new users rights, the Applications directory in the internal storage is created.
The contents of the .apk-file are being extracted there.
The Android-Manifest is parsed and the declared intent-filters are registered (e.g. the android.intent.category.LAUNCHER-filter for the applications standard entry point).
Now the application is ready for it's first launch.
When you install an app, Android System copies its APK to "/data/app" folder and it named it by the package name followed by the installations number (how many times you install or update the app).
I tried to install an app manually by copying its APK and paste it in the /data/app folder and rebooted my device then it appears as an installed app and works perfectly.
Also I noticed in the link2SD app that any installed app has the folowing:
Apk located in /data/app/package-number.apk
Dex located in /data/dalvik-cache/data#app#package-number.apk#classes.dex
Lib located in /data/data/package/lib
Data located in /data/data/package
Cache located in /data/data/package/cache
Android defines an intent as "an abstract description of an operation to be performed." Not only do intents let you use activities made by others, but they are also used to launch applications. I'm sure you've seen these lines in every app you've written:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
This intent filter allows the launcher to find the starting activity of each app. Lookup "intent resolution" for more details on this process... I'd say it's more elegant than simply registering the application at some random directory.
As stated in, http://developer.android.com/guide/topics/intents/intents-filters.html, "Android system populates the application launcher, the top-level screen that shows the applications that are available for the user to launch, by finding all the activities with intent filters that specify the "android.intent.action.MAIN" action and "android.intent.category.LAUNCHER" category. It then displays the icons and labels of those activities in the launcher"