Reputation: 8347
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
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
Reputation: 456
There is another way to solve the problem w/o using 'android.jar', but it is very round-about.
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
}
add the 'dummydroid' module as a compileOnly
dependency to the applogic
module
// applogic/build.gradle
...
dependencies {
...
compileOnly project(path: ':dummydroid')
}
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
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
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