Shailen
Shailen

Reputation: 8347

Adding android.jar as a dependency for a module in Android Studio

I have decided to ask the question after my research did not reveal any useful solutions for my scenario which I believe should be quite popular.

My question is slightly related to this SO question, but the solution did not help in my scenario.

I want to create a Java module that will contain only my application logic. That said, I do not want it to be an Android Library module. I do not need to have manifest files and others for such a library. There will not be any Android activities in my application logic Java module. All Android-specific code will be in the Android module (called app). My Java module is called applogic.

So technically, I want my project to look like

AppProjectName
|-->app //Only Android-specific code here
   |
   -->src
|-->applogic //General, reusable Java-code here
   |
   -->src

In the app module settings, I add applogic as a module dependency. From my Android app, I create objects defined in classes in applogic. I am able to do that easily.

And here is the thing. I want to use Android's logging capabilities (in android.util.Log). How can I use that for my Java library?

A possible solution that was stated in the SO question mentioned above was to add android.jar as a library to my applogic module. I was not able to do that in Android Studio. Any guidance will be greatly helpful.

Thanks!

Upvotes: 1

Views: 3368

Answers (4)

Tom Rutchik
Tom Rutchik

Reputation: 1692

Write an interface that mimics the android Log interface

public interface LogInterface {
    int ASSERT = 7;
    int ERROR = 6;
    int WARN = 5;
    int INFO = 4;
    int DEBUG = 3;
    int VERBOSE = 2;
    int d(String tag, String msg, Throwable tr)
    int d(String tag, String msg)
    int e(String tag, String msg)
    int e(String tag, String msg, Throwable tr)
    String getStackTraceString(Throwable tr)
    ...

Modify your main activity so that it implements LogInterface and add the implementation methods for the LogInterface

class MainActivity : AppCompatActivity() implements LogInterface {

public d(d(String tag, String msg, Throwable tr) {
    return Log.d(tag,msg,tr);
}

public d(d(String tag, String msg) {
    return Log.d(tag,msg);
}
public e(d(String tag, String msg, Throwable tr) {
    return Log.e(tag,msg,tr);
}

public e(d(String tag, String msg) {
    return Log.e(tag,msg);
}

public String getStackTraceString(Throwable tr) {
      return Log.getStackTraceString(tr)
}
....

Write your own Log accessor class probably storing it in its own java library module:

final public class Log {

    private Log() {} // prevent this class from being instantiated

    static private LogInterface logInterface;
      static protected void setLogInterface(LogInterface implementation) {
        logInterface = implementation;
    }

    static public int ASSERT = LogInterface.ASSERT;
    static public int ERROR = LogInterface.ERROR;
    static public int WARN = LogInterface.WARN;
    static public int INFO = LogInterface.INFO;
    static public int DEBUG = LogInterface.DEBUG;
    static public int VERBOSE = LogInterface.VERBOSE;
    static d(String tag, String msg, Throwable tr) {
        logInterface.d(tag,msg,tr);
    }
    ...

Initialize the static class in your MainActivity's onCreate method

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    Log.setLogInterface(this)
    ...
}

Include the module containing Log class as a dependencies in your java library. Then in your java library you can use a statement like:

 Log.d("myJavaLibrary", "here's a debug message");

lazyDen's solution is fairly clever, I think it works and it involves less core writing. I don't however like the concept of calling android methods directly from inside a Java library. The android.jar is code that is written to run on top of a properly configured android environment. When you start using android methods from inside your java code, you have no guarantees that your android environment is properly setup when you use methods. Probably is, but who knows for sure. In using the approach that I suggested you don't have to worry whether this is a issue or not. I would strongly suggest avoiding Karim's suggestion of adding the android.jar as a dependency to the java library. That seems like asking for problems.

Upvotes: 0

lazyden
lazyden

Reputation: 456

There is another way to solve the problem w/o using 'android.jar', but it is very round-about.

  1. Create an usual jar module (for example with name 'dummydroid') and add empty implementation of required android API:

    // file dummydroid/src/main/android/util/Log.java
    package android.util;
    public class Log {
      public static int e(String tag, String msg, Throwable tr) { return 0; }
      //... etc
    }
    
  2. add the 'dummydroid' module as a compileOnly dependency to the applogic module

    // applogic/build.gradle
    ...
    dependencies {
        ...
        compileOnly project(path: ':dummydroid')
    }
    
  3. That is all. The dummydroid object helps to resolve calls to android API during compilation of the applogic module. Because of the compileOnly type the dummydroid.jar is not transitively included in the compilation of the android app module --- and API references in applogic.jar are resolved to calls into the real android.jar on device/emulator.

The big shortcoming of this idea is that you have to make dummy implementation of all API those are used in the applogic.

Upvotes: 0

mhsmith
mhsmith

Reputation: 8091

If you're running within the context of a project created by Android Studio, you'll have a local.properties file giving the SDK location. Even if you're haven't got such an auto-generated file, there's nothing stopping you from creating it. It looks something like this:

## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Tue Apr 04 12:34:41 BST 2017
ndk.dir=C\:\\Users\\smith\\Programs\\android-sdk\\ndk-bundle
sdk.dir=C\:\\Users\\smith\\Programs\\android-sdk

Either way, you can then use it in what I assume is the same manner as the Android Gradle plugin does:

dependencies {
    Properties localProps = new Properties()
    localProps.load(project.rootProject.file('local.properties').newDataInputStream())
    implementation files("${localProps.getProperty('sdk.dir')}/platforms/android-15/android.jar")
}

Of course, you'll have to make sure you've downloaded the appropriate version of the platform using the Android SDK Manager, but if you're an Android developer you've probably already done that.

Upvotes: 5

Karim ElDeeb
Karim ElDeeb

Reputation: 375

I have the same setup for one of my projects. I'm using android.util.Log and android.os.Build classes in a Java Library module.

In your app module, you should add applogic as a module dependency to build.gradle, which you have already done.

Then, in your build.gradle for applogic module, you should add android.jar dependency like this:

apply plugin: 'java'

dependencies {
    compile files('libs/android.jar')
}

Since you are using android.util.Log which is available since API 1, then you can use any "android.jar" from any SDK Platform. Just copy it to your applogic module libs folder. Android Studio creates libs folder for Java Library modules.

So, your final project should look like

AppProjectName
|-->app
   |
   -->src
|-->applogic
   |
   -->src
   -->libs
     |
     -->android.jar

Upvotes: 1

Related Questions