Test against multiple versions.

This commit is contained in:
Nick Alexander 2021-08-15 21:31:06 -07:00
Родитель 7218fcd0b0
Коммит e0245cc94a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 1C0E512189F400BE
14 изменённых файлов: 772 добавлений и 23 удалений

80
.github/workflows/check.yml поставляемый Normal file
Просмотреть файл

@ -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

2
gradle/wrapper/gradle-wrapper.properties поставляемый
Просмотреть файл

@ -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"
}