I am trying to use Jacoco Offline instrumentation in my android project to get coverage with PowerMockito. Following is my build.gradle.
apply plugin: 'jacoco'
configurations {
jacocoAnt
jacocoRuntime
}
jacoco {
toolVersion = '0.8.8'
}
dependencies {
jacocoAnt group: 'org.jacoco', name: 'org.jacoco.ant', version: '0.8.8', classifier: 'nodeps'
jacocoRuntime group: 'org.jacoco', name: 'org.jacoco.agent', version: '0.8.8', classifier: 'runtime'
}
//def testTaskName = "test${sourceName.capitalize()}UnitTest"
project.afterEvaluate {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type -> type.name }
def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
def excludes = ['**/R.class',
......]
task "${testTaskName}Instrument"() {
ext.outputDir = buildDir.path + '/classes-instrumented'
doLast {
ant.taskdef(name: 'instrument',
classname: 'org.jacoco.ant.InstrumentTask',
classpath: configurations.jacocoAnt.asPath)
ant.instrument(destdir: outputDir) {
fileset(dir: "${project.buildDir}/intermediates/javac", excludes: excludes)
fileset(dir: "${project.buildDir}/tmp/kotlin-classes", excludes: excludes)
}
testProdUnitTest.classpath = files(outputDir) + testProdUnitTest.getClasspath()
}
}
task "${testTaskName}Report"(dependsOn: ["${testTaskName}Instrument"]) {
doLast {
ant.taskdef(name: 'report',
classname: 'org.jacoco.ant.ReportTask',
classpath: configurations.jacocoAnt.asPath)
ant.report() {
executiondata {
ant.file(file: "$buildDir.path/jacoco/testProdUnitTest.exec")
}
structure(name: 'Example') {
classfiles {
fileset(dir: "${project.buildDir}/intermediates/javac", excludes: excludes)
fileset(dir: "${project.buildDir}/tmp/kotlin-classes", excludes: excludes)
}
sourcefiles {
fileset(dir: 'src/main/java')
}
}
html(destdir: "$buildDir.path/reports/jacoco")
}
}
}
}
}
}
The instrumented class folder is created properly. But still for some classes jacoco shows 0 coverage. Please help me by pointing out what I am doing wrong here. Thanks in advance
Related
`I've installed Nativescript, and tns doctor returned no errors.
Then I installed android studio, and after that tns run returns the following error : "A problem occurred configuring root project 'core'.
compileSdkVersion is not specified. Please add it to build.gradle"
build.gradle`
import groovy.io.FileType
import groovy.json.JsonSlurper
import org.apache.commons.io.FileUtils
import javax.inject.Inject
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
import java.security.MessageDigest
import java.util.jar.JarEntry
import java.util.jar.JarFile
import static org.gradle.internal.logging.text.StyledTextOutput.Style
apply plugin: "com.android.application"
apply from: "gradle-helpers/BuildToolTask.gradle"
apply from: "gradle-helpers/CustomExecutionLogger.gradle"
apply from: "gradle-helpers/AnalyticsCollector.gradle"
def enableKotlin = (project.hasProperty("useKotlin") && project.useKotlin == "true")
if (enableKotlin) {
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
}
def onlyX86 = project.hasProperty("onlyX86")
if (onlyX86) {
outLogger.withStyle(Style.Info).println "OnlyX86 build triggered."
}
//common
def BUILD_TOOLS_PATH = "$rootDir/build-tools"
def PASSED_TYPINGS_PATH = System.getenv("TNS_TYPESCRIPT_DECLARATIONS_PATH")
def TYPINGS_PATH = "$BUILD_TOOLS_PATH/typings"
if (PASSED_TYPINGS_PATH != null) {
TYPINGS_PATH = PASSED_TYPINGS_PATH
}
def PACKAGE_JSON = "package.json"
//static binding generator
def SBG_JAVA_DEPENDENCIES = "sbg-java-dependencies.txt"
def SBG_INPUT_FILE = "sbg-input-file.txt"
def SBG_OUTPUT_FILE = "sbg-output-file.txt"
def SBG_JS_PARSED_FILES = "sbg-js-parsed-files.txt"
def SBG_BINDINGS_NAME = "sbg-bindings.txt"
def SBG_INTERFACE_NAMES = "sbg-interface-names.txt"
def INPUT_JS_DIR = "$projectDir/src/main/assets/app"
def OUTPUT_JAVA_DIR = "$projectDir/src/main/java"
//metadata generator
def MDG_OUTPUT_DIR = "mdg-output-dir.txt"
def MDG_JAVA_DEPENDENCIES = "mdg-java-dependencies.txt"
def METADATA_OUT_PATH = "$projectDir/src/main/assets/metadata"
// paths to jar libraries
def pluginsJarLibraries = new LinkedList<String>()
def allJarLibraries = new LinkedList<String>()
def computeKotlinVersion = { -> project.hasProperty("kotlinVersion") ? kotlinVersion : "${ns_default_kotlin_version}" }
def computeCompileSdkVersion = { -> project.hasProperty("compileSdk") ? compileSdk : NS_DEFAULT_COMPILE_SDK_VERSION as int }
def computeTargetSdkVersion = { -> project.hasProperty("targetSdk") ? targetSdk : NS_DEFAULT_COMPILE_SDK_VERSION as int }
def computeBuildToolsVersion = { ->
project.hasProperty("buildToolsVersion") ? buildToolsVersion : NS_DEFAULT_BUILD_TOOLS_VERSION as String
}
def enableAnalytics = (project.hasProperty("gatherAnalyticsData") && project.gatherAnalyticsData == "true")
def enableVerboseMDG = project.gradle.startParameter.logLevel.name() == 'DEBUG'
def analyticsFilePath = "$rootDir/analytics/build-statistics.json"
def analyticsCollector = project.ext.AnalyticsCollector.withOutputPath(analyticsFilePath)
if (enableAnalytics) {
analyticsCollector.markUseKotlinPropertyInApp(enableKotlin)
analyticsCollector.writeAnalyticsFile()
}
project.ext.selectedBuildType = project.hasProperty("release") ? "release" : "debug"
buildscript {
def applyBuildScriptConfigurations = { ->
def absolutePathToAppResources = getAppResourcesPath()
def pathToBuildScriptGradle = "$absolutePathToAppResources/Android/buildscript.gradle"
def buildScriptGradle = file(pathToBuildScriptGradle)
if (buildScriptGradle.exists()) {
outLogger.withStyle(Style.SuccessHeader).println "\t + applying user-defined buildscript from ${buildScriptGradle}"
apply from: pathToBuildScriptGradle, to: buildscript
}
nativescriptDependencies.each { dep ->
def pathToPluginBuildScriptGradle = "$rootDir/${dep.directory}/$PLATFORMS_ANDROID/buildscript.gradle"
def pluginBuildScriptGradle = file(pathToPluginBuildScriptGradle)
if (pluginBuildScriptGradle.exists()) {
outLogger.withStyle(Style.SuccessHeader).println "\t + applying user-defined buildscript from dependency ${pluginBuildScriptGradle}"
apply from: pathToPluginBuildScriptGradle, to: buildscript
}
}
}
applyBuildScriptConfigurations()
}
///////////// CONFIGURATIONS ////////////////
def applyBeforePluginGradleConfiguration = { ->
def appResourcesPath = getAppResourcesPath()
def pathToBeforePluginGradle = "$appResourcesPath/Android/before-plugins.gradle"
def beforePluginGradle = file(pathToBeforePluginGradle)
if (beforePluginGradle.exists()) {
outLogger.withStyle(Style.SuccessHeader).println "\t + applying user-defined configuration from ${beforePluginGradle}"
apply from: pathToBeforePluginGradle
}
}
def applyAppGradleConfiguration = { ->
def appResourcesPath = getAppResourcesPath()
def pathToAppGradle = "$appResourcesPath/Android/app.gradle"
def appGradle = file(pathToAppGradle)
if (appGradle.exists()) {
outLogger.withStyle(Style.SuccessHeader).println "\t + applying user-defined configuration from ${appGradle}"
apply from: pathToAppGradle
} else {
outLogger.withStyle(Style.Info).println "\t + couldn't load user-defined configuration from ${appGradle}. File doesn't exist."
}
}
def applyPluginGradleConfigurations = { ->
nativescriptDependencies.each { dep ->
def includeGradlePath = "$rootDir/${dep.directory}/$PLATFORMS_ANDROID/include.gradle"
if (file(includeGradlePath).exists()) {
apply from: includeGradlePath
}
}
}
def getAppIdentifier = { packageJsonMap ->
def appIdentifier = ""
if (packageJsonMap && packageJsonMap.nativescript) {
appIdentifier = packageJsonMap.nativescript.id
if (!(appIdentifier instanceof String)) {
appIdentifier = appIdentifier.android
}
}
return appIdentifier
}
def setAppIdentifier = { ->
outLogger.withStyle(Style.SuccessHeader).println "\t + setting applicationId"
File packageJsonFile = new File("$USER_PROJECT_ROOT/$PACKAGE_JSON")
if (packageJsonFile.exists()) {
def content = packageJsonFile.getText("UTF-8")
def jsonSlurper = new JsonSlurper()
def packageJsonMap = jsonSlurper.parseText(content)
def appIdentifier = getAppIdentifier(packageJsonMap)
if (appIdentifier) {
project.ext.nsApplicationIdentifier = appIdentifier
android.defaultConfig.applicationId = appIdentifier
}
}
}
android {
applyBeforePluginGradleConfiguration()
if (enableKotlin) {
kotlinOptions {
jvmTarget = '1.8'
}
}
compileSdkVersion computeCompileSdkVersion()
buildToolsVersion computeBuildToolsVersion()
defaultConfig {
def manifest = new XmlSlurper().parse(file(android.sourceSets.main.manifest.srcFile))
def minSdkVer = manifest."uses-sdk"."#android:minSdkVersion".text() ?: NS_DEFAULT_MIN_SDK_VERSION
minSdkVersion minSdkVer
targetSdkVersion computeTargetSdkVersion()
ndk {
if (onlyX86) {
abiFilters 'x86'
} else {
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8//////
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets.main {
jniLibs.srcDirs = ["$projectDir/libs/jni", "$projectDir/snapshot-build/build/ndk-build/libs"]
}
signingConfigs {
release {
if (project.hasProperty("release")) {
if (project.hasProperty("ksPath") &&
project.hasProperty("ksPassword") &&
project.hasProperty("alias") &&
project.hasProperty("password")) {
storeFile file(ksPath)
storePassword ksPassword
keyAlias alias
keyPassword password
}
}
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
////////// CONFIGURATION PHASE /////////////////
task addDependenciesFromNativeScriptPlugins {
nativescriptDependencies.each { dep ->
def aarFiles = fileTree(dir: file("$rootDir/${dep.directory}/$PLATFORMS_ANDROID"), include: ["**/*.aar"])
aarFiles.each { aarFile ->
def length = aarFile.name.length() - 4
def fileName = aarFile.name[0..<length]
outLogger.withStyle(Style.SuccessHeader).println "\t + adding aar plugin dependency: " + aarFile.getAbsolutePath()
project.dependencies.add("implementation", [name: fileName, ext: "aar"])
}
def jarFiles = fileTree(dir: file("$rootDir/${dep.directory}/$PLATFORMS_ANDROID"), include: ["**/*.jar"])
jarFiles.each { jarFile ->
def jarFileAbsolutePath = jarFile.getAbsolutePath()
outLogger.withStyle(Style.SuccessHeader).println "\t + adding jar plugin dependency: $jarFileAbsolutePath"
pluginsJarLibraries.add(jarFile.getAbsolutePath())
}
project.dependencies.add("implementation", jarFiles)
}
}
task addDependenciesFromAppResourcesLibraries {
def appResourcesPath = getAppResourcesPath()
def appResourcesLibraries = file("$appResourcesPath/Android/libs")
if (appResourcesLibraries.exists()) {
def aarFiles = fileTree(dir: appResourcesLibraries, include: ["**/*.aar"])
aarFiles.each { aarFile ->
def length = aarFile.name.length() - 4
def fileName = aarFile.name[0..<length]
outLogger.withStyle(Style.SuccessHeader).println "\t + adding aar library dependency: " + aarFile.getAbsolutePath()
project.dependencies.add("implementation", [name: fileName, ext: "aar"])
}
def jarFiles = fileTree(dir: appResourcesLibraries, include: ["**/*.jar"])
jarFiles.each { jarFile ->
def jarFileAbsolutePath = jarFile.getAbsolutePath()
outLogger.withStyle(Style.SuccessHeader).println "\t + adding jar plugin dependency: $jarFileAbsolutePath"
pluginsJarLibraries.add(jarFile.getAbsolutePath())
}
project.dependencies.add("implementation", jarFiles)
}
}
if (failOnCompilationWarningsEnabled()) {
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:all' << "-Werror"
options.deprecation = true
}
}
tasks.whenTaskAdded({ DefaultTask currentTask ->
if (currentTask =~ /generate.+BuildConfig/) {
currentTask.finalizedBy(extractAllJars)
extractAllJars.finalizedBy(collectAllJars)
}
if (currentTask =~ /compile.+JavaWithJavac/) {
currentTask.dependsOn(runSbg)
currentTask.finalizedBy(buildMetadata)
}
if (currentTask =~ /merge.*Assets/) {
currentTask.dependsOn(buildMetadata)
}
// ensure buildMetadata is done before R8 to allow custom proguard from metadata
if (currentTask =~ /minify.*WithR8/) {
currentTask.dependsOn(buildMetadata)
}
if (currentTask =~ /assemble.*Debug/ || currentTask =~ /assemble.*Release/) {
currentTask.finalizedBy("validateAppIdMatch")
}
})
////////////// EXECUTUION PHASE //////////
task runSbg(type: BuildToolTask) {
dependsOn "collectAllJars"
if (!findProject(':static-binding-generator').is(null)) {
dependsOn ':static-binding-generator:jar'
}
outputs.dir("$OUTPUT_JAVA_DIR/com/tns/gen")
inputs.dir(INPUT_JS_DIR)
inputs.dir(extractedDependenciesDir)
workingDir "$BUILD_TOOLS_PATH"
main "-jar"
def paramz = new ArrayList<String>()
paramz.add("static-binding-generator.jar")
if (failOnCompilationWarningsEnabled()) {
paramz.add("-show-deprecation-warnings")
}
setOutputs outLogger
args paramz
doFirst {
new File("$OUTPUT_JAVA_DIR/com/tns/gen").deleteDir()
}
}
def failOnCompilationWarningsEnabled() {
return project.hasProperty("failOnCompilationWarnings") && (failOnCompilationWarnings || failOnCompilationWarnings.toBoolean())
}
def explodeAar(File compileDependency, File outputDir) {
logger.info("explodeAar: Extracting ${compileDependency.path} -> ${outputDir.path}")
if (compileDependency.name.endsWith(".aar")) {
JarFile jar = new JarFile(compileDependency)
Enumeration enumEntries = jar.entries()
while (enumEntries.hasMoreElements()) {
JarEntry file = (JarEntry) enumEntries.nextElement()
if (file.isDirectory()) {
continue
}
if (file.name.endsWith(".jar")) {
def targetFile = new File(outputDir, file.name)
InputStream inputStream = jar.getInputStream(file)
new File(targetFile.parent).mkdirs()
Files.copy(inputStream, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
}
}
jar.close()
} else if (compileDependency.name.endsWith(".jar")) {
copy {
from compileDependency.absolutePath
into outputDir
}
}
}
def md5(String string) {
MessageDigest digest = MessageDigest.getInstance("MD5")
digest.update(string.bytes)
return new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
}
class WorkerTask extends DefaultTask {
#Inject
WorkerExecutor getWorkerExecutor() {
throw new UnsupportedOperationException()
}
}
class EmptyRunnable implements Runnable {
void run() {
}
}
def getMergedAssetsOutputPath() {
if (!project.hasProperty("mergedAssetsOutputPath")) {
// mergedAssetsOutputPath not found fallback to the default value for android gradle plugin 3.5.1
project.ext.mergedAssetsOutputPath = "$projectDir/build/intermediates/merged_assets/" + project.selectedBuildType + "/out"
}
return project.ext.mergedAssetsOutputPath
}
// Discover all jars and dynamically create tasks for the extraction of each of them
project.ext.allJars = []
allprojects {
afterEvaluate { project ->
def buildType = project.selectedBuildType
def jars = []
def artifactType = Attribute.of('artifactType', String)
android.applicationVariants.all { variant ->
if (variant.buildType.name == buildType) {
variant.getCompileClasspath().each { fileDependency ->
processJar(fileDependency, jars)
}
}
}
}
}
def processJar(File jar, jars) {
if (!jars.contains(jar)) {
jars.add(jar)
def destDir = md5(jar.path)
def outputDir = new File(Paths.get(extractedDependenciesDir, destDir).normalize().toString())
def taskName = "extract_${jar.name}_to_${destDir}"
logger.debug("Creating dynamic task ${taskName}")
// Add discovered jars as dependencies of cleanupAllJars.
// This is cruicial for cloud builds because they are different
// on each incremental build (as each time the gradle user home
// directory is a randomly generated string)
cleanupAllJars.inputs.files jar
task "${taskName}"(type: WorkerTask) {
dependsOn cleanupAllJars
extractAllJars.dependsOn it
// This dependency seems redundant but probably due to some Gradle issue with workers,
// without it `runSbg` sporadically starts before all extraction tasks have finished and
// fails due to missing JARs
runSbg.dependsOn it
inputs.files jar
outputs.dir outputDir
doLast {
// Runing in parallel no longer seems to bring any benefit.
// It mattered only when we were extracting JARs from AARs.
// To try it simply remove the following comments.
// workerExecutor.submit(EmptyRunnable.class) {
explodeAar(jar, outputDir)
// }
}
}
project.ext.allJars.add([file: jar, outputDir: outputDir])
}
}
task cleanupAllJars {
// We depend on the list of libs directories that might contain aar or jar files
// and on the list of all discovered jars
inputs.files(pluginDependencies)
outputs.files cleanupAllJarsTimestamp
doLast {
def allDests = project.ext.allJars*.outputDir*.name
def dir = new File(extractedDependenciesDir)
if (dir.exists()) {
dir.eachDir {
// An old directory which is no longer a dependency (e.g. orphaned by a deleted plugin)
if (!allDests.contains(it.name)) {
logger.info("Task cleanupAllJars: Deleting orphaned ${it.path}")
FileUtils.deleteDirectory(it)
}
}
}
new File(cleanupAllJarsTimestamp).write ""
}
}
// Placeholder task which depends on all dynamically generated extraction tasks
task extractAllJars {
dependsOn cleanupAllJars
outputs.files extractAllJarsTimestamp
doLast {
new File(cleanupAllJarsTimestamp).write ""
}
}
task collectAllJars {
dependsOn extractAllJars
description "gathers all paths to jar dependencies before building metadata with them"
def sdkPath = android.sdkDirectory.getAbsolutePath()
def androidJar = sdkPath + "/platforms/" + android.compileSdkVersion + "/android.jar"
doFirst {
def allJarPaths = new LinkedList<String>()
allJarPaths.add(androidJar)
allJarPaths.addAll(pluginsJarLibraries)
def ft = fileTree(dir: extractedDependenciesDir, include: "**/*.jar")
ft.each { currentJarFile ->
allJarPaths.add(currentJarFile.getAbsolutePath())
}
new File("$BUILD_TOOLS_PATH/$SBG_JAVA_DEPENDENCIES").withWriter { out ->
allJarPaths.each { out.println it }
}
new File("$BUILD_TOOLS_PATH/$MDG_JAVA_DEPENDENCIES").withWriter { out ->
allJarPaths.each {
if (it.endsWith(".jar")) {
out.println it
}
}
}
new File("$BUILD_TOOLS_PATH/$SBG_INPUT_FILE").withWriter { out ->
out.println INPUT_JS_DIR
}
new File("$BUILD_TOOLS_PATH/$SBG_OUTPUT_FILE").withWriter { out ->
out.println OUTPUT_JAVA_DIR
}
allJarLibraries.addAll(allJarPaths)
}
}
task copyMetadataFilters(type: Copy) {
from "$rootDir/whitelist.mdg", "$rootDir/blacklist.mdg"
into "$BUILD_TOOLS_PATH"
}
task copyMetadata {
doLast {
copy {
from "$projectDir/src/main/assets/metadata"
into getMergedAssetsOutputPath() + "/metadata"
}
}
}
task buildMetadata(type: BuildToolTask) {
if (!findProject(':android-metadata-generator').is(null)) {
dependsOn ':android-metadata-generator:jar'
}
dependsOn copyMetadataFilters
// As some external gradle plugins can reorder the execution order of the tasks it may happen that buildMetadata is executed after merge{Debug/Release}Assets
// in that case the metadata won't be included in the result apk and it will crash, so to avoid this we are adding the copyMetadata task which will manually copy
// the metadata files in the merge assets folder and they will be added to the result apk
// The next line is added to avoid adding another copyData implementation from the firebase plugin - https://github.com/EddyVerbruggen/nativescript-plugin-firebase/blob/3943bb9147f43c41599e801d026378eba93d3f3a/publish/scripts/installer.js#L1105
//buildMetadata.finalizedBy(copyMetadata)
finalizedBy copyMetadata
description "builds metadata with provided jar dependencies"
inputs.files("$MDG_JAVA_DEPENDENCIES")
// make MDG aware of whitelist.mdg and blacklist.mdg files
inputs.files(project.fileTree(dir: "$rootDir", include: "**/*.mdg"))
def classesDir = "$buildDir/intermediates/javac"
inputs.dir(classesDir)
def kotlinClassesDir = "$buildDir/tmp/kotlin-classes"
if (file(kotlinClassesDir).exists()) {
inputs.dir(kotlinClassesDir)
}
outputs.files("$METADATA_OUT_PATH/treeNodeStream.dat", "$METADATA_OUT_PATH/treeStringsStream.dat", "$METADATA_OUT_PATH/treeValueStream.dat")
workingDir "$BUILD_TOOLS_PATH"
main "-jar"
doFirst {
// get compiled classes to pass to metadata generator
// these need to be called after the classes have compiled
assert file(classesDir).exists()
new File(getMergedAssetsOutputPath() + "/metadata").deleteDir()
def classesSubDirs = new File(classesDir).listFiles()
def selectedBuildType = project.ext.selectedBuildType
def generatedClasses = new LinkedList<String>()
for (File subDir : classesSubDirs) {
if (subDir.getName() == selectedBuildType) {
generatedClasses.add(subDir.getAbsolutePath())
}
}
if (file(kotlinClassesDir).exists()) {
def kotlinClassesSubDirs = new File(kotlinClassesDir).listFiles()
for (File subDir : kotlinClassesSubDirs) {
if (subDir.getName() == selectedBuildType) {
generatedClasses.add(subDir.getAbsolutePath())
}
}
}
new File("$BUILD_TOOLS_PATH/$MDG_OUTPUT_DIR").withWriter { out ->
out.println "$METADATA_OUT_PATH"
}
new File("$BUILD_TOOLS_PATH/$MDG_JAVA_DEPENDENCIES").withWriterAppend { out ->
generatedClasses.each { out.println it }
}
setOutputs outLogger
def paramz = new ArrayList<String>()
paramz.add("android-metadata-generator.jar")
if(enableAnalytics){
paramz.add("analyticsFilePath=$analyticsFilePath")
}
if(enableVerboseMDG){
paramz.add("verbose")
}
args paramz.toArray()
}
}
task generateTypescriptDefinitions(type: BuildToolTask) {
if (!findProject(':dts-generator').is(null)) {
dependsOn ':dts-generator:jar'
}
def paramz = new ArrayList<String>()
def includeDirs = ["com.android.support", "/platforms/" + android.compileSdkVersion]
workingDir "$BUILD_TOOLS_PATH"
main "-jar"
doFirst {
delete "$TYPINGS_PATH"
paramz.add("dts-generator.jar")
paramz.add("-input")
for (String jarPath : allJarLibraries) {
// don't generate typings for runtime jars and classes
if (shouldIncludeDirForTypings(jarPath, includeDirs)) {
paramz.add(jarPath)
}
}
paramz.add("-output")
paramz.add("$TYPINGS_PATH")
new File("$TYPINGS_PATH").mkdirs()
logger.info("Task generateTypescriptDefinitions: Call dts-generator.jar with arguments: " + paramz.toString().replaceAll(',', ''))
outLogger.withStyle(Style.SuccessHeader).println "Task generateTypescriptDefinitions: Call dts-generator.jar with arguments: " + paramz.toString().replaceAll(',', '')
setOutputs outLogger
args paramz.toArray()
}
}
generateTypescriptDefinitions.onlyIf {
(project.hasProperty("generateTypings") && Boolean.parseBoolean(project.generateTypings)) || PASSED_TYPINGS_PATH != null
}
collectAllJars.finalizedBy(generateTypescriptDefinitions)
static def shouldIncludeDirForTypings(path, includeDirs) {
for (String p : includeDirs) {
if (path.indexOf(p) > -1) {
return true
}
}
return false
}
task copyTypings {
doLast {
outLogger.withStyle(Style.Info).println "Copied generated typings to application root level. Make sure to import android.d.ts in reference.d.ts"
copy {
from "$TYPINGS_PATH"
into "$USER_PROJECT_ROOT"
}
}
}
copyTypings.onlyIf { generateTypescriptDefinitions.didWork }
generateTypescriptDefinitions.finalizedBy(copyTypings)
task validateAppIdMatch {
doLast {
def lineSeparator = System.getProperty("line.separator")
if (project.hasProperty("nsApplicationIdentifier") && !project.hasProperty("release")) {
if (project.nsApplicationIdentifier != android.defaultConfig.applicationId) {
def errorMessage = "${lineSeparator}WARNING: The Application identifier is different from the one inside \"package.json\" file.$lineSeparator" +
"NativeScript CLI might not work properly.$lineSeparator" +
"Remove applicationId from app.gradle and update the \"nativescript.id\" in package.json.$lineSeparator" +
"Actual: ${android.defaultConfig.applicationId}$lineSeparator" +
"Expected(from \"package.json\"): ${project.nsApplicationIdentifier}$lineSeparator"
logger.error(errorMessage)
}
}
}
}
//////////////// OPTIONAL TASKS //////////
//////// custom clean ///////////
task cleanSbg(type: Delete) {
delete "$BUILD_TOOLS_PATH/$SBG_JS_PARSED_FILES",
"$BUILD_TOOLS_PATH/$SBG_JAVA_DEPENDENCIES",
"$BUILD_TOOLS_PATH/$SBG_INTERFACE_NAMES",
"$BUILD_TOOLS_PATH/$SBG_BINDINGS_NAME",
"$BUILD_TOOLS_PATH/$SBG_INPUT_FILE",
"$BUILD_TOOLS_PATH/$SBG_OUTPUT_FILE",
"$OUTPUT_JAVA_DIR/com/tns/gen"
}
task cleanMdg(type: Delete) {
delete "$BUILD_TOOLS_PATH/$MDG_OUTPUT_DIR",
"$BUILD_TOOLS_PATH/whitelist.mdg",
"$BUILD_TOOLS_PATH/blacklist.mdg",
"$BUILD_TOOLS_PATH/$MDG_JAVA_DEPENDENCIES",
"$METADATA_OUT_PATH"
}
cleanSbg.dependsOn(cleanMdg)
clean.dependsOn(cleanSbg)
I tried playing around with the sdk properties.
NativeScript usually adds this information by itself depending on what sdk versions you have installed. You might want to update the cli:
npm i -g nativescript
or manually set in your app.gradle inside the App_Resources folder:
android {
...
compileSdkVersion 32 // change 32 to whatever sdk you want or have installed
I have a java Android project and I am trying to include Kotlin/Convert some of the java classes to Kotlin.
Project's build.gradle:
Here I have introduced a variable for Kotlin version 1.6.10 and kotlin gradle plugin.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
import com.tcs.dev.Repo
import org.gradle.wrapper.SystemPropertiesHandler
buildscript {
ext.kotlin_version = '1.6.10'
// load local.properties file like gradle.properties
System.getProperties().putAll(SystemPropertiesHandler.getSystemProperties(file('local.properties')))
Properties properties = new Properties()
if (file("local.properties").exists()) {
properties.load(file('local.properties').newDataInputStream())
}
if (project.hasProperty('propfile')) {
properties.load(file(propfile).newDataInputStream())
}
properties.each { k, v -> ext[k] = v }
repositories {
google()
maven Repo.config(project)
maven { url 'https://jitpack.io' }
maven { url "https://oss.sonatype.org/content/repositories/snapshots" } // For Spoon snapshot, until 2.0.0 is released
jcenter()
}
dependencies {
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
classpath 'com.android.tools.build:gradle:7.0.4'
classpath 'com.google.gms:google-services:4.3.10'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
App's build.gradle:
Here I have introduced the Kotlin plugin and two more Kotlin libraries in the implementation section.
import com.tcs.dev.BuildVars
import com.tcs.dev.FileExtension
import com.tcs.dev.PropertiesFile
import com.tcs.dev.Repo
import com.tcs.dev.Shell
import com.tcs.dev.Version
import java.nio.file.Files
import java.nio.file.Paths
import java.util.regex.Pattern
buildscript {
// Items referenced both in and outside of the buildscript block
ext {
buildToolsDir = System.env.get('HOME') + "/build_tools"
localProperties = new File(rootProject.projectDir, "local.properties")
}
// SDK - needs to be done by buildscript because the android-sdk-manager plugin requires it on apply
def androidSdkName = getProperty('systemProp.tcs.dev.android.sdk.name')
def androidSdkVersion = getProperty('systemProp.tcs.dev.android.sdk.version')
def androidSdkClassifier = "darwin-x86_64"
def androidSdkExt = "tgz"
repositories {
jcenter()
google()
maven Repo.config(project)
}
dependencies {
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.3.0'
classpath group: 'com.google', name: androidSdkName,
version: androidSdkVersion, ext: androidSdkExt, classifier: androidSdkClassifier
}
PropertiesFile.addOrChangeKey(project.localProperties, "sdk.dir", androidSdkDir)
// This should already exist, but just in case not
FileExtension.mkdirs(project.buildToolsDir)
// Extract the Android SDK
if (! new File(sdkBomFile).exists()) {
def sdkFile = sprintf("%s-%s-%s.%s", androidSdkName, androidSdkVersion, androidSdkClassifier, androidSdkExt)
def sdkFullFile = buildscript.configurations.classpath.files.find {
if (it.getName() == sdkFile) return it.getAbsoluteFile()
}
println "Extracting Android SDK"
def cmd = "tar -zxf ${sdkFullFile} -C ${project.buildToolsDir}"
def (exitValue, output) = Shell.shellCommandReturningExitValueAndOutput(cmd)
if (exitValue != 0) {
throw new Exception("Extract command exited with '${exitValue}': ${cmd}")
}
if (! new File(sdkBomFile).exists()) {
throw new Exception("Extract command did not create file '${sdkBomFile}': ${cmd}")
}
println "Accepting license agreements"
cmd = "yes | ${androidSdkDir}/tools/bin/sdkmanager --sdk_root=${androidSdkDir} --licenses"
(exitValue, output) = Shell.shellCommandReturningExitValueAndOutput(cmd)
}
}
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'com.google.firebase.crashlytics'
id 'com.google.gms.google-services'
}
// NDK
def androidNdkName = getProperty('systemProp.tcs.dev.android.ndk.name')
def androidNdkVersion = getProperty('systemProp.tcs.dev.android.ndk.version')
def androidNdkDir = sprintf("%s/%s-%s", project.buildToolsDir, androidNdkName, androidNdkVersion)
def androidNdkInstalled = {
return new File(androidNdkDir, 'ndk-build').exists()
}
// AVD
def androidAvdName = getProperty('systemProp.tcs.dev.android.avd.name')
def androidAvdVersion = getProperty('systemProp.tcs.dev.android.avd.version')
def androidAvdDir = sprintf("%s/%s-%s", project.buildToolsDir, androidAvdName, androidAvdVersion)
def androidAvdInstalled = {
return new File(androidAvdDir, "Nexus_9_API_${androidAvdVersion}.ini").exists()
}
[graphicsLibVersion:graphicsLibVersion, serializableLibVersion:serializableLibVersion].each { k, v ->
if (!v.startsWith(Version.projectVersion())) {
logger.warn "WARNING: ${k} ${v} does not match projectVersion ${Version.projectVersion()} please update"
}
}
def gitSha() {
return 'git rev-parse --short HEAD'.execute().text.trim()
}
configurations {
graphicsLib
eigen
generatedSource
manuallyEditedSourceDependencies
if (!androidNdkInstalled()) {
androidNdk
}
if (!androidAvdInstalled()) {
androidAvd
}
}
dependencies {
graphicsLib group: 'com.tcs', name: 'graphics-lib',
version: graphicsLibVersion, ext: 'tgz', classifier: 'sources'
generatedSource group: 'com.tcs', name: 'tcs-serializable-generator',
manuallyEditedSourceDependencies group: 'com.tcs', name: 'cppGraphicsDependencies',
version: cppGraphicsVersion, ext: 'tgz', classifier: 'sources'
if (!androidNdkInstalled()) {
androidNdk group: 'com.google', name: androidNdkName,
version: androidNdkVersion, ext: 'zip', classifier: 'darwin-x86_64'
}
if (!androidAvdInstalled()) {
androidAvd group: 'com.google', name: androidAvdName,
version: androidAvdVersion, ext: 'tgz', classifier: 'darwin-x86_64'
}
}
def minutesSinceEpoch() {
// This should produce unique values for > 4000 years
def minutes = new Date().time.intdiv(1000).intdiv(60).intdiv(30) * 30
Integer clamped = minutes & Integer.MAX_VALUE
return clamped
}
android {
compileSdkVersion 30
buildToolsVersion '30.0.0'
// Required for butterknife compatibility with androidx
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding true
}
defaultConfig {
applicationId = BuildVars.applicationId
minSdkVersion 21
targetSdkVersion 30
versionCode minutesSinceEpoch()
versionName "${Version.packageVersion()}"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
}
sourceSets.main {
// use the jni .so compiled from the manual ndk-build command'''
jniLibs.srcDirs = ['src/main/jniLibs/debug/lib', 'src/main/jniLibs/release/lib']
jni.srcDirs = [] //disable automatic ndk-build call
}
signingConfigs {
debug {
storeFile file("../tcs-debug.keystore")
storePassword "dummy1"
keyAlias "debug"
keyPassword "dummy1"
}
release {
storeFile file("../tcs-android.keystore")
storePassword project.properties.get("dummy2")
keyAlias "release"
keyPassword project.properties.get("dummy2")
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.release
}
debug {
signingConfig signingConfigs.debug
applicationIdSuffix ".debug"
jniDebuggable true
ext.setBuildConfigFieldWithDefault = { fieldName, value ->
if (project.hasProperty(fieldName)) {
value = project.properties.get(fieldName)
}
buildConfigField "String", fieldName, "\"$value\""
}
def testMap = []
if (project.findProperty('testStack') == "staging") {
testMap = [
'testServer' :'https://staging.dev.tcs.com/',
'testAsmBrokenTestDocId':'a63f4467861f1c54500afd9d',
'testAsmBrokenTestWsId' :'9b6b7102fe2578a1d683adf1',
'testAnonymousDocId' :'346fa02ef804498723df9b6e'
]
} else {
testMap = [
'testServer' :'https://demo-c.dev.tcs.com/',
]
}
printf("testMap is: ${testMap}\n")
testMap.each{ k, v -> setBuildConfigFieldWithDefault(k, v) }
setBuildConfigFieldWithDefault("testUsername", "androidtester3#test.tcs.com")
setBuildConfigFieldWithDefault("testPassword", "testPassword")
ext.enableCrashlytics = false
pseudoLocalesEnabled true
testCoverageEnabled true
}
}
project.gradle.taskGraph.whenReady {
connectedDebugAndroidTest {
ignoreFailures = true
}
}
packagingOptions {
exclude 'META-INF/rxjava.properties'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'LICENSE.txt'
doNotStrip "*/armeabi/*.so"
doNotStrip "*/armeabi-v7a/*.so"
doNotStrip "*/x86/*.so"
}
dexOptions {
javaMaxHeapSize "2g"
}
applicationVariants.all { variant ->
variant.mergeAssetsProvider.get().dependsOn(extractShaders)
}
lintOptions {
disable 'MissingTranslation', 'ExtraTranslation', 'NotSibling'
}
}
android.applicationVariants.all { variant ->
def applicationId = variant.applicationId as String
//def adbPath = android.adbExe as String
def adbPath = "/platform-tools/adb"
def variantName = variant.name.capitalize()
String pd = projectDir as String
def adbPlus = pd + "/../buildSrc/adb+.sh"
def grantPermissionsTask = tasks.create("grant${variantName}Permissions") {
doLast {
"bash ${adbPlus} ${adbPath} ${applicationId} android.permission.READ_CONTACTS".execute()
"bash ${adbPlus} ${adbPath} ${applicationId} android.permission.WRITE_EXTERNAL_STORAGE".execute()
}
}
grantPermissionsTask.description = "Grants permissions on Marshmallow and later"
grantPermissionsTask.group = "extras"
}
tasks.whenTaskAdded { theTask ->
if (theTask.name.equals("compileReleaseJavaWithJavac")) {
theTask.dependsOn "ndkBuildRelease"
} else if (theTask.name.equals("compileDebugJavaWithJavac")) {
theTask.dependsOn "ndkBuildDebug"
}
}
def assetsDir = new File(projectDir, 'src/main/assets')
task createAssetsDir() {
doFirst {
FileExtension.mkdirs(assetsDir)
}
}
task extractEigen(type: Copy) {
description = 'Expand eigen files into $EIGEN_DIR'
from(tarTree(configurations.eigen.singleFile)) {
include '*/Eigen/*'
include '*/Eigen/src/**'
}
if (eigenVersion == '506565787cdc4') { // 3.1.2
into eigenDir
def root = Pattern.compile('.*/Eigen/')
eachFile {
it.mode |= 0220
it.path = it.path.replaceFirst(root, '')
}
} else {
into eigenDir
eachFile {
it.mode |= 0220
}
}
dirMode 0775
}
task extractShaders(type: Exec) {
dependsOn createAssetsDir
def wd = assetsDir
def extractDir = 'shaders'
def targetFile = 'shaders'
inputs.file configurations.graphicsLib.singleFile
// Ensure the shaders are extracted
outputs.upToDateWhen { false }
outputs.dir "${wd}/${extractDir}"
workingDir wd
commandLine 'tar', '-s', ",graphics-lib-${graphicsLibVersion}/${targetFile},${extractDir},", '-xzf', configurations.graphicsLib.singleFile, "graphics-lib-${graphicsLibVersion}/${targetFile}"
}
task extractGraphics(type: Exec) {
description = 'set property graphics.repo.dir if you want to use your own version of the graphics repo.' +
' e.g. put a line like this in local.properties: graphics.repo.dir=/Users/pkania/repos/master/graphics'
def wd = 'src/main/jni'
def extractDir = 'Graphics'
def targetFile = 'GraphicsLibrary'
def graphicsDir = "${wd}/${extractDir}"
// Ensure the graphics are extracted
outputs.upToDateWhen { false }
outputs.dir graphicsDir
workingDir wd
doFirst {
def path = Paths.get(graphicsDir)
if (Files.isSymbolicLink(path)) {
Files.delete(path)
}
}
def graphicsRepoDir = project.properties.get('graphics.repo.dir')
if (graphicsRepoDir) {
def script = """
if [ -d ${extractDir} ]; then
rm -rf ${extractDir}
fi
ln -sf ${graphicsRepoDir}/BTGraphicsLibrary ${extractDir}
"""
commandLine Shell.getShellCommandLine(script)
} else {
inputs.file configurations.graphicsLib.singleFile
commandLine 'tar', '-s', ",graphics-lib-${graphicsLibVersion}/${targetFile},${extractDir},", '-xzf', configurations.graphicsLib.singleFile, "graphics-lib-${graphicsLibVersion}/${targetFile}"
}
}
task getGeneratedSource(type:Exec) {
description = 'extract cppGraphics generated source'
dependsOn extractGraphics
def tarFile = configurations.generatedSource.singleFile.path
inputs.file tarFile
workingDir 'src/main/jni'
// Ensure the cpp graphics are extracted
outputs.upToDateWhen { false }
def cmd = Shell.getShellCommandLine("tar xf ${tarFile}")
commandLine cmd
}
task getManuallyEditedSourceDependencies(type:Exec) {
description = 'extract cppGraphics manually edited source'
// this task must run after the generated sources are copied because manually edited files can
// overwrite generated ones.
dependsOn getGeneratedSource
def tarFile = configurations.manuallyEditedSourceDependencies.singleFile.path
inputs.file tarFile
workingDir 'src/main/jni/cppGraphics'
def cmd = Shell.getShellCommandLine("tar xf ${tarFile}")
commandLine cmd
}
task getAndroidNdkDir(type:Exec) {
}
getAndroidNdkDir.onlyIf {
!androidNdkInstalled()
}
task getAndroidNdk() {
}
task createSwigOutputDir {
doLast {
def swigOutputDir = file('src/main/java/com/tcs/app/graphics/gen')
FileExtension.mkdirs(swigOutputDir)
}
}
task getAndroidAvdDir(type:Exec) {
}
getAndroidAvdDir.onlyIf {
!androidAvdInstalled()
}
task getAndroidAvd() {
}
task swigBuild(type: Exec) {
dependsOn extractGraphics
dependsOn getGeneratedSource
dependsOn getManuallyEditedSourceDependencies
dependsOn createSwigOutputDir
dependsOn extractEigen
workingDir 'src/main/jni'
commandLine '/usr/local/bin/swig', '-java', '-c++', '-package', 'com.tcs.app.graphics.gen', '-outdir', '../java/com/tcs/app/graphics/gen', '-o', './graphics_wrap.cpp', 'graphics.i'
}
def numCompilationThreads = {
def (exitValue, numCompileThreads) = Shell.shellCommandReturningExitValueAndOutput("sysctl -n hw.ncpu");
if (exitValue != 0) {
return 1
}
return numCompileThreads
}
// call regular ndk-build(.cmd) script from app directory
// http://stackoverflow.com/questions/16667903/android-studio-gradle-and-ndk
// http://ph0b.com/android-studio-gradle-and-ndk-integration/
// TODO: We'd rather not have two tasks here. Either research whether we can just use the default NDK build with our own Android.mk, or figure out how to streamline this w/Gradle.
task ndkBuildDebug(type: Exec) {
}
task ndkBuildRelease(type: Exec) {
}
// TODO: do not brute force delete the graphics generated files. Instead, tell gradle they are output files, and
// let gradle automatically clean them
task cleanGraphicsGen(type: Delete) {
}
clean.dependsOn(cleanGraphicsGen)
// TODO: This is a more complete way to get the dependencies in place, but we need to figure out how to get the
// TODO: buildtype so we can refer to the correct ndkBuild task...
//tasks.withType(JavaCompile) {
// compileTask -> compileTask.dependsOn ndkBuild
//}
dependencies {
implementation 'androidx.core:core-ktx:1.3.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'com.google.android.material:material:1.1.0-alpha08'
implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'
implementation 'androidx.viewpager:viewpager:1.0.0'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation("com.tcs:tcs-android:$serializableLibVersion") {
transitive = false
}
implementation("com.tcs:tcs-primogenitor:$serializableLibVersion") {
transitive = false
}
implementation("com.tcs:tcs-serialize-common:$serializableLibVersion") {
transitive = false
}
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.percentlayout:percentlayout:1.0.0'
implementation 'com.google.android.gms:play-services-analytics:16.0.8'
implementation 'com.google.firebase:firebase-core:18.0.0'
implementation 'com.google.firebase:firebase-analytics:18.0.0'
implementation "com.google.firebase:firebase-messaging:17.5.0"
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'
implementation 'com.squareup.picasso:picasso:2.5.2'
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:converter-jackson:2.0.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.1.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
implementation 'com.google.code.gson:gson:2.6.2'
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.0"))
// define any required OkHttp artifacts without version
implementation("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:logging-interceptor")
implementation("com.google.guava:guava:31.0.1-android")
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'io.reactivex.rxjava2:rxjava:2.1.0'
implementation 'commons-lang:commons-lang:2.6'
implementation 'org.slf4j:slf4j-api:1.7.13'
implementation 'com.melnykov:floatingactionbutton:1.3.0'
implementation 'com.getbase:floatingactionbutton:1.10.1'
implementation 'net.danlew:android.joda:2.9.9.4'
implementation 'io.github.inflationx:calligraphy3:3.1.1'
implementation 'io.github.inflationx:viewpump:2.0.3'
]
implementation 'com.google.firebase:firebase-crashlytics:17.2.2'
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.1') {
exclude module: 'support-annotations'
}
androidTestImplementation('androidx.test.espresso:espresso-idling-resource:3.1.1') {
exclude module: 'support-annotations'
}
androidTestImplementation "com.squareup.spoon:spoon-client:2.0.0-SNAPSHOT" // For Spoon snapshot, until 2.0.0 is released
androidTestImplementation 'androidx.test:rules:1.1.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test:core:1.1.0'
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.1.0', {
exclude group: 'com.android.support', module: 'support-annotations'
exclude group: 'com.android.support', module: 'support-v4'
exclude group: 'com.android.support', module: 'design'
exclude group: 'com.android.support', module: 'recyclerview-v7'
}
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.constraintlayout:constraintlayout-solver:1.1.3'
androidTestImplementation 'junit:junit:4.13'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
}
spoon {
def envSerial = System.env['ANDROID_SERIAL'];
if (envSerial) {
devices = [envSerial];
}
if (project.hasProperty('spoonClassName')) {
className = project.spoonClassName
}
if (project.hasProperty('spoonMethodName')) {
methodName = project.spoonMethodName
}
debug = true
adbTimeout = 10*60
// className = 'com.tcs.integration.smoketests'
// methodName = 'testSteeringWheel'
}
I get this error when gradle syncs:
Cause 1: com.android.build.gradle.internal.crash.ExternalApiUsageException: java.lang.IllegalArgumentException: Cannot change attributes of dependency configuration ':app:debugCompile' after it has been resolved
Caused by: java.lang.IllegalArgumentException: Cannot change attributes of dependency configuration ':app:debugCompile' after it has been resolved
at org.gradle.api.internal.attributes.ImmutableAttributeContainerWithErrorMessage.attribute(ImmutableAttributeContainerWithErrorMessage.java:57)
Cause 2: org.gradle.api.UnknownDomainObjectException: KotlinJvmAndroidCompilation with name 'debug' not found
There is no relevant code at all ...but according to the error message:
KotlinJvmAndroidCompilation with name 'debug' not found
I'd suggest to define android.buildTypes.debug, so that it would be known:
android {
buildTypes {
debug {}
}
}
But the answer may eventually rather be, to add Crashlytics on class-path (root build.gradle):
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
I saw messages like these in the gradlew --debug output.
RuntimeException: Configuration 'eigen' was resolved during configuration time
I ignored them at first because they didn't seem related to the exception displayed on the console.
I created an empty andriod studio project (with the kotlin-andorid plugin) and verified that could "build" without error.
I then added parts of our app/build.gradle file into the new project until I encountered the ':app:debugCompileOnly' error.
The error occurred when I added the extractEigen task.
That reminded me of the configuration resolution error I saw in the debug output.
I fixed the configuration resolution error and that fixed the ':app:debugCompileOnly'error.
(Fixed by a colleague)
Need help on enforcing code coverage metrics. I have based my solution on this blog post.
I have already referred following posts in an attempt to solve this problem.
this series of posts
this one on Jacoco with java project (not android)
this official documentation
this one was supposed to be a straight answer
many more SO questions and blogs
(Really embarrassing - still it looks like I'm missing something :( )
I am able to get the code coverage but not able to enforce minimum threshold.
Here is how my Jacoco.gradle looks like -
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.8.2"
}
project.afterEvaluate {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type ->
type.name
}
def productFlavors = android.productFlavors.collect { flavor ->
flavor.name
}
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
task "${testTaskName}Coverage" (type:JacocoReport, dependsOn: "$testTaskName") {
reports {
xml.enabled = true
html.enabled = true
}
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
classDirectories = fileTree(
dir: "${project.buildDir}/intermediates/javac/${buildTypeName}",
excludes: [
'**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/Manifest*.*'
]
)
def coverageSourceDirs = [
"src/main/java",
"src/$productFlavorName/java",
"src/$buildTypeName/java"
]
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
}
}
}
}
I have included the above script in app module's build.gradle.
apply plugin: 'com.android.application'
apply from: '../jacoco.gradle'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.jacocodemo"
minSdkVersion 27
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
testCoverageEnabled = true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
I have tried many different approaches so far. Looks like the Jacoco documentation is biased towards plain java projects as the code snippets almost always need changes when used in android, but even then no luck.
Here's my attempt to solve this -
(just give the Jacoco.gradle here as the main code is in it)
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.8.2"
}
// ****** THIS IS MY ATTEMPT AT IT [START] ******
task jacocoTestCoverageVerification(type: JacocoCoverageVerification) {
violationRules {
rule {
enabled = true
limit {
minimum = 0.9
}
}
}
}
check.dependsOn jacocoTestCoverageVerification
// ****** THIS IS MY ATTEMPT AT IT [END] ******
project.afterEvaluate {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type ->
type.name
}
def productFlavors = android.productFlavors.collect { flavor ->
flavor.name
}
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
task "${testTaskName}Coverage" (type:JacocoReport, dependsOn: "$testTaskName") {
reports {
xml.enabled = true
html.enabled = true
}
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
classDirectories = fileTree(
dir: "${project.buildDir}/intermediates/javac/${buildTypeName}",
excludes: [
'**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/Manifest*.*'
]
)
def coverageSourceDirs = [
"src/main/java",
"src/$productFlavorName/java",
"src/$buildTypeName/java"
]
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
}
}
}
}
and then I tried invoking it as follows:
gradle clean build testDebugUnitTestCoverage jacocoTestCoverageVerification.
Any help on this is much appreciated.
I'm new to Android development. I chose NativeScript for this purpose.
In a scenario I needed to use RadListView, so I added its plugin to my app. But when I try to run the app, I get this error:
FAILURE: Build failed with an exception.
* What went wrong:
Could not resolve all files for configuration ':app:debugCompileClasspath'.
> Could not find recyclerview-v7.jar (com.android.support:recyclerview-v7:28.0.0).
Searched in the following locations:
https://dl.google.com/dl/android/maven2/com/android/support/recyclerview-v7/28.0.0/recyclerview-v7-28.0.0.jar
https://dl.google.com/dl/android/maven2/com/android/support/recyclerview-v7/28.0.0/recyclerview-v7-28.0.0.jar returns a 404 Error.
How to reproduce:
> tns create my-app --template tns-template-hello-world
> cd my-app
> tns run android
> tns plugin add nativescript-ui-listview
> tns run android
First run is OK, second one is not.
Closest page to my problem is this. But he could solve his problem by upgrading gradle. I have already its latest release.
My build.gradle (root):
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.0'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
My build.gradle (app):
/*
* Script builds apk in release or debug mode
* To run:
* gradle assembleRelease -Prelease (release mode)
* gradle assembleDebug (debug mode -> default)
* Options:
* -Prelease //this flag will run build in release mode
* -PksPath=[path_to_keystore_file]
* -PksPassword=[password_for_keystore_file]
* -Palias=[alias_to_use_from_keystore_file]
* -Ppassword=[password_for_alias]
*
* -PtargetSdk=[target_sdk]
* -PbuildToolsVersion=[build_tools_version]
* -PsupportVersion=[support_version]
* -PcompileSdk=[compile_sdk_version]
*/
import groovy.json.JsonSlurper
import java.nio.file.Paths
import java.util.regex.Matcher
import java.util.regex.Pattern
apply plugin: "com.android.application"
def onlyX86 = project.hasProperty("onlyX86")
if (onlyX86) {
println "OnlyX86 build triggered."
}
//common
def BUILD_TOOLS_PATH = "$rootDir/build-tools"
def PASSED_TYPINGS_PATH = System.getenv("TNS_TYPESCRIPT_DECLARATIONS_PATH")
def TYPINGS_PATH = "$BUILD_TOOLS_PATH/typings"
if (PASSED_TYPINGS_PATH != null) {
TYPINGS_PATH = PASSED_TYPINGS_PATH
}
def USER_PROJECT_ROOT = "$rootDir/../.."
def PLATFORMS_ANDROID = "platforms/android"
def PACKAGE_JSON = "package.json"
//static binding generator
def SBG_JAVA_DEPENDENCIES = "sbg-java-dependencies.txt"
def SBG_INPUT_FILE = "sbg-input-file.txt"
def SBG_OUTPUT_FILE = "sbg-output-file.txt"
def SBG_JS_PARSED_FILES = "sbg-js-parsed-files.txt"
def SBG_BINDINGS_NAME = "sbg-bindings.txt"
def SBG_INTERFACE_NAMES = "sbg-interface-names.txt"
def INPUT_JS_DIR = "$projectDir/src/main/assets/app"
def OUTPUT_JAVA_DIR = "$projectDir/src/main/java"
//metadata generator
def MDG_OUTPUT_DIR = "mdg-output-dir.txt"
def MDG_JAVA_DEPENDENCIES = "mdg-java-dependencies.txt"
def METADATA_OUT_PATH = "$projectDir/src/main/assets/metadata"
// paths to jar libraries
def pluginsJarLibraries = new LinkedList<String>()
def allJarLibraries = new LinkedList<String>()
// the build script will not work with previous versions of the CLI (3.1 or earlier)
def dependenciesJson = file("$rootDir/dependencies.json")
if (!dependenciesJson.exists()) {
throw new BuildCancelledException("""
'dependencies.json' file not found. Check whether the NativeScript CLI has prepared the project beforehand,
and that your NativeScript version is 3.3, or a more recent one. To build an android project with the current
version of the {N} CLI install a previous version of the runtime package - 'tns platform add android#3.2'.
""")
}
project.ext.extractedDependenciesDir = "${project.buildDir}/exploded-dependencies"
def nativescriptDependencies = new JsonSlurper().parseText(dependenciesJson.text)
def computeCompileSdkVersion = { -> project.hasProperty("compileSdk") ? compileSdk : 28 }
def computeTargetSdkVersion = { -> project.hasProperty("targetSdk") ? targetSdk : 28 }
def computeBuildToolsVersion = { ->
project.hasProperty("buildToolsVersion") ? buildToolsVersion : "28.0.3"
}
project.ext.selectedBuildType = project.hasProperty("release") ? "release" : "debug"
project.ext.appResourcesPath = ""
////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// CONFIGURATIONS ///////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
def getAppResourcesPath = { ->
def relativePathToApp = "app"
def relativePathToAppResources
def absolutePathToAppResources
def nsConfigFile = file("$USER_PROJECT_ROOT/nsconfig.json")
def nsConfig
if (nsConfigFile.exists()) {
nsConfig = new JsonSlurper().parseText(nsConfigFile.getText("UTF-8"))
}
if(nsConfig != null && nsConfig.appPath != null){
relativePathToApp = nsConfig.appPath
}
if(nsConfig != null && nsConfig.appResourcesPath != null ) {
relativePathToAppResources = nsConfig.appResourcesPath
} else {
relativePathToAppResources = "$relativePathToApp/App_Resources"
}
absolutePathToAppResources = java.nio.file.Paths.get(USER_PROJECT_ROOT).resolve(relativePathToAppResources).toAbsolutePath()
project.ext.appResourcesPath = absolutePathToAppResources
return absolutePathToAppResources
}
def applyBeforePluginGradleConfiguration = { ->
def appResourcesPath = getAppResourcesPath()
def pathToBeforePluginGradle = "$appResourcesPath/Android/before-plugins.gradle"
def beforePluginGradle = file(pathToBeforePluginGradle)
if (beforePluginGradle.exists()) {
println "\t + applying user-defined configuration from ${beforePluginGradle}"
apply from: pathToBeforePluginGradle
}
}
def applyAppGradleConfiguration = { ->
def appResourcesPath = getAppResourcesPath()
def pathToAppGradle = "$appResourcesPath/Android/app.gradle"
def appGradle = file(pathToAppGradle)
if (appGradle.exists()) {
println "\t + applying user-defined configuration from ${appGradle}"
apply from: pathToAppGradle
} else {
println "\t + couldn't load user-defined configuration from ${appGradle}. File doesn't exist."
}
}
def applyPluginGradleConfigurations = { ->
nativescriptDependencies.each {dep ->
def includeGradlePath = "$rootDir/${dep.directory}/$PLATFORMS_ANDROID/include.gradle"
if(file(includeGradlePath).exists()) {
apply from: includeGradlePath
}
}
}
def getAppIdentifier = { packageJsonMap ->
def appIdentifier = "";
if (packageJsonMap && packageJsonMap.nativescript) {
appIdentifier = packageJsonMap.nativescript.id;
if (!(appIdentifier instanceof String)) {
appIdentifier = appIdentifier.android;
}
}
return appIdentifier;
}
def setAppIdentifier = { ->
println "\t + setting applicationId";
File packageJsonFile = new File("$rootDir/../../package.json");
if (packageJsonFile.exists()) {
def content = packageJsonFile.getText("UTF-8");
def jsonSlurper = new JsonSlurper();
def packageJsonMap = jsonSlurper.parseText(content);
def appIdentifier = getAppIdentifier(packageJsonMap);
if (appIdentifier) {
project.ext.nsApplicationIdentifier = appIdentifier;
android.defaultConfig.applicationId = appIdentifier;
}
}
}
android {
compileSdkVersion computeCompileSdkVersion()
buildToolsVersion computeBuildToolsVersion()
defaultConfig {
def manifest = new XmlSlurper().parse(file(android.sourceSets.main.manifest.srcFile))
def minSdkVer = manifest."uses-sdk"."#android:minSdkVersion".text() ?: 17
minSdkVersion minSdkVer
targetSdkVersion computeTargetSdkVersion()
ndk {
if (onlyX86) {
abiFilters 'x86'
} else {
abiFilters 'x86', 'armeabi-v7a'//, 'arm64-v8a'
}
}
dexOptions {
jumboMode = true
}
}
sourceSets.main {
jniLibs.srcDir "$projectDir/libs/jni"
}
signingConfigs {
release {
if (project.hasProperty("release")) {
if (project.hasProperty("ksPath") &&
project.hasProperty("ksPassword") &&
project.hasProperty("alias") &&
project.hasProperty("password")) {
storeFile file(ksPath)
storePassword ksPassword
keyAlias alias
keyPassword password
}
}
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
setAppIdentifier()
applyBeforePluginGradleConfiguration()
applyPluginGradleConfigurations()
applyAppGradleConfiguration()
}
def externalRuntimeExists = !findProject(':runtime').is(null)
repositories {
// used for local *.AAR files
def pluginDependencies = nativescriptDependencies.collect {
"$rootDir/${it.directory}/$PLATFORMS_ANDROID"
}
// some plugins may have their android dependencies in a /libs subdirectory
pluginDependencies.addAll(nativescriptDependencies.collect {
"$rootDir/${it.directory}/$PLATFORMS_ANDROID/libs"
})
if (!externalRuntimeExists) {
pluginDependencies.add("libs/runtime-libs")
}
def appResourcesPath = getAppResourcesPath()
def localAppResourcesLibraries = "$appResourcesPath/Android/libs"
pluginDependencies.add(localAppResourcesLibraries)
if (pluginDependencies.size() > 0) {
flatDir {
dirs pluginDependencies
}
}
}
dependencies {
def supportVer = "28.0.0"
if (project.hasProperty("supportVersion")) {
supportVer = supportVersion
}
println "Using support library version $supportVer"
implementation "com.android.support:multidex:1.0.2"
implementation "com.android.support:support-v4:$supportVer"
implementation "com.android.support:appcompat-v7:$supportVer"
implementation "com.android.support:design:$supportVer"
def sbgProjectExists = !findProject(':static-binding-generator').is(null)
if (sbgProjectExists) {
compileOnly project(':static-binding-generator')
}
def mdgProjectExists = !findProject(':android-metadata-generator').is(null)
if (mdgProjectExists) {
compileOnly project(':android-metadata-generator')
}
def dtsgProjectExists = !findProject(':dts-generator').is(null)
if (dtsgProjectExists) {
compileOnly project(':dts-generator')
}
def useV8Symbols = nativescriptDependencies.any {
def packageJsonPath = file("$rootDir/${it.directory}/$PACKAGE_JSON")
def packageJson = new JsonSlurper().parseText(packageJsonPath.text)
return packageJson.nativescript.useV8Symbols
}
if (!externalRuntimeExists) {
def runtime = "nativescript-optimized-with-inspector"
if (project.gradle.startParameter.taskNames.any { it.toLowerCase().contains('release') }) {
runtime = "nativescript-optimized"
}
if (useV8Symbols) {
runtime = "nativescript-regular"
}
println "\t + adding nativescript runtime package dependency: $runtime"
project.dependencies.add("implementation", [name: runtime, ext: "aar"])
} else {
implementation project(path: ':runtime', configuration: 'default')
}
}
////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// CONFIGURATION PHASE //////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
task addDependenciesFromNativeScriptPlugins {
nativescriptDependencies.each { dep ->
def aarFiles = fileTree(dir: file("$rootDir/${dep.directory}/$PLATFORMS_ANDROID"), include: ["**/*.aar"])
aarFiles.each { aarFile ->
def length = aarFile.name.length() - 4
def fileName = aarFile.name[0..<length]
println "\t + adding aar plugin dependency: " + aarFile.getAbsolutePath()
project.dependencies.add("implementation", [name: fileName, ext: "aar"])
}
def jarFiles = fileTree(dir: file("$rootDir/${dep.directory}/$PLATFORMS_ANDROID"), include: ["**/*.jar"])
jarFiles.each { jarFile ->
def jarFileAbsolutePath = jarFile.getAbsolutePath()
println "\t + adding jar plugin dependency: $jarFileAbsolutePath"
pluginsJarLibraries.add(jarFile.getAbsolutePath())
}
project.dependencies.add("implementation", jarFiles)
}
}
task addDependenciesFromAppResourcesLibraries {
def appResourcesPath = getAppResourcesPath()
def appResourcesLibraries = file("$appResourcesPath/Android/libs")
if (appResourcesLibraries.exists()) {
def aarFiles = fileTree(dir: appResourcesLibraries, include: ["**/*.aar"])
aarFiles.each { aarFile ->
def length = aarFile.name.length() - 4
def fileName = aarFile.name[0..<length]
println "\t + adding aar library dependency: " + aarFile.getAbsolutePath()
project.dependencies.add("implementation", [name: fileName, ext: "aar"])
}
def jarFiles = fileTree(dir: appResourcesLibraries, include: ["**/*.jar"])
jarFiles.each { jarFile ->
def jarFileAbsolutePath = jarFile.getAbsolutePath()
println "\t + adding jar plugin dependency: $jarFileAbsolutePath"
pluginsJarLibraries.add(jarFile.getAbsolutePath())
}
project.dependencies.add("implementation", jarFiles)
}
}
tasks.whenTaskAdded({ org.gradle.api.DefaultTask currentTask ->
if (currentTask =~ /generate.+BuildConfig/) {
currentTask.finalizedBy(extractAllJars)
extractAllJars.finalizedBy(collectAllJars)
}
if (currentTask =~ /compile.+JavaWithJavac/) {
currentTask.dependsOn(runSbg)
currentTask.finalizedBy(ensureMetadataOutDir)
ensureMetadataOutDir.finalizedBy(buildMetadata)
}
if (currentTask =~ /assemble.*Debug/ || currentTask =~ /assemble.*Release/) {
currentTask.finalizedBy("validateAppIdMatch")
}
})
////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// EXECUTUION PHASE /////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
task runSbg(type: JavaExec) {
inputs.dir(INPUT_JS_DIR)
workingDir "$BUILD_TOOLS_PATH"
main "-jar"
args "static-binding-generator.jar"
doFirst {
new File("$OUTPUT_JAVA_DIR/com/tns/gen").deleteDir();
}
}
task ensureMetadataOutDir {
doLast {
def outputDir = file("$METADATA_OUT_PATH")
outputDir.mkdirs()
}
}
def explodeAar(File compileDependency, String outputDir) {
if (compileDependency.name.endsWith(".aar")) {
java.util.jar.JarFile jar = new java.util.jar.JarFile(compileDependency)
Enumeration enumEntries = jar.entries()
while (enumEntries.hasMoreElements()) {
java.util.jar.JarEntry file = (java.util.jar.JarEntry) enumEntries.nextElement()
if (file.name.endsWith(".jar")) {
def f = new File(outputDir, file.name)
new File(f.parent).mkdirs()
InputStream is = jar.getInputStream(file)
FileOutputStream fos = new FileOutputStream(f)
while (is.available() > 0) {
fos.write(is.read())
}
fos.close()
is.close()
}
if (file.isDirectory()) {
continue
}
}
jar.close()
} else if (compileDependency.name.endsWith(".jar")) {
copy {
from compileDependency.absolutePath
into outputDir
}
}
}
task extractAllJars {
outputs.dir extractedDependenciesDir
doLast {
def buildType = project.selectedBuildType == "release" ? "Release" : "Debug"
def iter = []
Pattern pattern = Pattern.compile("^(.+)${buildType}CompileClasspath\$")
configurations.all{ config ->
Matcher matcher = pattern.matcher(config.name)
if (matcher.find() || config.name == "${buildType.toLowerCase()}CompileClasspath") {
config.resolve().each {
if (!iter.contains(it)) {
iter.push(it)
}
}
}
}
def dependencyCounter = 0
iter.each {
def nextDependency = it
def outputDir = java.nio.file.Paths.get(extractedDependenciesDir, "" + dependencyCounter).normalize().toString()
explodeAar(nextDependency, outputDir)
dependencyCounter++
}
}
}
task collectAllJars {
description "gathers all paths to jar dependencies before building metadata with them"
def sdkPath = android.sdkDirectory.getAbsolutePath()
def androidJar = sdkPath + "/platforms/" + android.compileSdkVersion + "/android.jar"
doFirst {
def allJarPaths = new LinkedList<String>()
allJarPaths.add(androidJar)
allJarPaths.addAll(pluginsJarLibraries)
def ft = fileTree(dir: extractedDependenciesDir, include: "**/*.jar")
ft.each { currentJarFile ->
allJarPaths.add(currentJarFile.getAbsolutePath())
}
new File("$BUILD_TOOLS_PATH/$SBG_JAVA_DEPENDENCIES").withWriter { out ->
allJarPaths.each { out.println it }
}
new File("$BUILD_TOOLS_PATH/$MDG_JAVA_DEPENDENCIES").withWriter { out ->
allJarPaths.each {
if (it.endsWith(".jar")) {
out.println it
}
}
}
new File("$BUILD_TOOLS_PATH/$SBG_INPUT_FILE").withWriter { out ->
out.println INPUT_JS_DIR
}
new File("$BUILD_TOOLS_PATH/$SBG_OUTPUT_FILE").withWriter { out ->
out.println OUTPUT_JAVA_DIR
}
allJarLibraries.addAll(allJarPaths)
}
}
task buildMetadata(type: JavaExec) {
description "builds metadata with provided jar dependencies"
inputs.files("$MDG_JAVA_DEPENDENCIES")
def classesDir = "$buildDir/intermediates/javac"
inputs.dir(classesDir)
outputs.files("$METADATA_OUT_PATH/treeNodeStream.dat", "$METADATA_OUT_PATH/treeStringsStream.dat", "$METADATA_OUT_PATH/treeValueStream.dat")
doFirst {
// get compiled classes to pass to metadata generator
// these need to be called after the classes have compiled
assert file(classesDir).exists()
def classesSubDirs = new File(classesDir).listFiles()
def selectedBuildType = project.ext.selectedBuildType
def generatedClasses = new LinkedList<String>()
for (File subDir : classesSubDirs) {
if (subDir.getName().equals(selectedBuildType)) {
generatedClasses.add(subDir.getAbsolutePath())
}
}
new File("$BUILD_TOOLS_PATH/$MDG_OUTPUT_DIR").withWriter { out ->
out.println "$METADATA_OUT_PATH"
}
new File("$BUILD_TOOLS_PATH/$MDG_JAVA_DEPENDENCIES").withWriterAppend { out ->
generatedClasses.each { out.println it }
}
workingDir "$BUILD_TOOLS_PATH"
main "-jar"
args "android-metadata-generator.jar"
}
}
task generateTypescriptDefinitions(type: JavaExec) {
def paramz = new ArrayList<String>()
def includeDirs = ["com.android.support", "/platforms/" + android.compileSdkVersion]
doFirst {
delete "$TYPINGS_PATH"
workingDir "$BUILD_TOOLS_PATH"
main "-jar"
paramz.add("dts-generator.jar")
paramz.add("-input")
for (String jarPath : allJarLibraries) {
// don't generate typings for runtime jars and classes
if (shouldIncludeDirForTypings(jarPath, includeDirs)) {
paramz.add(jarPath)
}
}
paramz.add("-output")
paramz.add("$TYPINGS_PATH")
new File("$TYPINGS_PATH").mkdirs()
logger.info("Task generateTypescriptDefinitions: Call dts-generator.jar with arguments: " + paramz.toString().replaceAll(',', ''))
println "Task generateTypescriptDefinitions: Call dts-generator.jar with arguments: " + paramz.toString().replaceAll(',', '')
args paramz.toArray()
}
}
generateTypescriptDefinitions.onlyIf {
(project.hasProperty("generateTypings") && Boolean.parseBoolean(project.generateTypings)) || PASSED_TYPINGS_PATH != null
}
collectAllJars.finalizedBy(generateTypescriptDefinitions)
static def shouldIncludeDirForTypings(path, includeDirs) {
for (String p : includeDirs) {
if (path.indexOf(p) > -1) {
return true
}
}
return false
}
task copyTypings {
doLast {
println "Copied generated typings to application root level. Make sure to import android.d.ts in reference.d.ts"
copy {
from "$TYPINGS_PATH"
into "$USER_PROJECT_ROOT"
}
}
}
copyTypings.onlyIf { generateTypescriptDefinitions.didWork }
generateTypescriptDefinitions.finalizedBy(copyTypings)
task validateAppIdMatch {
doLast {
def lineSeparator = System.getProperty("line.separator")
if (project.hasProperty("nsApplicationIdentifier") && !project.hasProperty("release")) {
if(project.nsApplicationIdentifier != android.defaultConfig.applicationId) {
def errorMessage = "${lineSeparator}WARNING: The Application identifier is different from the one inside \"package.json\" file.$lineSeparator" +
"NativeScript CLI might not work properly.$lineSeparator" +
"Remove applicationId from app.gradle and update the \"nativescript.id\" in package.json.$lineSeparator" +
"Actual: ${android.defaultConfig.applicationId}$lineSeparator" +
"Expected(from \"package.json\"): ${project.nsApplicationIdentifier}$lineSeparator";
logger.error(errorMessage)
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// OPTIONAL TASKS //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
//////// custom clean ///////////
task cleanSbg(type: Delete) {
delete "$BUILD_TOOLS_PATH/$SBG_JS_PARSED_FILES",
"$BUILD_TOOLS_PATH/$SBG_JAVA_DEPENDENCIES",
"$BUILD_TOOLS_PATH/$SBG_INTERFACE_NAMES",
"$BUILD_TOOLS_PATH/$SBG_BINDINGS_NAME",
"$BUILD_TOOLS_PATH/$SBG_INPUT_FILE",
"$BUILD_TOOLS_PATH/$SBG_OUTPUT_FILE",
"$OUTPUT_JAVA_DIR/com/tns/gen"
}
task cleanMdg(type: Delete) {
delete "$BUILD_TOOLS_PATH/$MDG_OUTPUT_DIR",
"$BUILD_TOOLS_PATH/$MDG_JAVA_DEPENDENCIES",
"$METADATA_OUT_PATH"
}
cleanSbg.dependsOn(cleanMdg)
clean.dependsOn(cleanSbg)
My package.json (root):
{
"nativescript": {
"id": "org.nativescript.nativescriptrecyclerview",
"tns-android": {
"version": "5.0.0"
},
"tns-ios": {
"version": "5.0.0"
}
},
"description": "NativeScript Application",
"license": "SEE LICENSE IN <your-license-filename>",
"repository": "<fill-your-repository-here>",
"dependencies": {
"nativescript-theme-core": "~1.0.4",
"nativescript-ui-listview": "^5.0.1",
"tns-core-modules": "~5.0.2"
},
"devDependencies": {
"nativescript-dev-webpack": "~0.18.0"
},
"readme": "NativeScript Application"
}
Android SDK Tools from Android Studio:
Edit: Unfortunately I can't confirm whether further answers works, or even respond to comments, since I'm not using NativeScript or other gradle-related projects anymore. But feel free to add your answers or comments; it might help others.
In build.gradle this is the new implementation
implementation 'androidx.recyclerview:recyclerview:1.0.0'
This is a problem from Google's Maven Repository.
Some libraries just disappears 😫
Here's the issue on the Google Issue Tracker.
Migrate your project to AndroidX using this link
Add below dependency in you app module gradle file
implementation 'androidx.appcompat:appcompat:1.0.0'
I have Android project.
And I am trying to use JaCoCo code coverage with Gradle.
This is my JaCoCo configuration:
apply plugin: 'jacoco'
project.afterEvaluate {
def buildTypes = android.buildTypes.collect { type -> type.name }
def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName -> buildTypes.each {
buildTypeName -> def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}" }
else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
task "${testTaskName}Coverage" (type:JacocoReport, dependsOn: "$testTaskName") {
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
classDirectories = fileTree(
dir: "${project.buildDir}/intermediates/classes/${sourcePath}",
excludes: [
'**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/Manifest*.*'
]
)
def coverageSourceDirs = [
"src/main/java",
"src/$productFlavorName/java",
"src/$buildTypeName/java"
]
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
reports {
xml.enabled = true
html.enabled = true
}
}
}
}
}
But it generates only .exec files, there are no xml or html.
What am I missing? Are this lines not enough?
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
reports {
xml.enabled = true
html.enabled = true
}