custom framework library(classes-full-debug.jar) in android-studio [duplicate] - android

First Here's my Java Build Path in Eclipse:
These four jars 'common.jar,core.jar, framework.jar,layout.jar' are packaged from Android source code, which contains some classes that can't be publicly used by developer.They needn't to be exported because they are for cheat compiler. In Eclipse everything is OK.
Now I'm trying to import my project to Android-Studio with gradle.I've add the jars to dependencies,However I can't change the compile order of my jars and android jar. I can't put these jars in front of android jar.I'm not familiar with gradle, now the compiler can't find classes in these jars. Any help will be appreciated!
Here's my build.gradle:
apply plugin: 'android'
dependencies {
compile files('jars/common.jar')
compile files('jars/core.jar')
compile files('jars/framework.jar')
compile files('jars/layout.jar')
compile fileTree(dir: 'libs', include: '*.jar')
compile files('jars/animation_nineoldandroids_src.jar')
compile files('jars/json_simple_src.jar')
compile files('jars/jsoup-1.7.2-sources.jar')
}
android {
compileSdkVersion 17
buildToolsVersion "21.1.1"
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
// Move the tests to tests/java, tests/res, etc...
instrumentTest.setRoot('tests')
// Move the build types to build-types/<type>
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
// This moves them out of them default location under src/<type>/... which would
// conflict with src/ being used by the main source set.
// Adding new build types or product flavors should be accompanied
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}

You can't do what you want in Gradle(*), at least for the foreseeable future at the time this is written. A few problems are getting in your way:
Gradle doesn't do ordering of dependencies in the build classpath the way that Eclipse does, which is what you were doing to put your classes ahead of android.jar. Gradle has the philosophy that you should be explicit about dependencies in your build so what's going on is understandable and repeatable; systems that rely on classpath ordering tend to be subtle and fragile. So what you would need to do is to tell Gradle that your project depends on your custom classes and not android.jar, but the plugin's DSL doesn't give you the means to do that. There's some discussion at http://forums.gradle.org/gradle/topics/classpath_ordering_again and http://www.gradle.org/docs/current/userguide/dependency_management.html
Another way of looking at it is a reference to android.jar is hardcoded into the Android Gradle plugin, so you can't get at that dependency and replace it with something else.
(*) Having said all that, nothing is impossible -- you could make it work, but you're going to have to hack something together, so it's going to be more trouble-prone than the Eclipse approach, and tougher to maintain in the face of SDK and tooling updates. And when something goes wrong you'll be on your own.
You could assemble your own custom SDK with your own android.jar.
You could hack the Android Gradle plugin. This approach would definitely be tough -- the learning curve there is pretty steep, and the code is under heavy development, which would be a maintenance burden as you try to stay up-to-date.
I hesitate to offer much more insight into either of those approaches, partly because I don't know a lot about it and could pretty easily give you bad advice, and partly because I don't want inexperienced developers seeing this to think it's an awesome thing to do. But if you figure it out, it would be very much worthy of writing up, because I've seen this sort of question before, so you're not the only one.

Following script works for me:
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:/mylib.jar')
}
}
}

I solved the issue from this post to build application with system libraries :
Supposing you have added system libraries like libframework.jar and libcore.jar in app/libs :
add Xbootclasspath to your top level build.gradle :
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:app/libs/libframework.jar:app/libs/libcore.jar')
}
}
}
in you app build.gradle, use provided :
dependencies {
provided fileTree(include: ['*.jar'], dir: 'libs')
}
in the same app build.gradle, add a task to put <orderEntry> referring to Android API 25 Platform in the last position in app.iml, this way gradle will take into account your system libs first and Android SDK in last resort :
preBuild {
doLast {
def imlFile = file(project.name + ".iml")
println 'Change ' + project.name + '.iml order'
try {
def parsedXml = (new XmlParser()).parse(imlFile)
def jdkNode = parsedXml.component[1].orderEntry.find { it.'#type' == 'jdk' }
parsedXml.component[1].remove(jdkNode)
def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
} catch (FileNotFoundException e) {
// nop, iml not found
}
}
}

A updated and somewhat more future-proof answer (since bootclasspath compilerargs have been changing in more recent JDKs):
Supposing you have taken system libraries like framework.jar and libcore.jar from aosp intermediates (generated when building aosp) and added them into a folder (such as system_libs) in your project, add the libraries to the compile classpath in build.gradle:
dependencies {
compileOnly fileTree(dir: 'system_libs', include: ['*.jar'])
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.bootstrapClasspath = files(
new File("./system_libs/framework.jar").path,
new File("./system_libs/libcore.jar").path
)
}
}
Add a task to put referring to the Android API Platform in the last position in app.iml, this way gradle will take into account your system libs first and Android SDK last:
preBuild {
doLast {
def imlFile = file(project.name + ".iml")
println 'Change ' + project.name + '.iml order'
try {
def parsedXml = (new XmlParser()).parse(imlFile)
def jdkNode = parsedXml.component[1].orderEntry.find { it.'#type' == 'jdk' }
parsedXml.component[1].remove(jdkNode)
def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
} catch (FileNotFoundException e) {
// nop, iml not found
}
}
}
Based on #Bertrand's answer

You can do this automatically, just like in Eclipse:
File > Project structure... > (select app in Modules) > (go to Dependencies tab) > reposition with arrows on the right
Another way is to edit the [AppName].iml file in the folder your application is in. What you want to change are the tags at the end of the file. However, Android Studio will rearrange those each time you clean or re-open the project.

Make dir (ex: exlibs)
Copy your jar file to exlibs dir
..
dependencies {
provided files("$projectDir/exlibs/yourlib.jar")
}

I use the following scenario, the perfect solution!
Add your XXX.jar to Library
Then change the "Scope" to "Provided"
Find this in your project .gradle:
allprojects {
repositories {
jcenter()
}
}
Change it to:
allprojects {
repositories {
jcenter()
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:app\\libs\\XXX.jar')
}
}
}
In YourApplicationName.iml file, adjust the XXX.jar to top, like this
so, it's ok!

Update app/app.iml file order as
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="common" level="project" />
<orderEntry type="library" exported="" name="framework" level="project" />
<orderEntry type="library" exported="" name="layout" level="project" />
<orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />

The simplest solution for me was to replace android.jar with one with the hidden API included. Get android.jar from this project library that provides access to Android hidden API and internal resources and place it to your ASDK platforms folder, to the platform you're compiling against (compileSdkVersion).
I'm sure it works with Eclipse as well ))

That's really easy!
And you DO NOT need to modify build.gradle in your project any more!
Step 1:
Backup your original android.jar in Android-SDK directory (e.g. your app compileSdkVersion=30 in build.gradle, and the corresponding path is "~/Library/Android/sdk/platforms/android-30" on the MacOS).
Step 2:
Rename your custom framework.jar(*) to "android.jar" and copy it to your Android-SDK directory, against the original one.
Step 3:
Sync gradle if needed, then you can use the #hide function what you want without red error reported.
(*) If you would not like to take your time to clone AOSP and compile it, you'd better download it on Github: https://github.com/anggrayudi/android-hidden-api
Good luck~

seems the*.impl file path had changed, you need to change
def imlFile = file(project.name + ".iml")
with
def imlFile = file(".." + File.separator + ".idea" + File.separator + "modules" + File.separator + project.name + File.separator + rootProject.name + "." + project.name + ".iml")

Related

How to put my libraries in front of android.jar by editing build.gradle in Android-Studio

First Here's my Java Build Path in Eclipse:
These four jars 'common.jar,core.jar, framework.jar,layout.jar' are packaged from Android source code, which contains some classes that can't be publicly used by developer.They needn't to be exported because they are for cheat compiler. In Eclipse everything is OK.
Now I'm trying to import my project to Android-Studio with gradle.I've add the jars to dependencies,However I can't change the compile order of my jars and android jar. I can't put these jars in front of android jar.I'm not familiar with gradle, now the compiler can't find classes in these jars. Any help will be appreciated!
Here's my build.gradle:
apply plugin: 'android'
dependencies {
compile files('jars/common.jar')
compile files('jars/core.jar')
compile files('jars/framework.jar')
compile files('jars/layout.jar')
compile fileTree(dir: 'libs', include: '*.jar')
compile files('jars/animation_nineoldandroids_src.jar')
compile files('jars/json_simple_src.jar')
compile files('jars/jsoup-1.7.2-sources.jar')
}
android {
compileSdkVersion 17
buildToolsVersion "21.1.1"
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
// Move the tests to tests/java, tests/res, etc...
instrumentTest.setRoot('tests')
// Move the build types to build-types/<type>
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
// This moves them out of them default location under src/<type>/... which would
// conflict with src/ being used by the main source set.
// Adding new build types or product flavors should be accompanied
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}
You can't do what you want in Gradle(*), at least for the foreseeable future at the time this is written. A few problems are getting in your way:
Gradle doesn't do ordering of dependencies in the build classpath the way that Eclipse does, which is what you were doing to put your classes ahead of android.jar. Gradle has the philosophy that you should be explicit about dependencies in your build so what's going on is understandable and repeatable; systems that rely on classpath ordering tend to be subtle and fragile. So what you would need to do is to tell Gradle that your project depends on your custom classes and not android.jar, but the plugin's DSL doesn't give you the means to do that. There's some discussion at http://forums.gradle.org/gradle/topics/classpath_ordering_again and http://www.gradle.org/docs/current/userguide/dependency_management.html
Another way of looking at it is a reference to android.jar is hardcoded into the Android Gradle plugin, so you can't get at that dependency and replace it with something else.
(*) Having said all that, nothing is impossible -- you could make it work, but you're going to have to hack something together, so it's going to be more trouble-prone than the Eclipse approach, and tougher to maintain in the face of SDK and tooling updates. And when something goes wrong you'll be on your own.
You could assemble your own custom SDK with your own android.jar.
You could hack the Android Gradle plugin. This approach would definitely be tough -- the learning curve there is pretty steep, and the code is under heavy development, which would be a maintenance burden as you try to stay up-to-date.
I hesitate to offer much more insight into either of those approaches, partly because I don't know a lot about it and could pretty easily give you bad advice, and partly because I don't want inexperienced developers seeing this to think it's an awesome thing to do. But if you figure it out, it would be very much worthy of writing up, because I've seen this sort of question before, so you're not the only one.
Following script works for me:
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:/mylib.jar')
}
}
}
I solved the issue from this post to build application with system libraries :
Supposing you have added system libraries like libframework.jar and libcore.jar in app/libs :
add Xbootclasspath to your top level build.gradle :
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:app/libs/libframework.jar:app/libs/libcore.jar')
}
}
}
in you app build.gradle, use provided :
dependencies {
provided fileTree(include: ['*.jar'], dir: 'libs')
}
in the same app build.gradle, add a task to put <orderEntry> referring to Android API 25 Platform in the last position in app.iml, this way gradle will take into account your system libs first and Android SDK in last resort :
preBuild {
doLast {
def imlFile = file(project.name + ".iml")
println 'Change ' + project.name + '.iml order'
try {
def parsedXml = (new XmlParser()).parse(imlFile)
def jdkNode = parsedXml.component[1].orderEntry.find { it.'#type' == 'jdk' }
parsedXml.component[1].remove(jdkNode)
def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
} catch (FileNotFoundException e) {
// nop, iml not found
}
}
}
A updated and somewhat more future-proof answer (since bootclasspath compilerargs have been changing in more recent JDKs):
Supposing you have taken system libraries like framework.jar and libcore.jar from aosp intermediates (generated when building aosp) and added them into a folder (such as system_libs) in your project, add the libraries to the compile classpath in build.gradle:
dependencies {
compileOnly fileTree(dir: 'system_libs', include: ['*.jar'])
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.bootstrapClasspath = files(
new File("./system_libs/framework.jar").path,
new File("./system_libs/libcore.jar").path
)
}
}
Add a task to put referring to the Android API Platform in the last position in app.iml, this way gradle will take into account your system libs first and Android SDK last:
preBuild {
doLast {
def imlFile = file(project.name + ".iml")
println 'Change ' + project.name + '.iml order'
try {
def parsedXml = (new XmlParser()).parse(imlFile)
def jdkNode = parsedXml.component[1].orderEntry.find { it.'#type' == 'jdk' }
parsedXml.component[1].remove(jdkNode)
def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
} catch (FileNotFoundException e) {
// nop, iml not found
}
}
}
Based on #Bertrand's answer
You can do this automatically, just like in Eclipse:
File > Project structure... > (select app in Modules) > (go to Dependencies tab) > reposition with arrows on the right
Another way is to edit the [AppName].iml file in the folder your application is in. What you want to change are the tags at the end of the file. However, Android Studio will rearrange those each time you clean or re-open the project.
Make dir (ex: exlibs)
Copy your jar file to exlibs dir
..
dependencies {
provided files("$projectDir/exlibs/yourlib.jar")
}
I use the following scenario, the perfect solution!
Add your XXX.jar to Library
Then change the "Scope" to "Provided"
Find this in your project .gradle:
allprojects {
repositories {
jcenter()
}
}
Change it to:
allprojects {
repositories {
jcenter()
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:app\\libs\\XXX.jar')
}
}
}
In YourApplicationName.iml file, adjust the XXX.jar to top, like this
so, it's ok!
Update app/app.iml file order as
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="common" level="project" />
<orderEntry type="library" exported="" name="framework" level="project" />
<orderEntry type="library" exported="" name="layout" level="project" />
<orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />
The simplest solution for me was to replace android.jar with one with the hidden API included. Get android.jar from this project library that provides access to Android hidden API and internal resources and place it to your ASDK platforms folder, to the platform you're compiling against (compileSdkVersion).
I'm sure it works with Eclipse as well ))
That's really easy!
And you DO NOT need to modify build.gradle in your project any more!
Step 1:
Backup your original android.jar in Android-SDK directory (e.g. your app compileSdkVersion=30 in build.gradle, and the corresponding path is "~/Library/Android/sdk/platforms/android-30" on the MacOS).
Step 2:
Rename your custom framework.jar(*) to "android.jar" and copy it to your Android-SDK directory, against the original one.
Step 3:
Sync gradle if needed, then you can use the #hide function what you want without red error reported.
(*) If you would not like to take your time to clone AOSP and compile it, you'd better download it on Github: https://github.com/anggrayudi/android-hidden-api
Good luck~
seems the*.impl file path had changed, you need to change
def imlFile = file(project.name + ".iml")
with
def imlFile = file(".." + File.separator + ".idea" + File.separator + "modules" + File.separator + project.name + File.separator + rootProject.name + "." + project.name + ".iml")

Android Studio "cannot resolve symbol String"

I have a small project that was started in Eclipse. I then exported it to a gradle file, and imported it to AS (0.5.7).
At first, not much seemed to work as it should, but after a "build => make project", I didn't seem to get any highlighted errors or so.
So I tried to run the app to an emulated device. Well, the device never launched, and now I get red squiggly lines under mentions of "String", "ArrayList" etc, saying it "cannot resolve the symbol".
What the f?
I have tried cleaning and rebuilding, as well as "sync project with gradle files".
Where do I go from here? I want to get going with developing in AS so bad!
edit: Screenshot of project setup: http://i.imgur.com/ycNyPaT.png
Contents of build.gradle:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.+'
}
}
apply plugin: 'android'
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
}
android {
compileSdkVersion 19
buildToolsVersion "19.0.1"
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
// Move the tests to tests/java, tests/res, etc...
instrumentTest.setRoot('tests')
// Move the build types to build-types/<type>
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
// This moves them out of them default location under src/<type>/... which would
// conflict with src/ being used by the main source set.
// Adding new build types or product flavors should be accompanied
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}
There is simpler and I think more correct way:
Just select menu item 'File/Invalidate Caches/Restart...'
For me this successfully resolved the issue (was caused by surprising power off of PC)
So project arrangement should be as follows:
create app folder within your project.
within app folder make following folders: libs and src
inside src create main folder
inside main create java and assets
move contents of old src to java
move contents of old libs to libs
move res folder to src
move AndroidManifest.xml to src
move assets folder into src
create build.gradle inside app folder with following content:
apply plugin: 'android'
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
}
android {
compileSdkVersion 19
buildToolsVersion "19.0.1"
}
create settings.gradle in project root with following content:
include 'app'
build.gradle in root should have following structure:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.+'
}
}
Android Studio 4.2.1 with Gradle 7.0.2.
Just had this problem with a module in my project. Basically many fundamental symbols like String, #Override there are not resolved. Non of the syncing or deleting cache etc helped me. The project builds without problem though, and after a successful build, the problem remained.
It turns out the issue relates to the line in the build.gradle file of the module:
apply plugin: 'java-library'
I had it there for ages and I haven't opened the module in a long time, so probably since some newer version of Gradle it's not accepted.
So the solution for me is to change the line to:
apply plugin: 'com.android.library'
Just writing this for people like me, who also landed here through googling this error.
What actually solved it for current Android Studio 3.1.+ was this
You just need to sync the project as you have opened an external project from a zip file in the android studio.
After you sync the project, you will see folders like Java,res folder,etc, instead of these not useful folders. And also, all the errors will be gone too.
When you open the external project, it will show like this.
https://photos.app.goo.gl/BFa113X9DWH8eNDt7
Then you click on the install, it will install the required components required for the project and then it will sync the project. After syncing, the Gradle will be build and your project is ready to run.
Remove the following line from the file that reported with the error if there is.
import static com.google.android.gms.internal.a.R;
try deleting [project]/[module]/build folder.
and then rebuild the project from menu->build->rebuild project
thats what worked for me.

Migrating from Eclipse to Android-Studio (gradle)

I'm trying to migrate my applications to use gradle, but I'm facing some problems including library projects.
My project tree is this:
My projects root
- MyLib1
-- res
-- src
-- libs
- MyLib2
-- res
-- src
-- libs
- MyLib3
-- res
-- src
-- libs
- MyAppBase
-- res
-- src
-- libs
- MyApp - full version
-- res
-- src
-- libs
- MyAppFree - free version
-- res
-- src
-- libs
With Eclipse I had the following dependencies
MyAppBase depends on:
-MyLib1
-MyLib2
-MyLib3
MyApp depends on:
-MyAppBase
-MyLib1
-MyLib2
-MyLib3
MyAppFree depends on:
-MyAppBase
-MyLib1
-MyLib2
-MyLib3
This organization worked well within Eclipse, but now with Android-Studio and gradle I'm having problems.
I've got the following build.gradle file:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.7.+'
}
}
apply plugin: 'android'
dependencies {
//compile project('../MyLib1') <- error
compile fileTree(dir: 'libs', include: '*.jar')
}
android {
compileSdkVersion 18
buildToolsVersion "19.0.1"
defaultConfig {
minSdkVersion 4
targetSdkVersion 14
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
// Move the tests to tests/java, tests/res, etc...
instrumentTest.setRoot('tests')
// Move the build types to build-types/<type>
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
// This moves them out of them default location under src/<type>/... which would
// conflict with src/ being used by the main source set.
// Adding new build types or product flavors should be accompanied
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}
How can I include the projects MyLib1, MyLib2, MyLib3 as a dependency so It will be compiled along with my project???
At present, all dependencies need to live under the project's root directory, so you'd need to set up your project to be rooted at the directory above MyLib1, MyLib2, MyApp, etc. This limitation will be lifted in the future; you can track its progress at https://code.google.com/p/android/issues/detail?id=56367. Your libraries would be library modules under that root, and your app(s) would be Android application modules. Each module has its own separate build.gradle file and can compile to a JAR (plain Java library), AAR (Android library, which includes code + resources), or APK (Android app).
I'm not sure if MyAppFree and MyApp are separate Eclipse projects; if they are, under Android Studio and Gradle I'd encourage you to combine them into one module that has free and paid flavors. Build flavors are designed explicitly to aid this sort of use case. See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Product-flavors for more info.
UPDATE
In the comments below it looks like you have a very large number of libraries. In that you probably don't want to build them all from source all the time, or manage a project that has dozens of modules. In that scenario, keeping modules that don't change very often as separate projects makes more sense. Those projects can compile to JAR or AAR, which brings us back to your original question of how to make those work in Android Studio.
You could copy JAR files into a libs directory under your project root and link them in. I believe there are problems trying to do the same with AAR libraries; see https://code.google.com/p/android/issues/detail?id=63908 to track the progress of that. If you don't want to maintain multiple copies of the libraries, you could either try symlinking the directories (I think that will work), or you could set up a local Maven repository and have the side projects publish their artifacts to that. I don't have links with detailed instructions on that at my fingertips; you could start with http://www.gradle.org/docs/current/userguide/publishing_maven.html.
There will be a fair learning curve to getting a local Maven repo set up, but once it's done, you'll probably find that it solves your problem pretty cleanly, and if you're in a shop with multiple developers and would like an organization-wide Maven repo, perhaps with artifacts that are published to it from a build server, you can set that up.
Maybe go to the menu "Project Structure" (Ctrl+Shift+Alt+S) and add the desired dependencies to the correct modules.
In Android Studio Your Project Structure should be looking like this
YourProjectName
-libraries
--myLib1
--myLib2
--myLib3
-MyAppBase
--build.gradle( It will have dependency of all three libraries like mentioned in last)
--src
--res
-MyApp
--src
---main
----java
----res
----Manifest
---full
----java
----res
----Manifest
---free
----java
----res
----Manifest
--build.gradle ( It will have dependency of only MyAppBase because your MyAppBase is already having dependency of all of your three libraries so no need to include them again)
Now you can have your build flavors in this last mentioned build.gradle file like
buildTypes {
debug {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
release{
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.prodSigning // write your signingConfig
}
}
productFlavors{
full {
//required configuration for full version
}
free {
//required configuration for full version
}
}
Note your directory name and product falvours name in build.gradle file must be same so while compilation (from Built Variant tab available in Left panel or command prompt) it will automatically take the code/res/manifest from respective folder.
Above configuration will give four type of following build variants
debugFull,debugFree,releaseFull,releaseFree
You Can add dependency in build.gradle of MyAppBase like
dependencies {
compile project(':libraries:myLib1')
compile project(':libraries:myLib2')
compile project(':libraries:myLib3')
}
And in the MyApp module's build.gradle file like this
dependencies {
compile project(':MyAppBase')
}

Gradle build fails looking for Google Play Services in Android Studio

I'm trying to run my project in Android Studio 0.3.6, but I always get this error :
Gradle: A problem occurred configuring root project 'myapp_android'.
> Failed to notify project evaluation listener.
> Could not resolve all dependencies for configuration ':_DebugCompile'.
> Could not resolve com.google.android.gms:play-services:3.1.36.
Required by:
:myapp_android:unspecified
> Could not GET 'http://maven.hq.couchbase.com/nexus/content/repositories/releases/com/google/android/gms/play-services/3.1.36/play-services-3.1.36.pom'. Received status code 503 from server: Service Temporarily Unavailable
Here is my complete build.gradle file :
home = System.getenv("ANDROID_HOME")
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.5.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
maven {
url "http://maven.hq.couchbase.com/nexus/content/repositories/releases/"
}
maven {
url "http://files.couchbase.com/maven2/"
}
}
dependencies {
compile 'com.android.support:support-v4:18.0.+'
compile 'com.android.support:appcompat-v7:18.0.+'
compile 'com.google.android.gms:play-services:3.1.36'
compile 'com.couchbase.cblite:CBLite:1.0.0-beta'
compile 'com.couchbase.cblite:CBLiteEktorp:1.0.0-beta'
compile 'com.couchbase.cblite:CBLiteJavascript:1.0.0-beta'
compile fileTree(dir: 'libs', include: '*.jar')
instrumentTestCompile 'com.jayway.android.robotium:robotium-solo:4.3'
}
android {
compileSdkVersion 18
buildToolsVersion "18.1"
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
instrumentTest.setRoot('tests')
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}
tasks.withType(Compile) {
options.encoding = 'UTF-8'
}
And finally, my SDK Manager :
I tried with many versions of Android Studio (0.2.8, 0.2.9, 0.2.13, 0.3.2, 0.3.6) and it's always the same. I tried changing the Play Services version, I tried changing the order of the dependencies, nothing did the trick.
Is there something not correct with my setup? I looked for answers and pretty much everything I found (build.gradle structure, SDK missing items) was already fine...
I finally found what was the problem. #gnuf pointed me in the right direction. But the problem was that Android Studio, in Project Structure | Platform Settings | Android SDK, showed the wrong SDK. It showed the SDK it used was C:/Program Files (x86)/Android/android-studio/sdk, but in fact, I discovered it tried to build with another SDK located in C:\Users\my_username\AppData\Local\Android\android-studio\sdk.
Needless to say, it didn't work. There was nothing installed in this SDK. So I copied the contents of C:/Program Files (x86)/Android/android-studio/sdk to C:\Users\my_username\AppData\Local\Android\android-studio\sdk and it worked! My first build in three weeks.
So I think it's a bug of Android Studio. If anyone runs into this problem, make sure you only have one SDK on your computer. If you have more than one, make sure they all have the required dependencies. If you can, just copy the content of the most up to date to the others.
It may be the case that the location where you've installed the SDK components is different than the one that Android Studio is using.
Can you verify that the local Maven repositories (installed by the Google Repository and Android Support Repository) are under the Android SDK that you're using in your Android Studio project?
In Android Studio, go to Project Structure | Platform Settings | Android SDK. (On my machine, the path for Android SDK Location is /opt/boxen/homebrew/Cellar/android-sdk/22.2.1 ) In that directory, ensure that the subdirectory extras/google/m2repository/com/google/android/gms/play-services/ exists.
It looks for Google dependencies like Google Play Services in your SDK extras, not in Maven repositories over the network. Install the "Google Repository" in your SDK manager and you should be good to go.

How to replace strings resources with Android Gradle

I made a new app with gradle in Android Studio, and now I need to make about 10 versions with different package names and values in resources. I made custom flavors as in example and want to replace some strings in this custom flavors with custom values. I found example like this:
filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: ['version': '2.2'])
But i don't know where to put it. As i understand i need to put it into separate task, but how to make this task called by IDE?
Also i need to replace few variables inside Java classes and Content Provider's auth, maybe i need to do this by copy files into flavor1 folder and let gradle to merge it, but it seems like wrong solution to store many copies of files with difference in one line... Maybe i need to user some other solution for all this?
Here is build.gradle:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.4.2'
}
}
apply plugin: 'android'
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
compile project(':JazzyListView')
compile project(':ABS')
compile project(':Volley')
}
android {
compileSdkVersion 17
buildToolsVersion "17.0.0"
defaultConfig {
versionCode 5
versionName "3.0"
minSdkVersion 8
targetSdkVersion 17
}
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java']
res.srcDirs = ['src/main/res']
}
}
productFlavors {
flavor1 {
packageName "com.example.flavor1"
}
flavor2 {
packageName "com.example.flavor2"
}
}
}
I had a similar problem. I wanted to add the Jenkins build number to the strings that get merged from strings.xml. Here's my solution as of Android Gradle plugin 0.12.+.
// Insert the build number into strings.xml
android.applicationVariants.all{ variant ->
variant.mergeResources.doLast{
ext.env = System.getenv()
def buildNumber = env.BUILD_NUMBER
if (buildNumber != null) {
File valuesFile = file("${buildDir}/intermediates/res/${variant.dirName}/values/values.xml")
println("Replacing revision number in " + valuesFile)
println("Build number = " + buildNumber)
String content = valuesFile.getText('UTF-8')
content = content.replaceAll(/devBuild/, buildNumber)
valuesFile.write(content, 'UTF-8')
}
}
}
You might want to hook into a different Gradle task depending on what you want to do. Take a look at the tasks that are part of the Android build to figure that out.
http://tools.android.com/tech-docs/new-build-system/user-guide
UPDATE: At some point, the Android Gradle plugin changed the way to iterate through application variants keyword from each to all. My answer has been updated to reflect the change, but try switching to each if this code doesn't print anything to the console.
I was trying to get similar functionality as Maven resource filtering.
This is what I came up with. My solution could use some changes to be more robust (i.e. pulling from a properties file, etc).
My example just shows how to replace a single value, which is all that I needed. The variables follow the ${some.property} convention. This solution also works with product flavors that have their own resource files.
import org.apache.tools.ant.filters.*
...
android.applicationVariants.all{ variant ->
// Perform resource filtering
variant.mergeResources.doLast {
filterResources(variant)
}
}
def filterResources(buildVariant) {
//Setup temp directory to filter the resources
File resFiltered = file("${buildDir}/res/all/filtered/${buildVariant.dirName}")
if(resFiltered.exists()){
resFiltered.delete()
}
//Copy and filter the resources.
copy {
from(buildVariant.processResources.resDir) {
include '**/*.xml'
//Could be improved upon to pull from a properties file, etc.
ant.properties['app.version'] = project.version
filter(ExpandProperties, project: ant.project)
}
from(buildVariant.processResources.resDir) {
exclude '**/*.xml'
}
into resFiltered
}
//Delete all the original resource files
file(buildVariant.processResources.resDir).deleteDir()
//Replace with the filtered ones.
resFiltered.renameTo(file(buildVariant.processResources.resDir))
//Delete the original 'filtered' directory
file( "${buildDir}/res/all/filtered").deleteDir()
}
Example in strings.xml
...
<string name="app_version">${app.version}</string>
...
These links may be helpful:
Using Gradle for building Android applications
Gradle Plugin User Guide
And my filter definition using regex to replace something:
from('res/') {
include '**/*.xml'
filter {
line -> line.replaceAll(/YOUR_REGEX_TO_REPLACE_SOMETHING/, 'REPLACED_RESULT_EXPRESSION')
}
}
into 'build/path/to/your/filtered/resources/'
In your "src" folder, create "flavor1" and "flavor2" folders with the same hierarchy as your "main" folder. If you have strings.xml in your main/res/values, you can do it in flavor1/res/values as well and have the replacement values in there. It may show errors in the IDE but it should still build and run.

Categories

Resources