I received some legacy code of app (not developed by me, but by some other team, with no documentation), which has almost 20+ dependencies, in build.gradle.
Now, I wanted to clean up unused Libraries/dependencies, by removing them from build.gradle
I searched on Google and came across this project for resource shrinking. But it seems to be used for removal of resources that are unused, at build time, in the packaged app and this also removes resources from libraries you are depending on if they are not actually needed by your application.
Also, I use ProGuard, for obfuscation and shrinking in conjunction with shrinkResources true in build.gradle
My intention is to remove unused Libraries/dependencies from build.gradle itself, without breaking app functionality.
Is there a way or tool which shows which library is safe to remove without breaking the app functionality?
By 20+ dependencies you don't need any tooling and can do a manual check.
I would proceed like this:
Comment out all dependencies and check what fails (see below)
Uncomment the dependency that causes the failure
Repeat
This way you might also notice dependencies that are seldom used or can be replaced with standard libraries or other libraries that you use in the project.
Here are the things that will indicate you that a dependency is required (in the order of slowing down the feedback loop):
compilation errors
unit test errors
integration / system / end-to-end / device test errors (whatever you use and call them)
application functionality at runtime
application performance at runtime
Runtime dependencies can be especially tricky. For example, your code might not depend on a library, but this library provides a runtime implementation for some other library you depend on. Removing such a dependency will only be visible at runtime as missing functionality or performance issues.
Instead of commenting out all dependencies I would go the other way around - comment out one dependency at a time and see what breaks. This way you would also get a grasp of use-cases of all dependencies because the IDE will point you to the place where code broke. If nothing breaks after commenting out a dependency you'll know that it's not used. Another thing you could potentially do is analyze an unobfuscated release .apk where all unused dependencies will be missing but package structure will be preserved.
If you mean that finding unused library or import, you can easily see with "Ctrl + alt + shift + i" and type "unused import"
You can see now all unused imports.
Finding libraries and resources used in an Android app comes up in several contexts.
For the apps published in Google Play, AppBrain maintains reverse lookups, from the library to the more popular apps that use it. For example, apps using a newish 2D game library Godot.
Apktool will decode the APK directly.
The author instead wants to find (unused) resources, starting from the source code and the build process. Gabriele Mariotti above links to the question, whose accepted answer provides detailed information on use of minifyEnabled and shrinkResources in Gradle configuration.
Review Shrinking Android app and ProGuard vs R8.
Related
A project I'm working on contains a lot of external dependencies on 3rd party libraries. While analyzing compiled apk I found out that a package within the app that is supposed to be obfuscated remains clean. When I dived deeper I figured out that merged ProGuard configuration contains a rule breaking obfuscation logic.
None of the project's ProGuard configurations contain this rule. So I assume that it was gotten from one of the dependencies and merged to final configuration.
I look through this question but it seems that the answer is no longer valid for Android Plugin for Gradle 3.0.1 that I'm using because build/intermediates/exploded-aar folder no longer contains any ProGuard configurations.
So I'm wondering:
Is there a way to find what library causes the problem?
Is it still possible to disable a rule from consumer proguard file?
I'm in the process of writing an instant app for others to learn how to write an instant app and hoping to get some ideas on how to best structure the app for dependencies.
Now reading the Android developer docs on project structure and referencing the diagram below:
I'm wondering with the new gradle 3.0 dependency configurations, what libraries should live in which modules?
Base Feature
I was thinking pretty much anything in the base feature module should be using the api gradle configuration since the base feature module essentially compiles down to an AAR library file. One question I might have for this module, if one was to use ROOM would this be the module to place it in?
Feature
Now in the feature modules, it is my understanding that everything should be utilizing the implementation gradle configuration since these modules should not leak there dependencies out to any other modules in order to truly make them independent from one another.
Just looking for some confirmation of my understanding and also any ideas to help with the project. Here is the github repo if you want to check out the code I got so far. It is really simple at the moment, but I was thinking about messing around with the Star Wars API using Retrofit.
Thanks for any help and gladly accept any contributions if you want to to try and make a pull request yourself for any other concepts in making an instant app that others should know.
Shared details in your question are correct. Consider some of the below suggestions which add to the points mentioned by TWL:
Adding certain libraries to specific feature module which should
be included in the feature module only, instead of being added in the
base APK.
For example, let's say you have an application that depends on
libraries X, Y, and Z. Initially, you may pack all the libraries in
the base module by placing all the dependencies in the base
gradle.build file. But if only the code in the feature module requires
library Z, it makes sense to move that dependency from the base module
to the feature module.This works as long as no other feature modules
depend on the same library. If multiple feature modules use the same
library it definitely makes sense to keep it in the base module.
Taking care of Transitive dependencies.
Transitive dependencies occur when the library your project relies
upon depends on another library, which in turn may depend on yet
another library. Sometimes those transitive dependencies may contain
unexpected surprises such as libraries you do not need at all (i.e. a
JSON processing library you never use in your code.)
I hope this adds some information to your query,
I'm wondering with the new gradle 3.0 dependency configurations, what libraries should live in which modules?
Some of these links can also be referred for additional data:
Android Instant Apps(best-practices)
AIA structure
As mentioned by keyboardsurfer, your dependency assumption is in the right direction.
Base is at the root and acts like a library shared by all the
non-base feature modules, so its shared dependencies should be set with
api so that modules that depend on it can also access them. (though, base doesn't have to act only like a library, it can
also be a feature APK itself)
Features, as an instant app, each one extends out to the end as its own APK, so there's no reason it should be leaking its dependencies to any other modules and therefore dependencies should be set with implementation here.
Within the Google Samples, the cookie-api and install-api are some samples that more clearly demonstrate the dependency configuration usage as how I explained above.
We have developed an android library (aar) using Java and it depends on android support library v4. In fact, we have extended ViewPager (android.support.v4.view.ViewPager) class and consumed it in our library’s GUI.
We have applied proguard on the library and it works fine with our test apps but we have a customer that has developed its android app in native C++ and they are going to integrate our component into their app and there is an issue on build.
They receive com.android.dex.DexIndexOverflowException on build which is a sign of having more than almost 64K methods that are allowed in a single dex.
They asked us to use fewer or smaller dependencies as they have to include our component dependencies into their build setting and one of their suggestions is that we should extract ViewPager out of android support source and put it in our component source code.
Now the questions are
If we extract ViewPager out of android source and add it to our
library source code then will it reduce the amount of methods to
prevent mentioned exception? Is it a good practice to do that?
What is the best way to resolve this issue?
Thanks
If we extract ViewPager out of android source and add it to our library source code then will it reduce the amount of methods to prevent mentioned exception?
Probably not, at least for release builds. Your customer should have configured ProGuard, which will identify and remove unnecessary code pulled in via libraries.
Is it a good practice to do that?
No. Your customer should know better than that.
What is the best way to resolve this issue?
Mostly, it is not your problem. It is your customer's problem. Your customer is blaming you, but there is no evidence in your question that your library is a significant source of the customer's DEX method references.
Your customer should be configuring ProGuard, and your customer should use the APK Analyzer in Android Studio 2.2+ to see where their method references come from.
You, in your library, could:
Try to use more focused dependencies than support-v4. ViewPager itself is in the support-core-ui artifact. However, if you are using FragmentPagerAdapter or FragmentStatePagerAdapter, in addition you will need either support-fragment (if you are using the v4 edition of those classes) or support-v13 (if you are using the v13 edition of those classes).
Use the APK Analyzer on some demo project that you create that uses your library, so you can see how many DEX method references that your library uses, to see if you are really a significant source of such references.
Suggest ProGuard settings for your customer that will keep required classes of yours, to help them use ProGuard effectively with their app.
You can set jumboMode in your build.gradlefile like this:
dexOptions {
jumboMode true
}
This option will allow you to have 32it wide string references in your .dex file. Thus you can have 2^32 referenced strings in your project.
Hope it helps.
Available options are :
Yes, you can extract ViewPager from support library. ViewPager import some files from support library that are also required to be extracted. This will reduce method count with significant difference.
You can also use exclude parameter in dependencies in build.gradle file.
compile ('com.android.support:recyclerview-v7:+') {
exclude module: 'support-v4'
}
I would like built a closed source android library using the Gradle. My library has some dependencies to open source projects. How should I structure my library? Can I use gradle?
Can I use gradle?
Short answer:
Yes.
Long answer:
I would assume that your library is packaged as aar (contains resources and compiled bytecode).
First thing you need to know is that at the moment of writing this post there is no way to create fat-aar libraries, which means that you'll have to distribute dependencies of your library separately. The most convenient way to do that, in my opinion, is to generate pom.xml file and publish your library on Maven repository (maven plugin can do all of that), so clients will just fetch all dependencies themselves. Since it is a "private" library, that could be your company's closed repo by access rights (in simple words - create special user for your repo and share password with interested parties).
One downside here is that all dependencies will be exposed in pom.xml and you won't be able to obfuscate them. Personally, I don't think that this is an issue.
Moreover, you get the huge advantage of being able to deploy build automatically and let clients use snapshot versions of the library. This is extremely helpful when you're trying to fix issues and want to deliver them to users fast. On client's side, all they need to do is either just update version in their build.gradle or just re-sync project in case if they were using snapshot.
Second thing. Since your library is closed source, you need to run proguard to obfuscate everything but public interface of your library (all public methods which are exposed to end user).
Remember, that even after obfuscation your code still can be decompiled and all string literals are still there. So, although it was said million times already, avoid storing any critical data in the library (such as passwords, keys, etc.). It is not as hard to extract it as you might think it is: https://www.youtube.com/watch?v=X28Oogg2Q3k
Third thing. I highly suggest you to create internal test project (as a gradle submodule) which will use your library, so you will be sure that you're not making any breaking changes.
Hopefully this answer made things at least a bit easier for you.
For the moment I am developing small Android projects to practice with the Android prorgramming. However, once on the market, I would like to obfuscate / optimise the APK thanks to ProGuard. But this tool renames classes to obfuscate the code, so:
Is it safe to use tools like Android Query to write the code?
If it is not safe, what are some framework examples that can be used safely with Pro Guard?
What could be a solution to the problem? Or should I write everything using the good old Android style and forget about a "write less, do more" approach?
How do I identify the tools that are ProGuard-safe from the ones that are not?
I assume you want to use third party libraries (jar files). You could use a 3 step approach:
If the third party jar explicitly supports Android, it will have a proguard configuration. Usually this is a snippet that you merge into your proguard-project.txt.
If there is no such explicit support, you may still try to use the jar, obfuscate and test your app. If errors occur, gradually exclude classes from obfuscation until it works. A common problem is that libraries use reflection to instantiate classes and call methods which breaks after obfuscation.
Exclude the whole library from obfuscation. This will work in any case and proguard will not touch the library at all. (The Android toolchain will still repackage the contents of the jar into your apk which might cause problems.) This will also produce the least obfuscated result and should really be your last resort.
In any case, obfuscation is not a switch that you simply toggle. You'll need to get familiar with proguard config files which involves a learning curve.