Switching AspectJ Plugins in Android
This article will be talking about Aspect-Oriented Programming (AOP), particularly in the context of Android Applications. If you aren't familiar with this paradigm, I'd recommend reading my previous article on the subject: Aspect-Oriented Programming in Android
Artistic interpretation of AOP Code being woven
Trouble in AOParadise
Recently, when updating my Aspect-Oriented Programming Android sample project, I ran into issues for every Android Gradle Plugin (AGP) release version. Frequently with AGP updates, my previous aspect plugin of choice, android-gradle-aspectj, would break and I would be unable to update AGP until the plugin itself supported the newer AGP version.
This isn't ideal for various reasons and was made worse since some recent fixes have re-introduced older issues. Of course, since this is an open-source project, I can't exactly blame the maintainers since it's free software and no one is getting paid. I could potentially fix the issues myself and raise PRs every time the plugin broke with an AGP change (assuming I could understand the internals properly in the first place), but I wanted to find something that felt a little more stable.
At their core, most (if not all) AOP Plugins for Android are using AspectJ as their base, so I figured that as long as I switched to a plugin leveraging the same aspectjrt library, I would be able to swap out the plugins with relatively little effort. This is because the aspects that you write when using the android-gradle-aspectj plugin, for example, are referencing classes within the aspectjrt.jar rather than anything defined in the plugin itself.
Searching GitHub or Google for some AspectJ Android plugins/libraries, I found that the most popular options seemed to be the following (sorry about all the similar names!):
This plugin seems like it would still have the fragile nature I described above since at the time of writing, the project's README specifies that it supports AGP 3.6.1. Further, contributing to the project or understanding the source code itself would likely be a little daunting for me personally as the docs are in Chinese, so I'd need to Google Translate basically everything as I went along.
This is the plugin that I initially was having troubles with in the first place and was looking to replace.
This project has a decent amount of stars on GitHub but is archived and no longer maintained.
No longer maintained.
Since the larger projects for weaving AspectJ in Android seemed unsuitable to me, I figured I'd have to start looking at smaller, newer projects.
While looking for another project, I stumbled upon this article by Eric Schlenz on the Ibotta team: "Ibotta's Solution for AOP Weaving on Android".
I was curious what approach an actual company was taking and intrigued to find out that they had decided to create their own open-source AOP project for Android. They had found that the existing projects had limitations and decided to write their own to solve the issue. Their project is on GitHub and named gradle-aspectj-pipeline-plugin.
Since their article mentions that they use the "Android bytecode manipulation pipeline" and believe that they are the only Android AOP project doing so, I felt like it was worth a shot incorporating into my own sample project to see if it would be a suitable replacement. Since I wasn't using any of the more advanced options provided in the previous plugin, I tried to just switch over to their plugin.
In the top-level build.gradle, I had to add the Gradle plugin repository to my repositories block and replace the old plugin with the new one:
In the app-level build.gradle, I just needed to replace which plugin was applied and add a dependency on the aspectjrt dependency since the plugin doesn't add it automatically:
All-in-all, for a simple project the switch was painless. After running the app, I was able to verify that my existing aspect code was still weaved. I was able to see which locations were injected using the
build/aop.log file (as opposed to
build.ajc-transform.log in the previous plugin) . Most importantly, the aspects were still functioning as expected in the compiled application.
The fact that the plugin switched with such a small amount of effort was great, but it didn't guarantee that the project would still remain functional across AGP updates. However, I did a quick test and it seemed that the same plugin version (1.0.7) did work on all of the AGP plugin versions between 3.0.1 and the current 4.1.1. Since AGP 3.0.1 was released in November 2017, this was a really good sign to me personally and made me feel confident switching, even if the gradle-aspectj-pipeline-plugin is relatively new or has a low number of contributors currently.
Just to be sure, I raised this issue to directly ask the developers about the items I was hesitant about. They mentioned that they did think that AGP updates could break things but figured it was unlikely since the bytecde mechanism they had mentioned has been introduced in April 2017 and the contract hasn't changed since then. Since this made sense to me, I decided to switch the sample project to this new plugin and update my previous AOP article.
Limitations & Considerations
Although this plugin supports Kotlin, Java, and Kotlin+Java codebases, it currently does not appear to support weaving in external aspects from outside the project source code and doesn't appear to be able to weave code inside of libraries (such as appcompat). If you are leveraging either of those features from alternate plugins, I don't think you would be able to make any switch at this time. If you have a more simple setup where your aspects all live inside your own project modules, I believe this plugin could work for you.
Another potential issue is that this project doesn't have much activity around it currently. This is likely due to a combination of factors. AOP isn't exactly super popular for Android in the first place so new libraries are unlikely to get a lot of attention. Further, codebases that are already working won't look to switch unless they are forced to, since generally switching libraries requires a decent amount of work.
This isn't a huge issue now, since the library is working for me directly, but it may be an issue for anyone implementing as there will be less eyes on the project. That being said, the project isn't abandoned and the maintainers are open to community contributions and suggestions.
Thanks for following along with me as I explained why I moved from android-gradle-aspectj to gradle-aspectj-pipeline-plugin for weaving AOP code in my Android builds. If you have any comments or questions, feel free to leave them below. I also would definitely recommend checking out the Ibotta Medium article and their plugin if you are interested in switching (or even doing a first implementation of) AOP in Android!
This article is also available on Medium. You can find it here.