Android studio doesn't recognise source folders - android

I'm using a standard Android Studio directory structure and I created different build types:
buildTypes {
debug {
runProguard false
packageNameSuffix ".debug"
signingConfig signingConfigs.debug
}
preview.initWith(buildTypes.debug)
preview {
packageNameSuffix ".preview"
}
release {
runProguard false
signingConfig signingConfigs.release
}
}
everything compiles fine, but AS doesnt recognize all of the source folders.
Only folders under main and debug are marked as source, folders under preview and release are displayed as normal folders
In effect there is no error checking in those folders
I checked the .iml file and sourceFolder tags were not added.
If I edit the project iml file manually adding the lines:
<sourceFolder url="file://$MODULE_DIR$/src/preview/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/preview/res" type="java-resource" />
It seems to work fine.
...until I sync with my gradle file - which removes the above lines.
Is this a bug in gradle plugin, or am I doing something wrong?

You have to switch it in the build variants list, then AS will pick up the appropriate source sets.

First, try re-importing the project. Delete all of your build directories, .iml files and the .idea folder. Then import the project.
If that doesn't work then you can try this to "force it".
Checkout this response from Bernd Bergler. Note that this is a hack and ideally isn't necessary
Here's a slightly modified version of his code.
task addPreview {
def src = ['src/preview/java']
def file = file("app.iml")
doLast {
try {
def parsedXml = (new XmlParser()).parse(file)
def node = parsedXml.component[1].content[0]
src.each {
def path = 'file://$MODULE_DIR$/' + "${it}"
def set = node.find { it.#url == path }
if (set == null) {
new Node(node, 'sourceFolder', ['url': 'file://$MODULE_DIR$/' + "${it}", 'isTestSource': "false"])
def writer = new StringWriter()
new XmlNodePrinter(new PrintWriter(writer)).print(parsedXml)
file.text = writer.toString()
}
}
} catch (FileNotFoundException e) {
// nop, iml not found
}
}
}
// always do the addPreview on prebuild
gradle.projectsEvaluated {
preBuild.dependsOn(addPreview)
}
Simply drop that in your build.gradle file outside of the android section.
Description from this source:
Android Studio automatically generates .iml project files from gradle
build files. This task edits the Android Studio project file app.iml
and adds the test directory. The changes are lost whenever Android
Studio rescans the gradle files, but right after that it runs a build
and the task is hooked into that, so it’s all good. This version has a
couple of tweaks, such as adding the new task into the normal build
cycle a bit differently, and gracefully handling the absence of the
.iml file.
This has worked to an extent for me: The IDE recognizes it as a src tree now but doesn't want to link it with any other src trees.

In my case only File -> Invalidate Caches / Restart have helped me, so if solutions above does not work for you - try this.

Add this to your module's build.gradle file:
sourceSets {
main.java.srcDirs += 'src/preview/java'
main.java.srcDirs += 'src/release/java'
}

Related

How to encrypt passwords in build.gradle with Android 3.3? Getting "Cannot resolve symbol" in IDE

Since update to Android Studio 3.3 we get a weird warning with some legacy code about encrypted gradle parameters.
In build.gradle we have this line:
apply from: "encryption.gradle"
In encryption.gradle we have this content:
afterEvaluate {
android.applicationVariants.all { variant ->
def pwd = "";
variant.productFlavors.each { flavor ->
if (flavor.ext.has("pwd1")) {
pwd = flavor.ext.pwd1
}
}
if (pwd.isEmpty() && variant.buildType.ext.has("pwd2")) {
pwd = variant.buildType.ext.pwd2
}
variant.resValue 'string', 'pwd', encryptPassword(pwd, variant.signingConfig, variant.applicationId)
}
}
def String encryptPassword(String password, signingConfig, String applicationId) {
...
}
In the code we use it like this:
getString(R.string.pwd)
And since the AS update we get the following error:
Cannot resolve symbol 'pwd'
When compiling/building the project everything runs fine because it can find the parameter. But when working in the IDE, all files that try to use R.string.pwd are marked red and show the error message, which is pretty annoying.
Any way to make this go away easily? SuppressWarnings("all") and SuppressLint("all") are not helping.
Is afterEvaluate the right place to do this or would it be better somehow in the defaultConfig section of build.gradle?
Even i was facing similar issues. so i reverted my gradle to 3.2.1 and it works as expected, it might be a technical glitch/issue with gradle 3.3
While i was on gradle 3.3 i tried invalidating cache for android studio, restarted it etc, but nothing solved the issue.

Gradle/Jenkins : Create a gradle file to direct to sub projects

I've got a directory with three android projects in it.
The MainDir looks like that :
/.gradle
/.git
/project1
/project2
/project3
.gitignore
.Jenkinsfile
.README.md
In jenkins I can't run a shell script during the build that launchs gradle tasks for eauch of those projects because he doesn't know these are projects (he says "no sub-project").
In a project dir it looks like :
/.gradle
/app
/build
/gradle
.gitignore
.build.gradle
.gradle.properties
.gradlew
Is there a way to make jenkins understand these are three projects he can launch gradle taks in ? Like creating a build.gradle file in the main directory doing that ?
Or should I just create 3 Jenkins items?
You could make three builds in jenkins but unless there is a need to build the libs seperately then it might just end up being extra effort. Sounds like what you really want is a multi project build [1]. A simple example could sit at the folder above your lib projects as two files, build.gradle and settings.gradle
The settings.gradle will define what projects are included in your build's scope.
For example given your project1, project2 and project3 example your settings.gradle may look like this.
rootProject.name = 'myRootProjectName'
// note the name is not required to match the actual path
include ":project1"
// but if the name is not the same as the path then we can just
// let gradle know where the project is expected
project(":project1").projectDir = new File(settingsDir, "pathToProject1")
include ":project2"
project(":project2").projectDir = new File(settingsDir, "pathToProject2")
include ":project3"
project(":project3").projectDir = new File(settingsDir, "pathToProject3")
//##### below would be instead of the code above, same thing just manual
// project setup vs letting gradle find the subprojects
// note sometimes you have lots of subprojects in that case it's sometimes
// easier to just use a little logic for finding and setting up the subprojects.
// don't use the code above ##### and below only use one or the other
// or you will have errors. The method below is the most scaleable since
// adding projects requires zero modifications to the root project
rootProject.name = 'myRootProjectName'
// set up a couple file filters to find the dirs we consider subprojects
FileFilter projectFilter = { File pathname ->
FileFilter gradleProjectFilter = { File file -> file.name == 'build.gradle' }
// add this folder if is a directory and that directory contains a build.gradle file
// here note `File#listFiles` is true if it's `size() > 0` due to
// groovy's concept of truth (details: http://groovy-lang.org/semantics.html#Groovy-Truth)
return pathname.isDirectory() && pathname.listFiles(gradleProjectFilter)
}
settingsDir.listFiles(projectFilter).each { dir ->
include ":$dir.name"
project(":$dir.name").projectDir = dir
}
now running gradle projects task should show the three submodules.
As for your build.gradle file you could specify some common properties to all the modules if needed or just leave the file blank, it must exist but can be empty. If you wanted to share some configurations then you might set up the build.gradle with something like this.
project.subprojects { Project subproject ->
// anything that is defined here will be executed before the subproject's build.gradle file
subproject.buildscript {
repositories {
jcenter()
// your private maven repo if needed
maven { url 'http://1.2.3.4:8081/nexus/content/repositories/release' }
}
dependencies {
// some plugin that is now available to be applied in any subproject
classpath 'my.sweet.gradle:plugin:0.1'
}
}
subproject.afterEvaluate {
// this block is executed after the subproject's build.gradle file
if (project.tasks.withType(org.gradle.jvm.tasks.Jar)) {
// for example you might want to set the manifest for each subproject
manifest {
attributes 'Implementation-Title': "Lib $subproject.name",
'Implementation-Version': version
}
}
}
}
[1] https://docs.gradle.org/current/userguide/multi_project_builds.html

Switch GCM Client on Development and Production

Just implement the new GCM. For official document,
Copy the google-services.json file you just downloaded into the app/ or mobile/ directory of your Android Studio project.
Anyone know how to setup gradle to switch development and production to use different google-services.json?
I have just answered a similar question here for different productFlavors.
In your case it's debug/production. I don't know why you need to switch between production and debug but i think you can do the same as what I proposed for flavors.
Create two extra folders src/release and src/debug , in each of the folders you put the corresponding google-services.json , so you will have: src/release/google-services.json and src/debug/google-services.json
Now in gradle add this :
android {
// set build config here to get the right gcm configuration.
//def myBuildConfig = "release"
def myBuildConfig = "debug"
// this will copy the right google-services.json file to app/ directory.
if (myBuildConfig.equals("release")) {
println "--> release copy!"
copy {
from 'src/release/'
include '*.json'
into '.'
}
} else {
println "--> debug copy!"
copy {
from 'src/debug/'
include '*.json'
into '.'
}
}
// other stuff
}

Exclude assets for release build type

I'm importing an android library in an application built with gradle, like that:
dependencies {
compile 'com.example:great-lib:0.1-SNAPSHOT'
}
This library contains only assets, js, css and images to be used in a webview, with a layout like that:
assets/
|-> great.css
|-> great.min.js
|-> great.min.js.map
|-> js/
| |-> plop.js
| |-> foo.js
| ...
|-> img/
| ...
The js folder contains source files (to be used with source maps). I would like to include it and the .map file for the debug builds, and have only the minified js in release builds, but I can't find a way to do that.
So far I've tried : 
android {
// this doesn't exclude anything
packageOptions {
exclude 'assets/js'
}
buildTypes {
release {
// this does exclude the js folder, but in both release and debug
aaptOptions {
ignoreAssetsPattern "!js"
}
}
}
}
Any idea if what I want is possible to achieve, and if so how?
(I've also thought of publishing two versions of the library (great-lib and great-lib-debug), and have the dependency in debugCompile and releaseCompile, but I'd prefer avoiding that and publishing a single version)
I had success with this approach (updated 2019-5-13 for TaskProvider support; see edit history for older versions):
android {
⋮
applicationVariants.all { variant ->
if (variant.buildType.name == 'release') {
variant.mergeAssetsProvider.configure {
doLast {
delete(fileTree(dir: outputDir, includes: ['**/js', '**/*.js.map']))
}
}
}
}
⋮
}
This should address the issues with #Xavier's answer:
The deletion is done as part of the variant's mergeAssets task so the deletion is reflected in the task's output and up-to-date checking should be unaffected.
The paths are calculated without magic strings. You may need to adjust the include patterns in case my example is too permissive.
The variant is being selected by the buildType name, which is less problematic than matching the entire variant name (though it is still stringly typed).
Note that this approach also works for res files rather than assets: just replace mergeAssets with mergeResources.
Other answers mentioning packagingOptions and aaptOptions are barking up the wrong tree, as these are scoped to all variants (they are defined in the android scope, not buildType or productFlavor).
I ended up doing the following:
android.applicationVariants.all { variant ->
if (variant.name.contains('Release')) {
// exclude source and sourcemap from release builds
def noJsSourceTask = task("delete${variant.name}JsSource", type: Delete) {
delete "${buildDir}/intermediates/assets/${variant.dirName}/js"
delete "${buildDir}/intermediates/assets/${variant.dirName}/great.min.js.map"
}
variant.mergeAssets.finalizedBy noCeJsSourceTask
}
}
It works ok, but there are a few things I don't really like:
I'm touching at the files produced by a task after it is done (the finalizedBy), so it doesn't work well with "up-to-date" checking. But it's only for release builds, I'm doing debug ones more often
the path of the files to delete is manually built. I'm not sure if it's generic enough to be reused in other projects as-is
I'm selecting the variants based on their name. I would have liked something more structured.
Gradle provides "aaptOptions, ignoreAssetsPattern" to filter/exclude assets folders and files from release or debug build.
Example for debug build (js folder and great.css files):
debug {
aaptOptions {
ignoreAssetsPattern '!js:!great.css:'
}
}
Example for release build (js folder and great.css files):
release {
aaptOptions {
ignoreAssetsPattern '!js:!great.css:'
}
}
I think you can use proguard. Proguard is include with android studio,obfuscate code, and remove not used classes, and if you want remove all resources that app not used. Only put in your build.gradle this:
release {
minifyEnabled true //remove classes, obfuscate code and zipalign
shrinkResources true //remove resources
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//autogenerated files
}
This is link information about that:
http://developer.android.com/tools/help/proguard.html
You can personalize, exclude particular files or ignore particular files
It's not possible through a filter.
You could have 2 assets folders though. a main one (src/main/assets) used for both debug and release and one (src/debug/assets) used only for the debug build.
source

Gradle using two property files one for debug and release

I am trying to migrate an android project from maven to gradle.
In maven I have two profiles (dev and prod), dev profile uses a dev.properties file to set up some properties and prod uses prod.properties.
I want to be able to tell gradle to use dev.properties for debug build and prod.properties for release build.
More specifically all I need to do is rename the file to constants.properties
How can I achieve this?
Assuming you already have a way to distinguish between dev vs prod, you can rename the file in Groovy with something like this:
def dev = true // set to true or false
def propFile
if (dev) {
propFile = file("dev.properties")
} else {
propFile = file("prod.properties")
}
propFile.renameTo("constants.properties")

Categories

Resources