When it comes to debugging tools and libraries for Android such as Stetho or Chuck or the Jake Wharton’s great Leak Canary, there’re almost separate modules for debug and release builds. For example, when you add Leak Canary in your app, you will be adding dependencies like this:

  debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
  releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'

Please note that there are two separate modules or AARs for debug and release. Its a common practice to call release variants for debugging and inspection tools as NO OP or No Operations. The purpose of this no-op modules is to do absolutely nothing in the code. Its just an empty wrapper of the debug module to avoid the compile time errors such as Unresolved method name or so.

Few days ago, I was working on a debugging tool plugin for Hyperion called as DBFlow Manager Hyperion plugin. I didn’t know about no-op yet and I simply created a module which did all the work for the DBFlow databases inspection and played very well with Hyperion. I added it in the app using debugImplementation and everything was great until I made a release APK of the app.

I was unable to compile a release APK now. The error I was getting was Unresolved object: DBFlowManager_Hyperion_Constants. You can follow the whole issue (fixed and closed) at here. Apparently, the app was using DBFlowManager_Hyperion_Constants in the code and this class was only available for debug builds as we only included the plugin for debugging. But, since code was using a reference, so release APK couldn’t find the class reference and it failed.

After a simple google search, I managed to learn about how it all works. I created another no-op module. All you have to do is add empty classes and methods and simply compile it. Now when release apk will be compiled, it will find all the references but code will do nothing at all. It will be just for a placeholder purpose.

For example, the DBFlowManagerPlugin class in the debug module looks like this:

public class DBFlowManagerPlugin extends Plugin {

    public PluginModule createPluginModule() {
        return new DBFlowManagerModule();               // This is the functionality class

While this same class in release and no-op module is empty and looks like this:

public class DBFlowManagerPlugin {

    public Object createPluginModule() {
        return null;                                   // This is returning null. 

Note that only class and method names are same. Even method’s return type has been changed to Object. It’s all an empty and nothing-to-do module.