There are various projects / tutorials / blogs out there about how to integrate AspectJ into the Android development process. They generally show you how to setup an application project to use AspectJ, with the aspects in the project itself.
However the way I tend to use AspectJ in Java projects is to try to put them into reusable libraries so that they can be applied to multiple projects. After all they are supposed to be used for cross-cutting concerns which are common to many applications. Searching the internet, I did not manage to find much information about how to do this in Android.
So here are some examples of one solution I found when using Eclipse (Windows version). If you are not already familiar with creating and setting up Android projects in the Eclipse IDE, and with using AspectJ, have a look at the documentation for Android and AspectJ.
These are the requirements for the samples:
- Android SDK, Tools R21
- Eclipse Java IDE Juno 4.2
- ADT (Android Development Tools) plugin 21.1
- AJDT (AspectJ Development Tools) plugin
Note that the Android tools tend to be a bit brittle, so different versions may have changes (and bugs). So the examples may not work if you are using a different version.
Also I had the following design goals in mind:
- keep it as simple as possible
- stick to using Android libraries
With Eclipse you can put code in separate Java projects and either reference them from an Android application either as a project or a jar, e.g. create a ‘glue’ Android library that references a Java library.
While this might work in Eclipse, it would make things much more complicated if I wanted to use another build system (e.g. Ant) to build the application.
Scenario 1: Self-Contained Aspect Library
In the first example, we will create an android library that contains all the aspect code, and use it to apply the aspects to some code in an application.
Here are some instructions on setting up an Android library with aspects, along with some sample code.
The Test Application
This is just a very simple app to demonstrate the aspects working.
1. Create a new Android application project and add some code that the aspects can intercept.
public class MainActivity extends Activity { private Button testButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); testButton = (Button)findViewById(R.id.test_button); testButton.setOnClickListener(testButtonListener); } private OnClickListener testButtonListener = new OnClickListener() { public void onClick(View v) { // invoke the method to be traced testMethod(); } }; public void testMethod() { Toast.makeText(this, "Inside test method", Toast.LENGTH_SHORT).show(); }
2. Add the AspectJ nature to the application project.
If you already know how to setup AspectJ in an Eclipse project, then you can skip the next bit …
To add the AspectJ nature to the application project, there are 2 ways of doing this:
a. Using the AJDT plugin
Right click on the project in the Package Explorer to bring up the context menu.
- Click ‘Configure’
- Click ‘Convert to AspectJ project’
b. Do it manually
- Edit the ‘.projects’ file for the project.
Replace the java builder …
<buildCommand> <name>org.eclipse.jdt.core.javabuilder</name> <arguments> </arguments> </buildCommand>
with the AspectJ builder …
<buildCommand> <name>org.eclipse.ajdt.core.ajbuilder</name> <arguments> </arguments> </buildCommand>
and then add the AspectJ nature …
<nature>org.eclipse.ajdt.ui.ajnature</nature>
The edited file should look something like this:
<?xml version="1.0" encoding="UTF-8"?> <projectDescription> <name>ATest</name> <comment></comment> <projects> </projects> <buildSpec> <buildCommand> <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> <arguments> </arguments> </buildCommand> <buildCommand> <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> <arguments> </arguments> </buildCommand> <buildCommand> <name>org.eclipse.ajdt.core.ajbuilder</name> <arguments> </arguments> </buildCommand> <buildCommand> <name>com.android.ide.eclipse.adt.ApkBuilder</name> <arguments> </arguments> </buildCommand> </buildSpec> <natures> <nature>org.eclipse.ajdt.ui.ajnature</nature> <nature>com.android.ide.eclipse.adt.AndroidNature</nature> <nature>org.eclipse.jdt.core.javanature</nature> </natures> </projectDescription>
- Add the AspectJ runtime jar to the classpath for the project.
The jar is named ‘aspectjrt.jar’ and it is probably a good idea to use the one that came with the AJDT plugin, which should be located under your Eclipse install at ‘plugin/org.aspectj.runtime_x.x.x’.
There are various ways of doing this, but if you have AJDT installed, the easiest way would be to add it as a library in your ‘Java Build Path’ dialog. In the ‘Java Build Path’ dialog, select the ‘Libraries’ tab, and then click the ‘Add Variable’ button. Then in the ‘New Variable Classpath Enty’ dialog that comes up, select the ‘ASPECTRT_LIB’ entry and click the ‘OK’ button.
To make the sample code a bit more portable, rather than doing it this way, I’ve just copied ‘aspectjrt.jar’ to a directory named ‘lib’ in the project and added it to the classpath from there.
The Aspect library
This is the Android library project that will contain the aspects.
1. Create an Android library project
2. Add the AspectJ nature to the library project (the same as for the application project)
3. For these samples I am going to show a very common usage of AOP – tracing. So add some an AspectJ tracing code to an aspect file in the library project, with the pointcut configured to intercept some code in the application project.
public aspect TraceAspect { private final static String TAG = "Aspect-Trace"; // pointcut to intercept a method in the application project protected pointcut traceOperations(): execution(* au.com.example.test.**.testMethod(..)); before() : traceOperations() { Signature sig = thisJoinPointStaticPart.getSignature(); log("Entering [" + sig.toShortString() + "]"); } protected void log(String msg) { Log.i(TAG, msg); } }
4. Add the aspect library project as an Android library for the application project.
5. Also add the aspect library project to the AspectPath for the application. Do this in the ‘AspectJ Build’ dialog for the application project.
For the application project, right click the project in the Package Explorer to bring up the context menu.
Then either …
- Click ‘Build Path -> Configure Build Path …’ to bring up the project properties dialog
- Click ‘AspectJ Build’ in the side menu
or …
- Click ‘AspectJ Tools -> Configure AspectJ Build Path …’
In the ‘AspectJ Build’ dialog, click the ‘Aspect Path’ tab. Then click the ‘Add Project…’ button and select the aspect library project.
Run the application
Now run the application in your device or emulator, making sure that the code that you want to trace is invoked.
For the sample app, just click the button ‘Click to test tracing’, and then check in LogCat that the aspect tracing has occurred.
The Sample Code
You can download the sample code for this example, aspect-lib-example_1.zip from GitHub.
- Unzip the zip file containing the Eclipse projects.
- Import the projects into your Eclipse IDE.
- The sample projects have Android 4.0 (API level 14) as the Android build target. So you need to either have API 14 present in your Android SDK installation or change the build target for all the projects to another API version.
- Optionally you may have to adjust any application or class paths to suit your development setup.
- Build and run the sample application project.
- Check LogCat to see if the aspect tracing is present.
Conclusion
The problem with this example is that the aspect library isn’t really all that reusable.
If you wanted to use the library in another application, chances are you would have to changed the pointcuts to match the code you want to intercept in the new application.
In the next part of this blog, we will make some improvements to it to make it more reusable.