3

I am investigating custom annotation processors for Android applications.

I have a use case where I would like to be able to use an annotation processor to read/amend the AndroidManifest.xml and add the following intent section for all Activities mentioned there in?

        <intent-filter>
            <action android:name="com.my.package.name.my_activity.open"/>
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>

Is this possible?

Hector
  • 4,016
  • 21
  • 112
  • 211

3 Answers3

3

It is a very interesting question but I don't think you could achieve such a task with an annotation processor since those work at Kotlin/Java code generation level.

How would you annotate XML @Something and have it still be valid XML?

Take a look at this:

KoltinConf18 - Annotation processing in Kotlin

Screenshot from the recorded talk on youtube

At 7:18 Zack goes over annotation processing in Java and it basically says:

  • Happens at compile time
  • And you cannot modify code, just generate more

So by using barebones annotation processing you can't really modify the already existing AndroidManifest.xml.

An alternative would be writing a Gradle plugin that generates those bits of XML and merges it with the current XML file that already exists within the project.

Something from the top of my head could be:

  1. Create an annotation and mark all activities that you want to introduce that bit of code
  2. On the plugin side; when you are writing the Gradle task; you may use reflection and figure out which classes are annotated by such extension. Or just make the programmer put those activities in a specific directory inside the source folder, which would be way easier
  3. With the fully qualified class names, you may look at the <activity> nodes in the AndroidManifest.xml, filter out the class names that don't match the list of annotated class names
  4. Modify those nodes with the piece of code you would like to inject.

To get started on how to write a Gradle plugin take a look here

A simple example to get you started could be:

Step 1

You create a separate module to write your plugin if it gets too cumbersome but for this simple example I decided to stick it right in the build.gradle.kts. It doesn't need to be a kotlin Gradle file, but I am more proficient in Kotlin than in Groovy :)

step 1

As you can see I have created a text testFile.txt in the root of the project.

In code I just navigate to it and read it; print it's content and then modify it.

You could do the very same thing with your AndroidManifes.xml. Then you would need to recursively iterate over the source files from your srcDir looking for all of those activities annotated by your special annotation and store all of the fully qualified class names inside a List<String>. Then do the necessary replacements inside the AndroidManifest

Note that with this basic configuration the Gradle task appears in the Gradle tab inside the others category, to change that is a little bit off of the scope of annotation processing.

Step 2, profit

step 2

It works, as you can see the file has been updated and the println statements show the previous content of the file before modifying it

Krishna Sony
  • 1,286
  • 13
  • 27
Some random IT boy
  • 7,569
  • 2
  • 21
  • 47
  • I was'nt thinking of using an @MyAnnotation in XML, I wanted to Annotate each Activity class and then amend the associated AndroidManifest file adding the XML snippet shown in my question – Hector May 22 '20 at 15:31
  • 2
    You can process annotations at run-time or at compile time. The problem is that when the APK is generated the code that you may generate for the activity itself, that code can't really touch the manifest there. The solution would be a gradle plugin that kicks in before all the compilation process and performs such modifications to the AndroidManifest file. Like the databinding plugin. When you hit "sync with gradle" it runs through the layouts and checks the ones whose first node is `` to generate binding classes. You can do the same and modify the AndroidManifest in your project – Some random IT boy May 22 '20 at 15:50
  • 1
    Take a look I've included a small example on how to create a simple gradle plugin that kinda gets close to what you want to do – Some random IT boy May 22 '20 at 20:05
  • 1
    Thanks for the bounty I am glad it was useful – Some random IT boy May 30 '20 at 09:50
1

You could have a template AndroidManifest_template.xml then using a gradle task go through the AndroidManifest_template.xml and generate the real AndroidManifest.xml which would be used to build the app.

In other words, AndroidManest.xml would be a transient part of the build and you could use any XML preprocessor you want to take the template and turn it into the real file.

user2199860
  • 788
  • 4
  • 14
0

In case you want to add these intents conditionally depending on flavour of your app, you could use gradle flavours and manifest merging to achieve this - read more about flavours at https://developer.android.com/studio/build/build-variants

Also refer to following question for example of using gradle to modify manifest

https://stackoverflow.com/a/22759572/9640177

Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122