Creating an Android no-op library for Debug Tools

Nathan May
HLTechnologyBlog
Published in
3 min readMay 5, 2020

What is a no-op?

“No op” is short for “no operation”.

It is a common assembly language instruction, and it signifies a computing operation that has no significant effect. For example, a function that contains no code:

In this case, a “no op library” is a library that an application depends upon, but in reality has no effect.

Why do we want a no op library?

During app development, you may want to make use of debug tools which increase efficiency when making changes. However, you often don’t want to put debug tools in the hands of end users. This is because:

  • This would expose a level of control over the app, in production, that is not safe or sensible
  • This would needlessly increase the size of the APK file

A good example of a library like this is Stetho. It is a powerful debugging tool which doesn’t have a readily available no-op version.

So, if we wanted to, we could include the above library in live builds and simply toggle it off (via BuildConfig.FLAVOUR) or create a “DebugApplication” class.
However, neither of these solutions are preferable. The former adds logic and doesn’t remove implementation of the genuine library. The latter removes implementation of the genuine library but adds a new class which extends your normal Application class.

So, how do we create one?

  • Firstly, we add a new module in Android Studio (version 3.6.2 for me) via File -> New -> New Module
  • Then, we add a new Android library which will contain our no-op version:
The Android Studio New Module helper dialog

“Application / Library name” and “Module name” can be whatever you want (within reason of course) but it is important that the “Package name” field is exactly the same as the genuine library that you’re using. We also set the language and the Minimum SDK values to match what the genuine library uses. In this case, it’s Java and API 18.

It is important that the “Package name” field is exactly the same as the genuine library that you’re using.

After finishing the above dialog, we are prompted with an option to generate some files. You can do what you like here, but we ensured that the project file structure was set up in the following way:

An example of project structure

Here, the Android Manifest file is only a single line:

And, we can slim down the automatically generated build file:

Then, we create our own version of the Stetho.java file, with our no-op implementation of all publicly accessible methods from the genuine library’s API surface (in this case, just one!):

So, we’ve created a Java file in our custom library with the same structure as the genuine one, with a class under the same name and the static method that we want, with the same signature. Now, if we were to switch to a live flavour the IDE would show us that there is an error — we cannot resolve Stetho.

Therefore, we need to tell Gradle (Android Studio may automatically suggest this change) which version of the “Stetho” library to use, depending on the build flavour:

Here, debugImplementation tells Gradle which dependency to use in debug flavours. liveImplementation tells Gradle which to use in live flavours, and using project(‘path’) locates our no-op library in our project, by it’s path. This means that, when we’re in a debug flavour, we’re using the genuine version of Stetho. In a live flavour, we’re using our no-op version.

Once Gradle has synchronised, you should notice a difference when finding usages of initializeWithDefaults — the debug flavour will point to the genuine library, and the live flavour to the no-op that we’ve created.

And that’s it!

--

--