I was trying to create reproducible Android builds, but blocked by drawable resources from AppCompat library.
The drawables, abc_ic_menu_cut_mtrl_alpha.png and abc_ic_menu_copy_mtrl_am_alpha.png appear and disappear from folders res/drawable-ldrtl-xxxhdpi-v17 and res/drawable-xxxhdpi-v4 in the artifact apk files across different builds against same code base.
I'm using androidx.appcompat:appcompat:1.1.0, com.android.tools.build:gradle:3.5.1 and Gradle 5.4.1, and not directly referencing these resources.
shrinkResources wouldn't affect the result as I tested with both true and false. When it was true, I tried to add keep.xml to discard or keep these resources, but the results are the same, neither of them were fully removed.
I suspected it was caused by Gradle merge resources, but couldn't find logs or mapping reports for that.
I noticed that it is Rtl folder that these drawables may be shown, so I also tried android:supportsRtl="false". But the issue persists and rtl resources from AppCompat are still there.
It turned out to be I have used booster framework in my project, which randomly removed the resources when creating artifact apks.
I've created an issue for them https://github.com/didi/booster/issues/103, and have this question resolved.
Related
In android studio's build.gradle file,we can use shrinkresources set to true to shrinkify our app.Also can use minifyenabled and proguard options as well.
But in xamarin, How can I use these options?
I use proguard in my app as it referred in xamarin doc.but didn't find any use of it (I mean my app size didn't get reduced).My simple app is having around 18Mb in size.If anyone have experience using proguard in xamarin,please paste a sample file here also explain how you accomplished this.So others can also benefited.
I know you're asking specifically about the proguard and minifyenabled features of Android Studio but if the intent is specifically to reduce the size of your application, you should configure a more aggressive linking strategy.
Right click android project
Under "Build" select "Android Build" (or "iOS Build")
Select "Link All" for "Linker behavior" dropdown
Make sure this is only for Release or Ad-Hoc configurations, depending on your distribution strategy.
Linker Configuration Workflow:
Run app on a physical device for desired configuration (Release/Ad-Hoc)
Test functionality until "TypeInitializationException" or similar exception occurs
Add the type/field/method to the configuration file
Rinse and repeat until the application is stable
If you don't like the configuration file, you can also use the PreserveAttribute. If the linker is stripping out classes in one of your PCLs that don't have access to this attribute, you can define your own attribute in that PCL called PreserverAttribute because the linker is just looking for an attribute with that name, not necessary of a specific type.
The linker works by analyzing code paths and removing what it believes to be unused references. If you use dependency injection, the linker won't understand which references it needs to keep around so this can take some time but it can drastically reduce the size of your application and you only need to do it once. You can follow the same steps above for iOS as well.
Bonus Make sure "Strip native debugging symbols" is checked in the build options. Its set by default but some disgruntled coworker could have unchecked it.
Additional Resources:
Linking on iOS
Linking on Android
Proguard only can reduce an APK size if it contains a large number of unused classes (e.g. included because of libraries). Therefore it can only reduce the size of the classes.dex file in your APK.
However an APK usually contains a large number of other files - they will not be touched by Proguard.
You should open the generated APK file in a ZIP viewer and see what elements take the space. If it is the classes.dex file it is only a matter of Proguard configuration.
I have a bunch of country flags in my drawable folders for a total of about 5mb. I was wondering if all the images will be packaged in the apk or only the one I reference to in the code.
If all the image get packaged, is there a way to only package those that I use in my code? (by using r.drawable.myimage)?
Thank you
Yes, all resources will be included in your APK even if they are not used.
If you use Gradle build system you can enable shrinkResources:
The Gradle build system for Android supports "resource shrinking": the
automatic removal of resources that are unused, at build time, in the
packaged app. In addition to removing resources in your project that
are not actually needed at runtime, this also removes resources from
libraries you are depending on if they are not actually needed by your
application.
Reference
http://tools.android.com/tech-docs/new-build-system/resource-shrinking
So, I've got a handful of "Utility" style classes in some of my projects. I'm curious if I can move them to an Android Library Project that contains all or most of my non-app specific glue code (wrappers and interfaces, mostly).
So, my question is what happens to the files I don't need in that library. I know Android Library Projects basically just copy their code into the other project, so if I say use 25% of the code in my "general purpose" library, will my app actually contain the bytecode for all 100%, or does it properly strip it down to only the stuff I need.
I had some issues with unused classes in Proguard in the past, so I'm just once-bitten, twice shy with the ADT now...
Unfortunately, all your projects will grow when the library is getting bigger - even if most contents of that library are not used. I tested it myself by creating an app A and a library L. If L is a library used in A, the classes.dex file (and therefore the A.apk file) is growing if I add more classes - even if they are not used.
To sum up: Right now I would create a basic library for certain things that are small and that may be used by many projects, and create a new library for every new component that is going to be larger and only is used by some projects. A good candidate for a new library would be a new UI component with multiple images defined in the resources. A good candidate for the base library are commonly-used methods and things like file caches, for example. Compiled code is compressed quite heavily for Dalvik, which you can see here. (The whole presentation is actually fun to watch :-)
Edit: If ProGuard is activated, it will also remove unused code for you. The default proguard.cfg is sufficient. It will not run on the (default) debug built, but when the final .apk is compiled. So it actually is possible!
I have used 3 level deep Android library projects successfully though it is kind of a pain. The primary use-case is when there are a set of resources and classes that you want to share across a few projects. Since I use a version control system, I would rather not use symlinks.
Note that Android Library projects also suffer greatly when dealing with resources. ADT will rebuild R.java once for each library, and each R.java will contain a copy of all resource ids from all libraries. The core problem here is that resources are regenerated for the entire project as a whole, and there is no way to "build a jar" for a dependency as would be expected with normal "libraries". We tried integrating with OpenFeint, and had all kinds of hell dealing with libraries and dependencies. I think we ended up just merging all the OpenFeint source and resource files into our own project and ditching the "Library" project as it was offering little value.
Android Library projects are a clunky way of sharing code between projects and have a number of drawbacks. I've found that everything accomplished with a Library project can also be accomplished with symlinks (symlink source into two projects). I've yet to find a usecase where an Android Library project offered something that wasn't easy to replicate with other, less fragile means.
I am having two versions of my android project (release and debug). They both are sharing the same source files. I want the debug version to be intact when we checkin any changes for release build.
It is not working as we cant have 2 different manifest files for it and if we make change in manifest, it will affect both the projects and keep them out of sync.
Is there any way we can have different build configurations for same project?
Please advise.
Thanks
If you don't want to impact the debug app when changing the release source files you'll have to use different source files. Having different build files or configuration will not help.
Gradle apps use at least 3 source folders.
src/main/... is used by all variants
src/debug/... is used by the debug variant
src/release/... is used by the release variant
To do a change that only impact the release variant, just edit code in src/release/.... This can contain a manifest, res, java code, etc...
That said I'm not why you don't want to change the debug version when changing the release version. The whole point of the debug version is to be the same as the release, except debuggable. The different source folders above should only be used for minor things (like enabling/disabling log output for instance). Making both versions different in bigger ways is not recommended.
I have a project A that referenced by Library B, A and B have the same name and type, but their value are different. I think aapt should deal with this issue that make sure project and library access the correct value. besides renaming all the resource in project or library, what else should I do to solve this problem?
The build system intentionally makes all project resources overlay on top of the library resources. This is done on purpose to be able to customize a library resource differently depending on the app using it.
If you want to prevent this happening without your knowledge we have always recommended users to use prefix in the library resources.
Changing the behavior at this point would break many, many people's projects. We've looked at making it an option, but it won't happen before the new build system is finished though.
As per the Android Building process, all projects and libraries (and all of the resources in all of them) are combined as part of the apkbuilder process. If there is a conflict between your project and library (or between two libraries), the final build will not know which to reference as they share the same name. Of course, this has benefits in that you can reference library resources in your project by name, even though the underlying build process is de-conflicting the underlying ids.
Import the appropriate R.java file to resolve the resource conflicts.
Make sure that your package name and the library's package names are different.
If you need your libraries resources then refer to them by library.packagename.R.drawable.resourceId and not by R.drawable.resourceId
Check your gen files if it has 2 R.java files.