Android

It is possible to create an Android port of BaseX. The present tutorial outlines the creation of a BaseX Android library, which can be used in any other application project.

For the creation of the library the IDE Android Studio is used, but the steps are more or less equal using the Eclipse IDE.


Creating the Android Library Project

The first step is to create an Android library project, which will be later modified to represent the BaseX Android library.

In Android Studio, the “Create New Project” menu item needs to be chosen. In order to this, the displayed window appears.

It is important that the minimum Android version is Gingerbread 2.3.3, because of some String methods used in BaseX which are not supported by Android versions older than Gingerbread.

To create an Android library project, the “Mark this project as library” item is checked. An Android library is not executable and therefore does not need the creation of an Activity, which is why this item is unchecked in the picture above.

Next, Android Studio creates an empty library project with all needed folders and files.

The next step is to copy the BaseX code into the created project folder src/main/java.

Except for the package gui and the Java file BaseXGUI.java, everything in the org.basex package can be copied into the project folder (Android does not support Java AWT and Swing).


Adjusting the Code

After having copied the BaseX packages and java files into the created Android library project, a few adjustments have to be done in order to get a working Android library.

At this moment, the BaseX source code is presented in the Android library project as well as an empty android package as shown in the following image.

In the empty Android package, a new Java class needs to be created, which is used to create the necessary BaseX files and communicate with BaseX. This class needs the data directory of the application for storing the corresponding BaseX files. The files should be stored in the apps /data/data/.. folder, which is only accessible from the application.

This information is only available inside the application context and not inside a library project, therefore it is necessary to pass this information to this class at the constructor call. The following source code shows a minimal example for a BaseX class.

public class BaseXDatabase {
  /** Database context. */
  private Context context;

  /**
   * Constructor.
   * @param dir  database directory
   */
  public BaseXDatabase(String dir) {
    context = new Context(dir);
  }
}

This class can be called in every Android application which uses the BaseX library with the following call, for example:

BaseXDatabase db = new BaseXDatabase(getApplicationInfo().dir);

Next, a constructor needs to be added to the Context class to create the BaseX files in the right directory and adjust the default constructor of it:

public Context(String path) {
  this(true, (Prop.HOME = path + "/"), (Prop.USERHOME = path + "/"));
  File dir = new File(Prop.HOME, "basex/data");
  if (!dir.exists()) {
    if (!dir.mkdir()) {
      android.util.Log.i("BASEX", "CREATING BASEX DIRECTORIES");
    }
  }
}

private Context(final boolean file, String home, String userhome) {
  this(new MainProp(file));
}

The two variables Prop.HOME and Prop.USERHOME need to be assigned during the constructor call. In the BaseX code, the variables are final, which needs to be changed.

The reason for this change is that System.getProperty(user.dir) returns an empty string in Android.


The next adjustment is to remove not supported packages inside the BaseX code. For example, the package 'org.basex.query.util.crypto' need to be removed, because it uses external packages which are not supported by Android.

The class which uses these files is found inside the FNCrypto.java file in the 'query.func' package. This file needs to be deleted as well as its usage inside the Function.java file, which can also be found inside the query.func package.

All enum entries starting with _CRYPTO need to be removed, as well as the URI registration:

/** XQuery function. */
_CRYPTO_HMAC(FNCrypto.class, "hmac(message,key,algorithm[,encoding])",
    arg(STR, STR, STR, STR_ZO), STR),
...

URIS.put(FNCrypto.class, CRYPTOURI);

The result of this adjustment is, that it is now possible to use BaseX as an Android library, with the lack of support of the following XQuery functions:

  • hmac(string,string,string[,string])
  • encrypt(string,string,string,string)
  • decrypt(string,string,string,string)
  • generate-signature(node,string,string,string,string,string[,item][,item])
  • validate-signature(node)

Using the BaseX Android Library

To use the BaseX library, the BaseXDatabase class can be extended with additional methods which are delegating requests to the BaseX database and return the results.

An example of this can be seen in the following code:

public String executeXQuery(String query) throws IOException {
  if (context != null) return new XQuery(query).execute(context);
  Log.e("BaseXDatabase", "No context");
  return "";
}

The methods of the BaseXDatabase class can now be used in every Android application that includes the created BaseX Android library.

A .jar can be created, or an .aar file, by just building the source code. This file need to be copied inside the lib folder of the Android project. Additionally, the build file of the application must be adjusted to use the library.

Using Gradle, the Android build system, it can be done by adding the following line to the Gradle build file. This tells the build system that every library, inside the libs folder, is being compiled into the projects file.

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}

⚡Generated with XQuery