Is there a reliable way to specify the UID that Android assigns to the APK during the AOSP builds?
If there is a system APK that is built into and Android image, we observe that sometimes the UID associated with that APK ends up different between consecutive image builds. There seems to be little information that explains how exactly are the UIDs assigned.
The reason we'd like to preserve the UID, for at least one of the applications, is because an application needs to write to an internal file system areas, and if the UID changes between builds, then after a newer image is installed on a device, the files written by the older application are no longer accessible (the permissions to these files are 0600).
We now know that there is a "sharedUserId" Manifest statement that we can probably use for this, but since the application is already in the field, it's too late to apply that, plus that attribute has been deprecated in 29.
Related
How do I ensure that a file I created with the application stays in the iOS and Android device even if the application is deleted with Flutter?
Is there a way to this?
I used flutter path_provider, I save it in the external storage in the documents folder, but when the application is deleted, the file is deleted.
Let me explain why I want to do this. Since no unique information about the device can be obtained in applications anymore, I want to do this by giving a unique id with the file I have printed in it, such as imei number or mac address.
About using "non-deletable" file
Personally, i don't think creating file that containing your unique id is reliable. On Android, user have many ways to delete your file (which is properly stored in external storage) intentionally or unintentionally.
Propose solution
iOS: using keychain with your defined unique id
Android: ANDROID_ID
But Android is somewhat unreliable itself. it has been reported that it can be null when app first run, or can be changed after factory reset. The higher android version code the more stable it is. So using it at your own risk.
Quick pick up: https://github.com/GigaDroid/flutter_udid
References:
https://stackoverflow.com/a/2785493/4478019
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.
Background
I want to check if 2 APK files are identical (or have a very high chance of being identical) in the minimal work on the device.
The reason for this, is that I have an app (here) that allows to install apps using APK files, so I want to check if the installed app is already the same as the APK file. This includes using root privilege for background install. So far, what I did was to check the package name and the version code, but I want to know if there is a little better way to perform this check.
The problem
By "minimal work", I mean minimal reads of the APK file itself. This means that going through all of the bytes of each of the APK files is the most correct way to check if files are identical, but if there is a signature for the APK, that identifies it relatively uniquely, that would be much better.
For example, I know you can do MD5 check on both files, and if it's the same for both, it's a really good chance both are the same, but such an algorithm, along with other similar algorithms (sha1 etc...), go over the entire file, so this is about the same as what I wrote before. It could take a while for large APK files.
What I've found
What I do know is that comparing the package name and the version number gives a clue about whether the APK files are of the same app and version, but I think that Android-Studio knows more about the APK files, because sometimes it asks if we want to uninstall the installed app even though they have the same version, and it doesn't seem like it takes it a lot of time to ask this.
I could add a file size check too, which should be relatively as fast as the package name and the version number, but maybe there is more ...
Here's a sample code of what I did:
public static boolean areApksMostProbablyIdentical(PackageInfo packageInfo, PackageInfo packageInfo2) {
if (packageInfo == null || packageInfo2 == null)
return packageInfo == packageInfo2;
if (!packageInfo.packageName.equals(packageInfo2.packageName))
return false;
if (packageInfo.versionCode != packageInfo2.versionCode)
return false;
final File file = new File(packageInfo.applicationInfo.publicSourceDir);
final File file2 = new File(packageInfo2.applicationInfo.publicSourceDir);
if (file.exists() && file2.exists())
return file.length() == file2.length();
return true;
}
The question
My question is:
Is it possible to perform a "good-enough" check on both files, avoiding comparing all bytes, to see if 2 APK files are the same?
What I do know is that comparing the package name and the version number gives a clue about whether the APK files are of the same app and version,
No it does not. All it tells that both packages used the same values. Anything but that is just pure assumption.
but I think that Android-Studio knows more about the APK files, because sometimes it asks if we want to uninstall the installed app even though they have the same version, and it doesn't seem like it takes it a lot of time to ask this.
Wow :) All AS knows about APK is in APK. There's no magic. Yet, not sure how you managed to reach your 50K (mostly android based) reputation score and still act like you never heard about the APK signing and all the certificate system used on Android. What usually triggers such uninstallation request dialog to popup is ordinary certificate mismatch, usually release vs debug one.
Is it possible to perform a "good-enough" check on both files, avoiding comparing all bytes, to see if 2 APK files are the same?
Once you define what good-enough and the same really means for you in this then perhaps, but by using common means of phrases I'd say no.
EDIT
The reason for this, is that I have an app (here) that allows to install apps using APK files, so I want to check if the installed app is already the same as the APK file
Then all you need to check if your installed app and the APK files are signed using the same certificate and are using the same packageId. If not, this is different app. If this matches, then I'd compare versionCode - if the same -> this is the same app. If higler/lower it's downgrade/upgrade. Sure, one can still release different APKs with the same versionCode and try to sideload it but I'd say it's not your problem to solve (that's the reason Google Play Store enforects versionCode bump on each update). Optionally, if you really got too much spare time you could compare APK file sizes.
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
I want to create an "app loader" (primary) application, which will fetch a license from a server -- this license in turn will determine the features available in two other (secondary) applications.
I'd like to know the best approach to this. Should I:
just fetch the two secondary apks from the same server as the licensing info and attempt their installation from within the app loader code;
pack the secondary apks into the primary app apk. Am I able to then install the secondary apks from within the 'parent' apk's resource/assets at runtime?
recreate the secondary applications as multiple activities within one parent app -- with multiple launchers?
I require advice on the individual scenarios' feasibility, a preference (with a reason why) and indeed which ones are actually possible.
Many thanks.
Am I able to then install the secondary apks from within the 'parent' apk's resource/assets at runtime?
Not without copying those files to external storage. Since you cannot modify resources or assets at runtime, your "packed" "secondary" APKs will remain in the parent APK, for better or worse.
I require advice on the individual scenarios' feasibility
All are feasible, within the constraints outlined above.