Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to merge / combine two aar files?

My use case is the following:

  1. I have an aar library (lets say L1) provided to me by a third party. Please note that I don't have the source for this.
  2. I want to write a wrapper layer on top of L1 and create another aar (SDK) (lets say L2). L1 should be packaged inside L2. Please note that the code in L2 is minimal, it is just like a wrapper for L1.
  3. The idea is that if someone integrates this SDK into their Android application, the application should only be interacting with L2, it should not even need to know that L1 exists. Basically, I want that in the application gradle file, only L2 should be included.

My question is whether this is possible? I looked at some similar questions on stack overflow - I got the following possible solutions - but none of them seemed suitable:

  1. Use android-fat-aar plugin - From what I understand, this plugin does not work with the latest gradle versions and is no longer actively maintained. I am using Android Studio Version 3.3.1 and gradle version 4.10.1. I think it also has some other limitations of not working well in case of aidl files.
  2. Some answers seemed to indicate to publish the aar to some repository like maven, in which case this would get resolved. I am not exactly sure if I understood that correctly, but in any case, publishing either L1 or L2 to any public repository is not an option for me.

So again to reiterate basic requirements are:

  1. The application should only call APIs of and interact with L2.
  2. The application should only need to include depencency of L2 in its gradle file?

Is there any way to achieve it given the constraints I mentioned - it doesn't necessarily have to be via merging aars.

Is the following possible / does it make any sense:

  1. Write the code needed for L2 and create a jar out of it
  2. Extract L1 aar (since aar is basically an archive)
  3. Add the jar created in step 1 above and create a new aar (lets say L3) which includes L2 APIs.
  4. The application now needs to add as dependency and interact with only one dependency L3 (which will have L2 APIs).
like image 243
Archit Sinha Avatar asked Mar 01 '19 17:03

Archit Sinha


1 Answers

Visibility wise, if you want to hide L1, just add it into your project using the "implementation" keyword. That way, it will not be leaked into the consumer's path. Now, that does not mean L1 gets instantaneously packed into L2. Regular binary files pack only their classes, and external classes are expected to be supplied from a repository. Therefore, you have two possible paths:

1.-Upload L1 and L2 to some sort of repository. Note that said repository does not need to be public, you can set your own repository and provide credentials to the users. This is the least painful path in a long term scenario.

2.-Create an uber aar/fat aar. There are several plugins you can use for that. For example this one, which is in active development. Or you can use the maven android plugin and create L2 using maven; in that case, any maven plugin for uber binaries should work. The maven android plugin is compatible with the gradle project format, so you only would need a POM file. Obviously, if you are using extra gradle plugins to build L2, this may not be feasible.

3.-Pack all the L1 classes inside L2 somehow. You may build the aar file manually, for example. The caveat with this, is that maintenance will become a nightmare. You would essentially be going back to an ANT-like scenario, and there are tons of reasons people avoids working with ant. If L1 changes, it will be painful. Also, the final file will not work, since you will need to also trace ALL transitive dependencies of L1 and add them to L2's path so they get imported. If for some chance, the people providing you with L1 did something similar, you are royally screwed.

4.-Provide both L1 and L2 files to the users, so they add them into their lib folders. In this case, even if L1 is being imported as "implementation", it will leak into the path, since pretty much everybody just imports the whole libs folder.

All things said, you need to pick your poison. My recommendation? Create a private repo (you can even use github for that). Is the least painful option, you can cut access to the users whenever you want, and if is necessary to handle custom builds for all of them, it can be done by just changing the artifactId/groupID. All the other paths have gotchas that will give you a hard time at some point.

like image 131
Fco P. Avatar answered Nov 13 '22 03:11

Fco P.