Test against multiple versions.
This commit is contained in:
Родитель
7218fcd0b0
Коммит
e0245cc94a
|
@ -0,0 +1,80 @@
|
|||
name: CI
|
||||
|
||||
# Controls when the action will run. Triggers the workflow on push or pull request
|
||||
# events but only for the master branch
|
||||
on:
|
||||
push:
|
||||
branches: [ master, citest ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
generate_versions:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Gradle test
|
||||
run: |
|
||||
./gradlew -p plugin generateTestTasksJson
|
||||
|
||||
- id: setup-matrix
|
||||
run: echo "::set-output name=matrix::$(cat plugin/build/build-resources/androidTestTasks.json)"
|
||||
|
||||
- name: debug
|
||||
run: echo ${{ steps.setup-matrix.outputs.matrix }}
|
||||
|
||||
outputs:
|
||||
matrix: ${{ steps.setup-matrix.outputs.matrix }}
|
||||
|
||||
android_version_tests:
|
||||
needs: [generate_versions] # , sanity_check]
|
||||
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
androidTestTask: ${{ fromJson(needs.generate_versions.outputs.matrix) }}
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
# # Sets up the NDK required by AGP 3.6.x
|
||||
# - name: Setup NDK
|
||||
# run: sudo $ANDROID_HOME/tools/bin/sdkmanager 'ndk;20.0.5594570'
|
||||
|
||||
# - name: Install Rustup
|
||||
# run: |
|
||||
# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none
|
||||
# echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Setup Rust
|
||||
run: |
|
||||
rustup toolchain install stable
|
||||
rustup target add x86_64-linux-android
|
||||
rustup target add x86_64-unknown-linux-gnu
|
||||
|
||||
# Use Java 8
|
||||
- name: Setup Java 8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 8
|
||||
|
||||
- name: Gradle setup
|
||||
run: |
|
||||
./gradlew -p plugin tasks --warning-mode all
|
||||
|
||||
- name: Gradle test
|
||||
run: |
|
||||
./gradlew -p plugin ${{ matrix.androidTestTask }} --tests CargoBuildTest --info --warning-mode all
|
||||
|
||||
# # Gradle build
|
||||
# - uses: eskatos/gradle-command-action@v1
|
||||
# with:
|
||||
# arguments: ${{ matrix.androidTestTask }} -I gradle/buildScanInit.gradle
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
import groovy.json.JsonBuilder
|
||||
import org.gradle.util.VersionNumber
|
||||
|
||||
plugins {
|
||||
id 'com.gradle.plugin-publish' version '0.14.0'
|
||||
id "org.gradle.test-retry" version "1.2.0"
|
||||
}
|
||||
|
||||
apply plugin: "java-gradle-plugin"
|
||||
apply plugin: "maven-publish"
|
||||
apply plugin: "groovy"
|
||||
apply plugin: "kotlin"
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
simplePlugin {
|
||||
rustAndroidGradlePlugin {
|
||||
id = 'org.mozilla.rust-android-gradle'
|
||||
implementationClass = 'com.nishtahir.RustAndroidPlugin'
|
||||
displayName = 'Plugin for building Rust with Cargo in Android projects'
|
||||
|
@ -20,26 +25,40 @@ gradlePlugin {
|
|||
group 'org.mozilla.rust-android-gradle'
|
||||
version "$plugin_version"
|
||||
|
||||
def isCI = (System.getenv('CI') ?: 'false').toBoolean()
|
||||
|
||||
// Maps supported Android plugin versions to the versions of Gradle that support it
|
||||
def supportedVersions = [
|
||||
"7.0.0": ["7.1.1"],
|
||||
"4.2.2": ["6.8.3", "7.1.1"],
|
||||
"4.1.3": ["6.5.1", "6.8.3"],
|
||||
"4.0.2": ["6.1.1", "6.8.3"],
|
||||
"3.6.4": ["5.6.4", "6.8.3"],
|
||||
"3.5.4": ["5.4.1", "5.6.4", "6.8.3"],
|
||||
"3.1.2": ["4.10.2"]
|
||||
]
|
||||
|
||||
// A local repo we publish our library to for testing in order to workaround limitations
|
||||
// in the TestKit plugin classpath.
|
||||
def localRepo = file("$buildDir/local-repo")
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
url "../samples/maven-repo"
|
||||
}
|
||||
}
|
||||
publications {
|
||||
maven(MavenPublication) {
|
||||
groupId 'org.mozilla.rust-android-gradle'
|
||||
artifactId 'rust-android'
|
||||
|
||||
from components.java
|
||||
url = localRepo.toURI()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly gradleApi()
|
||||
implementation "com.android.tools.build:gradle:$agp_version"
|
||||
// implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation gradleApi()
|
||||
compileOnly "com.android.tools.build:gradle:${agp_version}"
|
||||
|
||||
testImplementation gradleTestKit()
|
||||
testImplementation "com.android.tools.build:gradle:${agp_version}"
|
||||
testImplementation platform("org.spockframework:spock-bom:2.0-M5-groovy-3.0")
|
||||
testImplementation("org.spockframework:spock-core") { exclude group: 'org.codehaus.groovy' }
|
||||
testImplementation("org.spockframework:spock-junit4") { exclude group: 'org.codehaus.groovy' }
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
|
@ -54,12 +73,90 @@ pluginBundle {
|
|||
vcsUrl = 'https://github.com/mozilla/rust-android-gradle.git'
|
||||
tags = ['rust', 'cargo', 'android']
|
||||
|
||||
plugins {
|
||||
rustAndroidPlugin {
|
||||
id = 'org.mozilla.rust-android-gradle.rust-android'
|
||||
displayName = 'Plugin for building Rust with Cargo in Android projects'
|
||||
description = 'A plugin that helps build Rust JNI libraries with Cargo for use in Android projects.'
|
||||
tags = ['rust', 'cargo', 'android']
|
||||
}
|
||||
mavenCoordinates {
|
||||
groupId = "gradle.plugin.org.mozilla.rust-android-gradle"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Generate a json file that contains the matrix of Gradle and AGP versions to test against.
|
||||
def generatedResources = "$buildDir/generated-resources/main"
|
||||
tasks.register('generateVersions') {
|
||||
def outputFile = file("$generatedResources/versions.json")
|
||||
inputs.property "version", version
|
||||
inputs.property "supportedVersions", supportedVersions
|
||||
outputs.dir generatedResources
|
||||
doLast {
|
||||
outputFile.text = new JsonBuilder([
|
||||
version: version,
|
||||
supportedVersions: supportedVersions
|
||||
]).toPrettyString()
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
output.dir(generatedResources, builtBy: tasks.named('generateVersions'))
|
||||
}
|
||||
}
|
||||
|
||||
// This is used by github actions to split out jobs by Android version test task
|
||||
def generatedBuildResources = "$buildDir/build-resources"
|
||||
tasks.register('generateTestTasksJson') {
|
||||
def outputFile = file("${generatedBuildResources}/androidTestTasks.json")
|
||||
inputs.property "supportedVersions", supportedVersions
|
||||
outputs.dir generatedBuildResources
|
||||
doLast {
|
||||
outputFile.text = new JsonBuilder(
|
||||
// Fails in CI with issues invoking Java 11. The single test that
|
||||
// requires Java 11 succeeds. To be investigated in the future.
|
||||
// ['test'] +
|
||||
(supportedVersions.keySet().collect {androidVersion -> androidTestTaskName(androidVersion) })
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration common to all test tasks
|
||||
tasks.withType(Test).configureEach {
|
||||
dependsOn publish
|
||||
systemProperty "local.repo", localRepo.toURI()
|
||||
useJUnitPlatform()
|
||||
retry {
|
||||
maxRetries = isCI ? 1 : 0
|
||||
maxFailures = 20
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a test task for each Android version and run the tests annotated with the MultiVersionTest category
|
||||
supportedVersions.keySet().each { androidVersion ->
|
||||
def testTaskName = androidTestTaskName(androidVersion)
|
||||
def jdkVersion = jdkVersionFor(androidVersion)
|
||||
def versionSpecificTest = tasks.register(testTaskName, Test) {
|
||||
description = "Runs the multi-version tests for AGP ${androidVersion}"
|
||||
group = "verification"
|
||||
|
||||
javaLauncher = javaToolchains.launcherFor {
|
||||
languageVersion = jdkVersion
|
||||
}
|
||||
|
||||
systemProperty 'org.gradle.android.testVersion', androidVersion
|
||||
}
|
||||
|
||||
tasks.named('check').configure {
|
||||
dependsOn versionSpecificTest
|
||||
}
|
||||
}
|
||||
|
||||
static def androidTestTaskName(String androidVersion) {
|
||||
return "testAndroid${normalizeVersion(androidVersion)}"
|
||||
}
|
||||
|
||||
static def normalizeVersion(String version) {
|
||||
return version.replaceAll('[.\\-]', '_')
|
||||
}
|
||||
|
||||
static def jdkVersionFor(String version) {
|
||||
def jdkVersion = VersionNumber.parse(version) > VersionNumber.parse("7.0.0-alpha01") ? 11 : 8
|
||||
|
||||
return JavaLanguageVersion.of(jdkVersion)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package com.nishtahir
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap
|
||||
import com.google.common.collect.ImmutableSortedSet
|
||||
import com.google.common.collect.Multimap
|
||||
import groovy.json.JsonSlurper
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.TypeCheckingMode
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.gradle.util.VersionNumber
|
||||
|
||||
@CompileStatic(TypeCheckingMode.SKIP)
|
||||
class Versions {
|
||||
static final VersionNumber PLUGIN_VERSION;
|
||||
static final Set<GradleVersion> SUPPORTED_GRADLE_VERSIONS
|
||||
static final Set<VersionNumber> SUPPORTED_ANDROID_VERSIONS
|
||||
static final Multimap<VersionNumber, GradleVersion> SUPPORTED_VERSIONS_MATRIX
|
||||
|
||||
static {
|
||||
def versions = new JsonSlurper().parse(Versions.classLoader.getResource("versions.json"))
|
||||
PLUGIN_VERSION = VersionNumber.parse(versions.version)
|
||||
|
||||
def builder = ImmutableMultimap.<VersionNumber, GradleVersion>builder()
|
||||
versions.supportedVersions.each { String androidVersion, List<String> gradleVersions ->
|
||||
builder.putAll(android(androidVersion), gradleVersions.collect { gradle(it) })
|
||||
}
|
||||
def matrix = builder.build()
|
||||
|
||||
SUPPORTED_VERSIONS_MATRIX = matrix
|
||||
SUPPORTED_ANDROID_VERSIONS = ImmutableSortedSet.copyOf(matrix.keySet())
|
||||
SUPPORTED_GRADLE_VERSIONS = ImmutableSortedSet.copyOf(matrix.values())
|
||||
}
|
||||
|
||||
static VersionNumber android(String version) {
|
||||
VersionNumber.parse(version)
|
||||
}
|
||||
|
||||
static GradleVersion gradle(String version) {
|
||||
GradleVersion.version(version)
|
||||
}
|
||||
|
||||
static VersionNumber earliestMaybeSupportedAndroidVersion() {
|
||||
VersionNumber earliestSupported = SUPPORTED_ANDROID_VERSIONS.min()
|
||||
// "alpha" is lower than null
|
||||
return new VersionNumber(earliestSupported.major, earliestSupported.minor, 0, "alpha")
|
||||
}
|
||||
|
||||
static VersionNumber latestAndroidVersion() {
|
||||
return SUPPORTED_ANDROID_VERSIONS.max()
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import org.gradle.api.DefaultTask
|
|||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.DuplicatesStrategy
|
||||
import java.io.File
|
||||
import java.util.Properties
|
||||
|
||||
|
@ -254,6 +255,7 @@ open class RustAndroidPlugin : Plugin<Project> {
|
|||
}
|
||||
fileMode = 493 // 0755 in decimal; Kotlin doesn't have octal literals (!).
|
||||
includeEmptyDirs = false
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
|
||||
val buildTask = tasks.maybeCreate("cargoBuild",
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package com.nishtahir
|
||||
|
||||
import org.gradle.testkit.runner.GradleRunner
|
||||
import org.junit.Rule
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import spock.lang.Specification
|
||||
|
||||
class AbstractTest extends Specification {
|
||||
@Rule TemporaryFolder temporaryFolder
|
||||
File cacheDir
|
||||
|
||||
def setup() {
|
||||
cacheDir = temporaryFolder.newFolder()
|
||||
}
|
||||
|
||||
def withGradleVersion(String gradleVersion) {
|
||||
GradleRunner.create()
|
||||
.withGradleVersion(gradleVersion)
|
||||
.forwardOutput()
|
||||
.withDebug(false)
|
||||
}
|
||||
|
||||
File file(String path) {
|
||||
return new File(temporaryFolder.root, path)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.nishtahir
|
||||
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
import spock.lang.Unroll
|
||||
|
||||
import com.nishtahir.Versions
|
||||
|
||||
|
||||
@MultiVersionTest
|
||||
class CargoBuildTest extends AbstractTest {
|
||||
@Unroll
|
||||
def "cargoBuild is invoked with #gradleVersion and Android plugin #androidVersion"() {
|
||||
given:
|
||||
SimpleAndroidApp.builder(temporaryFolder.root, cacheDir)
|
||||
.withAndroidVersion(androidVersion)
|
||||
.withKotlinDisabled()
|
||||
// TODO: .withCargo(...)
|
||||
.build()
|
||||
.writeProject()
|
||||
|
||||
def cargoModule = this.class.classLoader.getResource("rust/Cargo.toml").path
|
||||
cargoModule = new File(cargoModule).parent
|
||||
|
||||
file('app/build.gradle') << """
|
||||
cargo {
|
||||
module = "${cargoModule}"
|
||||
targetDirectory = "${cargoModule}/../target"
|
||||
targets = ["x86_64"]
|
||||
libname = "rust"
|
||||
}
|
||||
""".stripIndent()
|
||||
|
||||
file('library/build.gradle') << """
|
||||
cargo {
|
||||
module = "${cargoModule}"
|
||||
targetDirectory = "${cargoModule}/../target"
|
||||
targets = ["x86_64"]
|
||||
libname = "rust"
|
||||
}
|
||||
""".stripIndent()
|
||||
|
||||
when:
|
||||
BuildResult buildResult = withGradleVersion(gradleVersion.version)
|
||||
.withProjectDir(temporaryFolder.root)
|
||||
.withArguments('cargoBuild', '--info', '--stacktrace')
|
||||
// .withDebug(true)
|
||||
.build()
|
||||
|
||||
// To ease debugging.
|
||||
temporaryFolder.root.eachFileRecurse {
|
||||
println(it)
|
||||
}
|
||||
|
||||
then:
|
||||
buildResult.task(':app:cargoBuild').outcome == TaskOutcome.SUCCESS
|
||||
buildResult.task(':library:cargoBuild').outcome == TaskOutcome.SUCCESS
|
||||
new File(temporaryFolder.root, "app/build/rustJniLibs/android/x86_64/librust.so").exists()
|
||||
new File(temporaryFolder.root, "library/build/rustJniLibs/android/x86_64/librust.so").exists()
|
||||
|
||||
where:
|
||||
[androidVersion, gradleVersion] << TestVersions.allCandidateTestVersions.entries().collect { [it.key, it.value] }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.nishtahir
|
||||
|
||||
import java.lang.annotation.ElementType
|
||||
import java.lang.annotation.Inherited
|
||||
import java.lang.annotation.Retention
|
||||
import java.lang.annotation.RetentionPolicy
|
||||
import java.lang.annotation.Target
|
||||
|
||||
/**
|
||||
* Represents tests that span multiple versions of Android Gradle Plugin and need to be executed
|
||||
* with multiple versions of the JDK.
|
||||
*/
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@interface MultiVersionTest { }
|
|
@ -0,0 +1,321 @@
|
|||
package com.nishtahir
|
||||
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.util.VersionNumber
|
||||
|
||||
import static com.nishtahir.Versions.android
|
||||
|
||||
class SimpleAndroidApp {
|
||||
final File projectDir
|
||||
private final File cacheDir
|
||||
final VersionNumber androidVersion
|
||||
final VersionNumber kotlinVersion
|
||||
private final boolean kotlinEnabled
|
||||
private final boolean kaptWorkersEnabled
|
||||
|
||||
private SimpleAndroidApp(File projectDir, File cacheDir, VersionNumber androidVersion, VersionNumber kotlinVersion, boolean kotlinEnabled, boolean kaptWorkersEnabled) {
|
||||
this.projectDir = projectDir
|
||||
this.cacheDir = cacheDir
|
||||
this.androidVersion = androidVersion
|
||||
this.kotlinVersion = kotlinVersion
|
||||
this.kotlinEnabled = kotlinEnabled
|
||||
this.kaptWorkersEnabled = kaptWorkersEnabled
|
||||
}
|
||||
|
||||
def writeProject() {
|
||||
def app = 'app'
|
||||
def appPackage = 'org.gradle.android.example.app'
|
||||
def appActivity = 'AppActivity'
|
||||
|
||||
def library = 'library'
|
||||
def libPackage = 'org.gradle.android.example.library'
|
||||
def libraryActivity = 'LibraryActivity'
|
||||
|
||||
file("settings.gradle") << """
|
||||
buildCache {
|
||||
local {
|
||||
directory = "${cacheDir.absolutePath.replace(File.separatorChar, '/' as char)}"
|
||||
}
|
||||
}
|
||||
""".stripIndent()
|
||||
|
||||
file("build.gradle") << """
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = "${System.getProperty("local.repo")}"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath ('com.android.tools.build:gradle:$androidVersion') { force = true }
|
||||
classpath "org.mozilla.rust-android-gradle:plugin:${Versions.PLUGIN_VERSION}"
|
||||
${kotlinPluginDependencyIfEnabled}
|
||||
}
|
||||
}
|
||||
""".stripIndent()
|
||||
|
||||
writeActivity(library, libPackage, libraryActivity)
|
||||
file("${library}/src/main/AndroidManifest.xml") << """<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="${libPackage}">
|
||||
</manifest>
|
||||
""".stripIndent()
|
||||
|
||||
writeActivity(app, appPackage, appActivity)
|
||||
file("${app}/src/main/AndroidManifest.xml") << """<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="${appPackage}">
|
||||
|
||||
<application android:label="@string/app_name" >
|
||||
<activity
|
||||
android:name=".${appActivity}"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="${libPackage}.${libraryActivity}">
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
""".stripIndent()
|
||||
file("${app}/src/main/res/values/strings.xml") << '''<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Android Gradle</string>
|
||||
</resources>'''.stripIndent()
|
||||
|
||||
file('settings.gradle') << """
|
||||
include ':${app}'
|
||||
include ':${library}'
|
||||
""".stripIndent()
|
||||
|
||||
file("${app}/build.gradle") << subprojectConfiguration("com.android.application") << """
|
||||
android.defaultConfig.applicationId "org.gradle.android.test.app"
|
||||
""".stripIndent() << activityDependency() <<
|
||||
"""
|
||||
dependencies {
|
||||
implementation project(':${library}')
|
||||
}
|
||||
""".stripIndent()
|
||||
|
||||
file("${library}/build.gradle") << subprojectConfiguration("com.android.library") << activityDependency()
|
||||
|
||||
file("gradle.properties") << """
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
kapt.use.worker.api=${kaptWorkersEnabled}
|
||||
""".stripIndent()
|
||||
|
||||
configureAndroidSdkHome()
|
||||
}
|
||||
|
||||
private String getKotlinPluginDependencyIfEnabled() {
|
||||
return kotlinEnabled ? """
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}"
|
||||
""" : ""
|
||||
}
|
||||
|
||||
private subprojectConfiguration(String androidPlugin) {
|
||||
"""
|
||||
apply plugin: "$androidPlugin"
|
||||
${kotlinPluginsIfEnabled}
|
||||
apply plugin: "org.mozilla.rust-android-gradle.rust-android"
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
${kotlinDependenciesIfEnabled}
|
||||
}
|
||||
|
||||
android {
|
||||
${ndkVersion}
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "29.0.3"
|
||||
defaultConfig {
|
||||
minSdkVersion 28
|
||||
targetSdkVersion 28
|
||||
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
}
|
||||
}
|
||||
}
|
||||
""".stripIndent()
|
||||
}
|
||||
|
||||
private String getNdkVersion() {
|
||||
def isAndroid34x = androidVersion >= android("3.4.0")
|
||||
if (isAndroid34x) {
|
||||
return """ndkVersion '21.4.7075529'"""
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
private String getKotlinPluginsIfEnabled() {
|
||||
return kotlinEnabled ? """
|
||||
apply plugin: "kotlin-android"
|
||||
apply plugin: "kotlin-kapt"
|
||||
""" : ""
|
||||
}
|
||||
|
||||
private String getKotlinDependenciesIfEnabled() {
|
||||
return kotlinEnabled ? """
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
||||
""" : ""
|
||||
}
|
||||
|
||||
private writeActivity(String basedir, String packageName, String className) {
|
||||
String resourceName = className.toLowerCase()
|
||||
|
||||
file("${basedir}/src/main/java/${packageName.replaceAll('\\.', '/')}/${className}.java") << """
|
||||
package ${packageName};
|
||||
|
||||
import org.joda.time.LocalTime;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class ${className} extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.${resourceName}_layout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
LocalTime currentTime = new LocalTime();
|
||||
TextView textView = (TextView) findViewById(R.id.text_view);
|
||||
textView.setText("The current local time is: " + currentTime);
|
||||
}
|
||||
}
|
||||
""".stripIndent()
|
||||
|
||||
file("${basedir}/src/test/java/${packageName.replaceAll('\\.', '/')}/JavaUserTest.java") << """
|
||||
package ${packageName};
|
||||
|
||||
public class JavaUserTest {
|
||||
}
|
||||
""".stripIndent()
|
||||
|
||||
file("${basedir}/src/main/res/layout/${resourceName}_layout.xml") << '''<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
</LinearLayout>
|
||||
'''.stripIndent()
|
||||
|
||||
file("${basedir}/src/main/rs/${resourceName}.rs") << '''
|
||||
#pragma version(1)
|
||||
#pragma rs java_package_name(com.example.myapplication)
|
||||
|
||||
static void addintAccum(int *accum, int val) {
|
||||
*accum += val;
|
||||
}
|
||||
'''.stripIndent()
|
||||
}
|
||||
|
||||
private static String activityDependency() {
|
||||
"""
|
||||
dependencies {
|
||||
implementation 'joda-time:joda-time:2.7'
|
||||
}
|
||||
""".stripIndent()
|
||||
}
|
||||
|
||||
private void configureAndroidSdkHome() {
|
||||
file('local.properties').text = ""
|
||||
def env = System.getenv("ANDROID_HOME")
|
||||
if (!env) {
|
||||
def androidSdkHome = new File("${System.getProperty("user.home")}/Library/Android/sdk")
|
||||
file('local.properties').text += "sdk.dir=${androidSdkHome.absolutePath.replace(File.separatorChar, '/' as char)}"
|
||||
}
|
||||
// def env = System.getenv("ANDROID_NDK_HOME")
|
||||
// if (!env) {
|
||||
// def androidNdkHome = new File("${System.getProperty("user.home")}/Library/Android/sdk")
|
||||
// file('local.properties').text += "sdk.dir=${androidSdkHome.absolutePath.replace(File.separatorChar, '/' as char)}"
|
||||
// }
|
||||
}
|
||||
|
||||
def file(String path) {
|
||||
def file = new File(projectDir, path)
|
||||
file.parentFile.mkdirs()
|
||||
return file
|
||||
}
|
||||
|
||||
static Builder builder(File projectDir, File cacheDir) {
|
||||
return new Builder(projectDir, cacheDir)
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
boolean kotlinEnabled = true
|
||||
boolean kaptWorkersEnabled = true
|
||||
|
||||
VersionNumber androidVersion = Versions.latestAndroidVersion()
|
||||
VersionNumber kotlinVersion = VersionNumber.parse("1.3.72")
|
||||
File projectDir
|
||||
File cacheDir
|
||||
|
||||
Builder(File projectDir, File cacheDir) {
|
||||
this.projectDir = projectDir
|
||||
this.cacheDir = cacheDir
|
||||
}
|
||||
|
||||
Builder withKotlinDisabled() {
|
||||
this.kotlinEnabled = false
|
||||
return this
|
||||
}
|
||||
|
||||
Builder withKotlinVersion(VersionNumber kotlinVersion) {
|
||||
this.kotlinVersion = kotlinVersion
|
||||
return this
|
||||
}
|
||||
|
||||
Builder withKaptWorkersDisabled() {
|
||||
this.kaptWorkersEnabled = false
|
||||
return this
|
||||
}
|
||||
|
||||
Builder withAndroidVersion(VersionNumber androidVersion) {
|
||||
this.androidVersion = androidVersion
|
||||
return this
|
||||
}
|
||||
|
||||
Builder withAndroidVersion(String androidVersion) {
|
||||
return withAndroidVersion(android(androidVersion))
|
||||
}
|
||||
|
||||
Builder withProjectDir(File projectDir) {
|
||||
this.projectDir = projectDir
|
||||
return this
|
||||
}
|
||||
|
||||
Builder withCacheDir(File cacheDir) {
|
||||
this.cacheDir = cacheDir
|
||||
return this
|
||||
}
|
||||
|
||||
SimpleAndroidApp build() {
|
||||
return new SimpleAndroidApp(projectDir, cacheDir, androidVersion, kotlinVersion, kotlinEnabled, kaptWorkersEnabled)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.nishtahir
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap
|
||||
import com.google.common.collect.Multimap
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.gradle.util.VersionNumber
|
||||
|
||||
|
||||
class TestVersions {
|
||||
static Multimap<VersionNumber, GradleVersion> getAllCandidateTestVersions() {
|
||||
def testedVersion = System.getProperty('org.gradle.android.testVersion')
|
||||
if (testedVersion) {
|
||||
return ImmutableMultimap.copyOf(Versions.SUPPORTED_VERSIONS_MATRIX.entries().findAll {it.key == VersionNumber.parse(testedVersion) })
|
||||
} else {
|
||||
return Versions.SUPPORTED_VERSIONS_MATRIX
|
||||
}
|
||||
}
|
||||
|
||||
static VersionNumber latestAndroidVersionForCurrentJDK() {
|
||||
return allCandidateTestVersions.keySet().max()
|
||||
}
|
||||
|
||||
static GradleVersion latestGradleVersion() {
|
||||
return allCandidateTestVersions.values().max()
|
||||
}
|
||||
|
||||
static GradleVersion latestSupportedGradleVersionFor(String androidVersion) {
|
||||
return latestSupportedGradleVersionFor(VersionNumber.parse(androidVersion))
|
||||
}
|
||||
|
||||
static GradleVersion latestSupportedGradleVersionFor(VersionNumber androidVersion) {
|
||||
return allCandidateTestVersions.asMap().find {it.key.major == androidVersion.major && it.key.minor == androidVersion.minor }?.value?.max()
|
||||
}
|
||||
|
||||
static VersionNumber getLatestVersionForAndroid(String version) {
|
||||
VersionNumber versionNumber = VersionNumber.parse(version)
|
||||
return allCandidateTestVersions.keySet().findAll { it.major == versionNumber.major && it.minor == versionNumber.minor }?.max()
|
||||
}
|
||||
|
||||
static List<VersionNumber> getLatestAndroidVersions() {
|
||||
def minorVersions = allCandidateTestVersions.keySet().collect { "${it.major}.${it.minor}" }
|
||||
return minorVersions.collect { getLatestVersionForAndroid(it) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
[build]
|
||||
target-dir = "../target"
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "rust"
|
||||
version = "0.2.0"
|
||||
authors = ["Nick Alexander <nalexander@mozilla.com>"]
|
||||
|
||||
[dependencies]
|
||||
jni = "0.5.2"
|
||||
|
||||
[lib]
|
||||
crate_type = ["staticlib", "dylib"]
|
||||
|
||||
[features]
|
||||
default = ["foo"]
|
||||
foo = []
|
||||
bar = []
|
|
@ -0,0 +1,30 @@
|
|||
extern crate jni;
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
use jni::JNIEnv;
|
||||
use jni::objects::{JClass, JObject, JValue};
|
||||
|
||||
pub type Callback = unsafe extern "C" fn(*const c_char) -> ();
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
pub extern "C" fn invokeCallbackViaJNA(callback: Callback) {
|
||||
let s = CString::new("Hello from Rust").unwrap();
|
||||
unsafe { callback(s.as_ptr()); }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
pub extern "C" fn Java_com_nishtahir_androidrust_MainActivity_invokeCallbackViaJNI(
|
||||
env: JNIEnv,
|
||||
_class: JClass,
|
||||
callback: JObject
|
||||
) {
|
||||
let s = String::from("Hello from Rust");
|
||||
let response = env.new_string(&s)
|
||||
.expect("Couldn't create java string!");
|
||||
env.call_method(callback, "callback", "(Ljava/lang/String;)V",
|
||||
&[JValue::from(JObject::from(response))]).unwrap();
|
||||
}
|
|
@ -31,7 +31,7 @@ android {
|
|||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
ndkVersion "20.1.5948944"
|
||||
ndkVersion "22.1.7171670"
|
||||
sourceSets {
|
||||
test.resources.srcDirs += "$buildDir/rustJniLibs/desktop"
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ android {
|
|||
|
||||
cargo {
|
||||
module = "../rust"
|
||||
targets = ["x86_64", "darwin"] // "x86", "x86_64", "arm64"]
|
||||
targets = ["x86_64", "linux-x86-64"] // "x86", "x86_64", "arm64"]
|
||||
libname = "rust"
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче