How to build an android library with Android Studio and gradle?
AndroidGradleAndroid StudioAndroid Problem Overview
I am trying to migrate a project from Eclipse but nothing I have tried is working. In Eclipse I have 3 projects (2 android app projects and 1 android library project). The 2 app projects depend on the library project. When I do the gradle export I get 3 projects that don't work. I am open to restructuring the project but haven't found any documentation on how this should be done.
Is there a way to make the 3 projects that Eclipse exports work together? Am I better off restructuring things and if so is documentation for how this should be done?
Update
I have uploaded the entire project to GitHub https://github.com/respectTheCode/android-studio-library-example
Update 1
Based the suggestions from Padma Kumar this is what I have tried.
- Create a new Project called
MyApp
- Click
File > New Module
, chooseAndroid Library
and name itMyLib
- Click
Build > Make Project
The build fails with this error
Module "MyLib" was fully rebuilt due to project configuration/dependencies changes
Compilation completed with 1 error and 0 warnings in 19 sec
1 error
0 warnings
/.../MyApp/MyLib/build/bundles/debug/AndroidManifest.xml
Gradle: <manifest> does not have package attribute.
I then added a package
attribute to the manifest making it
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.mylib" >
After building I get this error
Module "MyApp" was fully rebuilt due to project configuration/dependencies changes
Compilation completed with 2 errors and 0 warnings in 13 sec
2 errors
0 warnings
/.../MyApp/MyLib/src/main/java/com/example/mylib/MainActivity.java
Gradle: package R does not exist
Gradle: package R does not exist
Adding dependency doesn't seem to have any impact on the error. Continuing from above
- Click
File > Project Structure > Modules > MyApp-MyApp
- Switch to
Dependencies
Tab - Click
+ > Module Dependency
and pickMyLib
- Click
Apply
andOK
- Click
Build > Make Project
Update 2
Based the suggestions from Ethan this is where we get
The 2 sub project build.gradle
seem to have all of the correct parts and the only difference is the plugin line bellow is the MyApp/build.gradle
.
buildscript {
repositories {
maven { url 'http://repo1.maven.org/maven2' }
}
dependencies {
classpath 'com.android.tools.build:gradle:0.4'
}
}
apply plugin: 'android'
dependencies {
compile files('libs/android-support-v4.jar')
}
android {
compileSdkVersion 17
buildToolsVersion "17.0.0"
defaultConfig {
minSdkVersion 7
targetSdkVersion 16
}
}
The root project build.gradle
was empty so I added the two projects like this
dependencies {
compile project(":MyLib")
compile project(":MyApp")
}
I now get this error when building
Gradle:
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/kevin/GitHub/AppPress/MyApp/build.gradle' line: 2
* What went wrong:
A problem occurred evaluating root project 'MyApp'.
> Could not find method compile() for arguments [project ':MyLib'] on root project 'MyApp'.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
Update 3
Big thanks Ethan for solving this.
- Add
compile project(':SubProjects:MyLib')
to theMyLib/build.gradle
- Remove
compile files('libs/android-support-v4.jar')
from theMyLib/build.gradle
- Close project and Import the root project from gradle
Update 4
As of 0.1.2 you can now include compile "com.android.support:support-v4:13.0.0"
instead of compile files('libs/android-support-v4.jar')
. Since it is coming from mavin now you can include this in multiple projects without problems.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.4.2'
}
}
apply plugin: 'android'
dependencies {
compile "com.android.support:support-v4:13.0.0"
compile project(':SubProjects:MyLib')
}
Update 5
As of 0.1.3 there is now a "Sync Project" button in the toolbar. You can click that instead of reimporting your project after making changes to .gradle
files.
Android Solutions
Solution 1 - Android
Note: This answer is a pure Gradle answer, I use this in IntelliJ on a regular basis but I don't know how the integration is with Android Studio. I am a believer in knowing what is going on for me, so this is how I use Gradle and Android.
TL;DR Full Example - https://github.com/ethankhall/driving-time-tracker/
Disclaimer: This is a project I am/was working on.
Gradle has a defined structure ( that you can change, link at the bottom tells you how ) that is very similar to Maven if you have ever used it.
Project Root
+-- src
| +-- main (your project)
| | +-- java (where your java code goes)
| | +-- res (where your res go)
| | +-- assets (where your assets go)
| | \-- AndroidManifest.xml
| \-- instrumentTest (test project)
| \-- java (where your java code goes)
+-- build.gradle
\-- settings.gradle
If you only have the one project, the settings.gradle file isn't needed. However you want to add more projects, so we need it.
Now let's take a peek at that build.gradle file. You are going to need this in it (to add the android tools)
build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.3'
}
}
Now we need to tell Gradle about some of the Android parts. It's pretty simple. A basic one (that works in most of my cases) looks like the following. I have a comment in this block, it will allow me to specify the version name and code when generating the APK.
build.gradle
apply plugin: "android"
android {
compileSdkVersion 17
/*
defaultConfig {
versionCode = 1
versionName = "0.0.0"
}
*/
}
Something we are going to want to add, to help out anyone that hasn't seen the light of Gradle yet, a way for them to use the project without installing it.
build.gradle
task wrapper(type: org.gradle.api.tasks.wrapper.Wrapper) {
gradleVersion = '1.4'
}
So now we have one project to build. Now we are going to add the others. I put them in a directory, maybe call it deps, or subProjects. It doesn't really matter, but you will need to know where you put it. To tell Gradle where the projects are you are going to need to add them to the settings.gradle.
Directory Structure:
Project Root
+-- src (see above)
+-- subProjects (where projects are held)
| +-- reallyCoolProject1 (your first included project)
| \-- See project structure for a normal app
| \-- reallyCoolProject2 (your second included project)
| \-- See project structure for a normal app
+-- build.gradle
\-- settings.gradle
settings.gradle:
include ':subProjects:reallyCoolProject1'
include ':subProjects:reallyCoolProject2'
The last thing you should make sure of is the subProjects/reallyCoolProject1/build.gradle has apply plugin: "android-library"
instead of apply plugin: "android"
.
Like every Gradle project (and Maven) we now need to tell the root project about it's dependency. This can also include any normal Java dependencies that you want.
build.gradle
dependencies{
compile 'com.fasterxml.jackson.core:jackson-core:2.1.4'
compile 'com.fasterxml.jackson.core:jackson-databind:2.1.4'
compile project(":subProjects:reallyCoolProject1")
compile project(':subProjects:reallyCoolProject2')
}
I know this seems like a lot of steps, but they are pretty easy once you do it once or twice. This way will also allow you to build on a CI server assuming you have the Android SDK installed there.
NDK Side Note: If you are going to use the NDK you are going to need something like below. Example build.gradle file can be found here: https://gist.github.com/khernyo/4226923
build.gradle
task copyNativeLibs(type: Copy) {
from fileTree(dir: 'libs', include: '**/*.so' ) into 'build/native-libs'
}
tasks.withType(Compile) { compileTask -> compileTask.dependsOn copyNativeLibs }
clean.dependsOn 'cleanCopyNativeLibs'
tasks.withType(com.android.build.gradle.tasks.PackageApplication) { pkgTask ->
pkgTask.jniDir new File('build/native-libs')
}
Sources:
Solution 2 - Android
I just had a very similar issues with gradle builds / adding .jar library. I got it working by a combination of :
- Moving the libs folder up to the root of the project (same directory as 'src'), and adding the library to this folder in finder (using Mac OS X)
- In Android Studio, Right-clicking on the folder to add as library
- Editing the dependencies in the build.gradle file, adding
compile fileTree(dir: 'libs', include: '*.jar')}
BUT more importantly and annoyingly, only hours after I get it working, Android Studio have just released 0.3.7, which claims to have solved a lot of gradle issues such as adding .jar libraries
http://tools.android.com/recent
Hope this helps people!
Solution 3 - Android
Here is my solution for mac users I think it work for window also:
First go to your Android Studio toolbar
Build > Make Project (while you guys are online let it to download the files) and then
Build > Compile Module "your app name is shown here" (still online let the files are
download and finish) and then
Run your app that is done it will launch your emulator and configure it then run it!
That is it!!! Happy Coding guys!!!!!!!
Solution 4 - Android
Gradle Build Tools 2.2.0+ - Everything just works
This is the correct way to do it
In trying to avoid experimental and frankly fed up with the NDK and all its hackery I am happy that 2.2.x of the Gradle Build Tools came out and now it just works. The key is the externalNativeBuild
and pointing ndkBuild
path argument at an Android.mk
or change ndkBuild
to cmake
and point the path argument at a CMakeLists.txt
build script.
android {
compileSdkVersion 19
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 19
targetSdkVersion 19
ndk {
abiFilters 'armeabi', 'armeabi-v7a', 'x86'
}
externalNativeBuild {
cmake {
cppFlags '-std=c++11'
arguments '-DANDROID_TOOLCHAIN=clang',
'-DANDROID_PLATFORM=android-19',
'-DANDROID_STL=gnustl_static',
'-DANDROID_ARM_NEON=TRUE',
'-DANDROID_CPP_FEATURES=exceptions rtti'
}
}
}
externalNativeBuild {
cmake {
path 'src/main/jni/CMakeLists.txt'
}
//ndkBuild {
// path 'src/main/jni/Android.mk'
//}
}
}
For much more detail check Google's page on adding native code.
After this is setup correctly you can ./gradlew installDebug
and off you go. You will also need to be aware that the NDK is moving to clang since gcc is now deprecated in the Android NDK.