diff --git a/build.gradle b/build.gradle index cefee7f..577a864 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,9 @@ +plugins { + id 'de.undercouch.download' +} + + + allprojects { apply plugin: 'maven' diff --git a/buildSrc/.gitignore b/buildSrc/.gitignore new file mode 100644 index 0000000..da88288 --- /dev/null +++ b/buildSrc/.gitignore @@ -0,0 +1 @@ +/.gradle/ diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 0000000..9471c52 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,7 @@ +repositories { + mavenCentral() +} + +dependencies { + compile 'de.undercouch:gradle-download-task:3.4.3' +} diff --git a/buildSrc/src/main/groovy/package-list.groovy b/buildSrc/src/main/groovy/package-list.groovy new file mode 100644 index 0000000..420eb95 --- /dev/null +++ b/buildSrc/src/main/groovy/package-list.groovy @@ -0,0 +1,31 @@ +import org.gradle.api.tasks.* + + +//////////////////////////////////////////////////////////////////////// +// +// create a Javadoc-style "package-list" file +// + +@CacheableTask +class CreatePackageList extends org.gradle.api.DefaultTask { + + @PathSensitive(PathSensitivity.RELATIVE) + @Input Object sourceSet + + @OutputFile File packageList = new File("$temporaryDir/package-list") + + @TaskAction + def create() { + sourceSet.sourceCollections.collect { collection -> + def sourceRoot = collection.tree.dir.toPath() + collection.collect { source -> + def javaSourceFilePath = source.toPath() + def parentPath = javaSourceFilePath.parent + def relativePath = sourceRoot.relativize(parentPath) + relativePath.toString().replace(File.separator, '.') + } + }.flatten().sort().unique().each { + packageList << "$it\n" + } + } +} diff --git a/buildSrc/src/main/groovy/verified-download.groovy b/buildSrc/src/main/groovy/verified-download.groovy new file mode 100644 index 0000000..791c8b6 --- /dev/null +++ b/buildSrc/src/main/groovy/verified-download.groovy @@ -0,0 +1,53 @@ +import org.gradle.api.tasks.* + + +//////////////////////////////////////////////////////////////////////// +// +// download and use checksum to verify that we got what we expected +// + +@CacheableTask +class VerifiedDownload extends org.gradle.api.DefaultTask { + + // URL of resource to download + def @Input src + + // expected checksum of resource as hex digits + def @Input checksum + + // algorithm to use for computing checksum + def @Input algorithm = 'MD5' + + // whether to use ETag for selective downloading + def @Input useETag = true + + // local file into which resource should be saved + def @OutputFile dest + + File getDest() { + return project.file(dest) + } + + VerifiedDownload() { + outputs.upToDateWhen { + getDest().exists() + } + } + + @TaskAction + downloadAndVerify() { + def destFile = getDest() + project.download { + src this.src + dest destFile + overwrite true + onlyIfModified true + useETag this.useETag + } + project.verifyChecksum { + src destFile + algorithm this.algorithm + checksum this.checksum + } + } +} diff --git a/com.logicalhacking.dasca.crosslanguage.test/build.gradle b/com.logicalhacking.dasca.crosslanguage.test/build.gradle index 0b1a6a1..fdc5be7 100644 --- a/com.logicalhacking.dasca.crosslanguage.test/build.gradle +++ b/com.logicalhacking.dasca.crosslanguage.test/build.gradle @@ -1,6 +1,80 @@ apply plugin: 'scala' description = 'com.logicalhacking.dasca.crosslanguage.test' + +def osName = System.getProperty('os.name') +ext.isWindows = osName.startsWith('Windows ') + +task downloadAndroidSdk(type: VerifiedDownload) { + def sdkOs + switch (osName) { + case ~/Linux/: + sdkOs = 'linux' + checksum '444e22ce8ca0f67353bda4b85175ed3731cae3ffa695ca18119cbacef1c1bea0' + break + case ~/Mac OS X/: + sdkOs = 'darwin' + checksum '4a81754a760fce88cba74d69c364b05b31c53d57b26f9f82355c61d5fe4b9df9' + break + case ~/Windows.*/: + sdkOs = 'windows' + checksum '7f6037d3a7d6789b4fdc06ee7af041e071e9860c51f66f7a4eb5913df9871fd2' + break + } + def archive = "sdk-tools-$sdkOs-3859397.zip" + src "https://dl.google.com/android/repository/$archive" + dest "$temporaryDir/$archive" + algorithm 'SHA-256' +} + +task installAndroidSdk(type: Sync, dependsOn: downloadAndroidSdk) { + from zipTree(downloadAndroidSdk.dest) + into temporaryDir + + def buildToolsVersion = '26.0.2' + ext { + components = [ + 'build-tools': buildToolsVersion, + 'platforms': "android-${buildToolsVersion.tokenize('.')[0]}" + ] + } + + doLast { + exec { + def shell, shellFlags, yes, semicolon, discard + if (project.isWindows) { + shell = 'PowerShell' + shellFlags = '-Command' + yes = 'echo y' + semicolon = '`;' + discard = '$null' + } else { + shell = 'sh' + shellFlags = '-ceu' + yes = 'yes 2>/dev/null' + semicolon = /\;/ + discard = '/dev/null' + } + + def componentArgs = components.collect { "$it.key$semicolon$it.value" }.join ' ' + commandLine shell, shellFlags, "$yes | $temporaryDir/tools/bin/sdkmanager $componentArgs >$discard" + } + } + outputs.cacheIf { true } +} + +task copyAndroidJar(type: Sync, dependsOn: installAndroidSdk) { + from "${installAndroidSdk.destinationDir}/platforms/${installAndroidSdk.components['platforms']}/android.jar" + into temporaryDir +} + +processResources { + with copySpec { + from copyAndroidJar + rename { "android-dasca.jar" } + } +} + dependencies { implementation group: 'org.scala-lang', name: 'scala-library', version:'2.12.3' implementation group: 'junit', name: 'junit', version: '4.12' @@ -22,3 +96,5 @@ dependencies { testRuntime group: 'com.typesafe.scala-logging', name: 'scala-logging_2.12', version: '3.5.0' testRuntime group: 'apktool', name: 'apktool', version:'2.3.0' } + + diff --git a/com.logicalhacking.dasca.crosslanguage/src/main/scala/com/logicalhacking/dasca/crosslanguage/builder/CordovaCGBuilder.scala b/com.logicalhacking.dasca.crosslanguage/src/main/scala/com/logicalhacking/dasca/crosslanguage/builder/CordovaCGBuilder.scala index 0dfc681..2bbcda3 100644 --- a/com.logicalhacking.dasca.crosslanguage/src/main/scala/com/logicalhacking/dasca/crosslanguage/builder/CordovaCGBuilder.scala +++ b/com.logicalhacking.dasca.crosslanguage/src/main/scala/com/logicalhacking/dasca/crosslanguage/builder/CordovaCGBuilder.scala @@ -159,13 +159,14 @@ class CordovaCGBuilder(val apk: File, val apkUnzipDir: File) { } private def createJavaCallGraph = { - val tmpAndroidJar = File.createTempFile("android", "jar") + val tmpAndroidJar = File.createTempFile("android-dasca", ".jar") tmpAndroidJar.deleteOnExit() - if (null != getClass.getClassLoader.getResource("android19.jar")){ - TemporaryFile.urlToFile(tmpAndroidJar, getClass.getClassLoader.getResource("android19.jar")) + if (null != getClass.getClassLoader.getResource("android-dasca.jar")){ + TemporaryFile.urlToFile(tmpAndroidJar, getClass.getClassLoader.getResource("android-dasca.jar")) }else{ - logger.error("Please install android19.jar."); - throw new FileNotFoundException("Please install android19.jar."); + val msg = "Please install android-dasca.jar in resources directory." + logger.error(msg); + throw new FileNotFoundException(msg); } val scope = AndroidAnalysisScope.setUpAndroidAnalysisScope(apk.toURI(), getClass.getClassLoader.getResource("javaexclusions.txt").getFile, CordovaCGBuilder.getClass.getClassLoader()) scope.addToScope(ClassLoaderReference.Primordial, new JarFileModule(new JarFile(tmpAndroidJar)))