How to apply lintChecks to all dependent modules? - android

I created a custom Lint check and want the check applied to all dependent modules in my Android project. The custom Lint check lives in the checks module, and I can successfully run it in other modules by adding lintChecks project(":checks") to their respective build.gradle files. What I'd like to do is add something similar to api <dependency>, so all dependent modules also run the check. There is a core module already serving the purpose for other functionalities. Is there an API or configuration to prevent lintChecks redundancy? Such that all I'd have to do is add lintChecks project(":checks") to the core module.

I did not create an IssueRegistry file in the correct directory, resulting in Gradle not showing the task. Found out lintChecks in build.gradle files was never necessary.

Related

Dependency missing but exists in APK, how?

I have a MyLocationService library, which has dependency from huawei_location_service.Inside I have HMSLocationService class which is the only one using huawei_location_service classes and I use relfection to access that class. Meaning is, if we run app on Huawei and if there is dependency from huawei_location_service, I will get location, otherwise will not. And application should run perfectly on non-hauwei devices without dependency from huawei_location_service.
So when I build MyLocationService.aar I removed huawei_location_service dependency from it's pom file. After that I created a new application and added dependency from MyLocationService.aar. When I check dependencies with command gradlew app:dependencies I don't see any dependency from huawei, but when I create an apk and analyze it, in classes.dex there are classes from huawei_location_service.
Question: How it is possible? And is there any other way to achieve what I want?
P.S. I analyzed also MyLocationService.aar, didn't find any huawei dependency. Is there another way to check dependencies of *.aar files instead of pom or analyzing tool of android studio?
So if someone will be mistaken as me, this answer will help.
The repositories and classes I saw in classes.dex were not coming from hms libraries. As I have imports in my custom classes, that imports' texts were the reason I was seeing huawei folder in classes.dex. Also take attention on the size, and you can see that they are kind of 20 bytes.
So I removed the imports, generate my library again, created apk and analyzed it and woala, no huawei folder is visible.
P.S. *.aars doesn't contain any library if you not put transitive=true. And you need to add dependencies required by your lib in your own applicaiton.
P.S.S. If you have locally or globally publishing your library, maven(Gradle uses maven) creates metadata, so called POM file, as a helper to identify all dependencies that the library needs.

How to organize common gradle tasks and extract common code blocks

I have an android project consisting of 10+ library modules. Each of these modules contains a lot of gradle code common to all modules. For example, I'm using the Javadoc generation task from this answer in all of my build.gradle files.
How would I go about to extract that task creation logic to a function put in a separate gradle file which can be "included" by each module? The code is identical for all my modules, but obviously depends on variant and project. Is it possible to extract a function that takes a project as parameter and returns a task for that project?
I'm probably going around this backwards since I really suck at Gradle but any pointers leading to me avoiding having the same 60 lines of gradle code in 10 different files (lib1/build.gradle, lib2/build.gradle, ...) would be helpful!
In fact, taking it even further, basically my entire build.gradle is identical for all projects except the dependencies section - there's an android block with buildTypes, compileOptions etc, there are some plugins applied (apply plugin: 'com.android.library' etc), and there are some artifact parameters set up. In fact, only my dependencies differ at all. So I'm wondering if it would be possible to extract a common file completely, like this (pseudo code obviously):
<include common.gradle> // includes android block, common tasks, artifact setup etc.
dependencies {
api 'androidx.appcompat:appcompat:1.1.0'
api 'com.google.code.gson:gson:2.8.5'
...
}
You can extract your common settings into a gradle file (lets say common.gradle and then use it as
apply from: '../path/to/common.gradle'
Reference: https://docs.gradle.org/current/userguide/plugins.html#sec:script_plugins
The recommended way of extracting common build logic is to leverage buildSrc and create plugins that are then applied to your projects.
This has a number of benefits of applying a script, as documented.
In addition, I would recommend being explicit through plugin application. While you could develop a single plugin that configures all your projects, with some logic based on project name for example, it is usually better to have different plugins matching the different project types.
That way, when opening a build file you immediately see what kind of project it is.
And of course you can have common code in buildSrc for the common parts.
One more benefit is that moving from a buildSrc plugin to a published plugin is much easier ... just in case your configuration patterns start to appear in different projects.

Android dynamic feature modules dependencies

so I have a couple of features that share common code - let's call them "feature1" and "feature2". I can't add the shared code as dependencies for "feature1" and "feature2" - Android studio throws the following error:
Multiple APKs packaging the same library can cause runtime errors.
Adding the above library as a dependency of the base module will resolve this
issue by packaging the library with the base APK instead.
So I thought I just create another dynamic feature module - let's call it "core" - to deliver the shared dependencies there. Which also works, kind of. I can access all the java classes from "core" inside "feature1" and "feature2", but as soon as I want to access a resource I get an ResourceNotFoundException. The features are deliver Fragments that call SplitCompat.install(context) in their onAttach() function.
So my question is - is it even possible to have a dynamic feature module where common code is stored, or should this all go in the app?
Thanks & Regards, Romanski
Now support for feature on feature dependencies have been introduced in the latest release of gradle:
https://developer.android.com/studio/releases/gradle-plugin#feature-on-feature

How can I acces Activity from AAR emded into another AAR?

How can I access Activity from AAR library which is not directly included into the project but is embed to another AAR library?
I got an error java.lang.NoClassDefFoundError: Failed resolution of:
The class is public and if I compile it directly in project application it can be used without problem.
I included an AAR to my project like this :
ProjectApplication
|
+--sharedModule (android library - AAR or any working solution)
| |
| +--Module1 (android library - AAR or any working solution)
| |
| +--Module2 (android library - AAR or any working solution)
| |
| +--Module3 (android library - AAR or any working solution)
compile (project(":sharedFrameWork")){ transitive = true }
which has also included in itself 2 other AAR libs. They are also set to be Transitive. When I try to open an activity from one of the sub AAR libraries. I got the class not found error. But when I include that particular AAR into my application directly the class is found and can be used. It looks like I do not have access to any sub AAR libraries which are not included directly into my Application.
To better describe my situation :
I have to create an integration AAR library (later called 'sharedFrameWork') which includes multiple AAR libraries and is later embed into an application.
Multiple AAR -> Shared AAR 'sharedFrameWork' -> Application
The sharedFrameWork has some method which starts some activities from the included AAR's or set up basic communication with the server. I have read that if all the dependencies are set to be transitive it will make it work, but unfortunately it does not.
So When I call from my application a method which should start an activity from one of the included AAR in sharedFrameWork the app reports me that no such a class was found.
But when I include that AAR module right to my application not to sharedFrameWork, and then call the exact same functionality the Class is found and the project is working as it is designed. Can you help me how can I create this sharedFrameWork to be working as it is designed? Can it be done by using AAR or should I take another approach? If any other way it can be done and the result will be that I can deliver just one library and it will work as designed so it can access its submodules I will go with it, feel free to point me out the best approach for this problem.
If I get it right, you want to create a fat AAR and achieve a single import of several libraries.
Now, since you haven't provided more info, I'm going to assume you are using gradle 2. In gradle 2, submodules don't share their dependencies. neither does anything you put into the libs folder. So, first, I would upgrade your projects to gradle 3, switch from "compile" command to "api" command, and check.
If that does not work, the next step would be to apply the gradle maven plugin to each one of your modules, and deploy the resultant AAR file to either your local maven repo (automatically created when you install maven), or a remote repo, like jitpack. If you have AARs/JARs into the libs folder, deploy them to a repo too and import them from there (libs folder scope is local in gradle 2, and in general, is a bad idea to use it instead of a centralized repo. You can even use github as a repo). Then, use the artifacts.
Finally, the last solution for your problem would be to use "shading"; the process to pack several different artifacts into one. If you can't upgrade to gradle 3, or deploy the artifacts somewhere (unlikely), this is what you should do. There are several plugins for this:
https://plugins.gradle.org/search?term=shade
https://github.com/zawn/android-shade-plugin
if those don't work for you, switch to maven and use the maven shade plugin.
As a side note, you should not provide a fat AAR. Is better to keep your framework in separate modules. That will speed up your build process and allow you to save space if you don't require some classes. Even in a multimodule project, you can create separate artifacts, one for each module, and import them as you need. Just avoid circular references (a module A that requires a module B which requires module C which requires module A) and you'll be fine.

How to access layouts of a sub-module from another sub-module?

I have two modules in my android project. And I want both of these modules to access the layout files of other module and perform operations like Intent().
But, Using compile project (':x ') is not working for this.
Edit:
Both the modules are successfully added into the project and gradle was synced properly and manifests are merged. I want to how to access res/layout files of one module from another module's java file.For context, I have activityA.xml in module 1 which I need in module two so that when a button is clicked in module 2, it transits to ActivityA.xml with intent.
ok so to use resources from another module you must do a few things.
Determine how you will package and use your module. Is the module "just" for this app or is it used in others.
If it is used by more than one project then I recommend packaging it as an AAR and hosting in a Maven Repo of your own and pulling via Gradle to avoid project dependencies on the code base itself.
If it is only used by this project then you must do a couple things as well.
1) Ensure that the settings.gradle has the module included. You can do this with simple :moduleName if it is local to the project directory. Otherwise you can do it with
include 'myLib'
project(':myLib').projectDir = new File('../../../workspace/libs/myLib')
Once you have done this confirm Gradle Sync pulls the module into the project. And not just an empty folder with an IML. If it is an empty folder confirm your path and try again.
Step 2) So you successfully imported your module and you can see it in your directory. However, you can't have a module depend on the app and the app depend on the module. It is called circular dependency, so you must only have the app depend on the module. Go to your app's module the one where it has
apply plugin: 'com.android.application'
and go to the dependency section and include
compile ':myLib'
Now you need to confirm your compile myLib is working (myLib is the name of your lib). To confirm you can do an assembleRelease from the terminal and see if it has any issue or you can do a Gradlesync as well.
If it worked you can now import resources or files into any Activity of the parent app module by simply including the import statement at the top.
Now you can do things like HelperClass.doSomething (where helperClass lives in myLibs).
So let's take it one step further. Maybe you need HelperClass to be able to respond to the app module. Then you must supply an interface inside the myLib of IMyCallBack with whatever methods you would call out to and have the parent module calling activity implement the interface for calling back.
Does this answer your question or are you having another issue. A there should be no issue accessing the content of your child module if your dependency is setup correctly.

Categories

Resources