├── .github
├── CODEOWNERS
└── workflows
│ └── android-ci.yaml
├── sample
├── java
│ ├── app
│ │ ├── .gitignore
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── values
│ │ │ │ │ │ ├── strings.xml
│ │ │ │ │ │ ├── colors.xml
│ │ │ │ │ │ └── themes.xml
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── values-night
│ │ │ │ │ │ └── themes.xml
│ │ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ │ ├── xml
│ │ │ │ │ │ ├── backup_rules.xml
│ │ │ │ │ │ └── data_extraction_rules.xml
│ │ │ │ │ ├── layout
│ │ │ │ │ │ └── activity_main.xml
│ │ │ │ │ └── drawable
│ │ │ │ │ │ ├── ic_launcher_foreground.xml
│ │ │ │ │ │ └── ic_launcher_background.xml
│ │ │ │ ├── rust
│ │ │ │ │ ├── Cargo.toml
│ │ │ │ │ ├── src
│ │ │ │ │ │ └── lib.rs
│ │ │ │ │ └── .cargo
│ │ │ │ │ │ └── config.toml
│ │ │ │ ├── java
│ │ │ │ │ └── com
│ │ │ │ │ │ └── devfigas
│ │ │ │ │ │ └── rustjni
│ │ │ │ │ │ └── sample
│ │ │ │ │ │ └── MainActivity.java
│ │ │ │ └── AndroidManifest.xml
│ │ │ ├── test
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── devfigas
│ │ │ │ │ └── rustjni
│ │ │ │ │ └── sample
│ │ │ │ │ └── ExampleUnitTest.kt
│ │ │ └── androidTest
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── devfigas
│ │ │ │ └── rustjni
│ │ │ │ └── sample
│ │ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── proguard-rules.pro
│ │ └── build.gradle.kts
│ ├── gradle
│ │ ├── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ └── libs.versions.toml
│ ├── build.gradle.kts
│ ├── .gitignore
│ ├── settings.gradle.kts
│ ├── gradle.properties
│ ├── gradlew.bat
│ └── gradlew
├── kotlin
│ ├── app
│ │ ├── .gitignore
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── values
│ │ │ │ │ │ ├── strings.xml
│ │ │ │ │ │ ├── colors.xml
│ │ │ │ │ │ └── themes.xml
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── values-night
│ │ │ │ │ │ └── themes.xml
│ │ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ │ ├── xml
│ │ │ │ │ │ ├── backup_rules.xml
│ │ │ │ │ │ └── data_extraction_rules.xml
│ │ │ │ │ ├── layout
│ │ │ │ │ │ └── activity_main.xml
│ │ │ │ │ └── drawable
│ │ │ │ │ │ ├── ic_launcher_foreground.xml
│ │ │ │ │ │ └── ic_launcher_background.xml
│ │ │ │ ├── rust
│ │ │ │ │ ├── Cargo.toml
│ │ │ │ │ ├── src
│ │ │ │ │ │ └── lib.rs
│ │ │ │ │ └── .cargo
│ │ │ │ │ │ └── config.toml
│ │ │ │ ├── java
│ │ │ │ │ └── com
│ │ │ │ │ │ └── devfigas
│ │ │ │ │ │ └── rustjni
│ │ │ │ │ │ └── sample
│ │ │ │ │ │ └── MainActivity.kt
│ │ │ │ └── AndroidManifest.xml
│ │ │ ├── test
│ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── devfigas
│ │ │ │ │ └── rustjni
│ │ │ │ │ └── sample
│ │ │ │ │ └── ExampleUnitTest.kt
│ │ │ └── androidTest
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── devfigas
│ │ │ │ └── rustjni
│ │ │ │ └── sample
│ │ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── proguard-rules.pro
│ │ └── build.gradle.kts
│ ├── gradle
│ │ ├── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ └── libs.versions.toml
│ ├── build.gradle.kts
│ ├── .gitignore
│ ├── settings.gradle.kts
│ ├── gradle.properties
│ ├── gradlew.bat
│ └── gradlew
└── game
│ ├── app
│ ├── src
│ │ ├── main
│ │ │ ├── rust
│ │ │ │ ├── .gitignore
│ │ │ │ ├── src
│ │ │ │ │ ├── player_state.rs
│ │ │ │ │ ├── lib.rs
│ │ │ │ │ └── game_controller.rs
│ │ │ │ ├── Cargo.toml
│ │ │ │ └── .cargo
│ │ │ │ │ └── config.toml
│ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ └── themes.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── drawable
│ │ │ │ │ ├── baseline_play_arrow_24.xml
│ │ │ │ │ ├── baseline_file_upload_24.xml
│ │ │ │ │ ├── ic_launcher_foreground.xml
│ │ │ │ │ └── ic_launcher_background.xml
│ │ │ │ ├── values-night
│ │ │ │ │ └── themes.xml
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ ├── xml
│ │ │ │ │ ├── backup_rules.xml
│ │ │ │ │ └── data_extraction_rules.xml
│ │ │ │ └── layout
│ │ │ │ │ └── activity_main.xml
│ │ │ ├── assets
│ │ │ │ ├── enemy.png
│ │ │ │ └── player.png
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── devfigas
│ │ │ │ │ └── gamesample
│ │ │ │ │ ├── GameListener.kt
│ │ │ │ │ ├── NativeLib.kt
│ │ │ │ │ ├── Sprite.kt
│ │ │ │ │ ├── MainActivity.kt
│ │ │ │ │ └── GameSurfaceView.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── devfigas
│ │ │ │ └── gamesample
│ │ │ │ └── ExampleUnitTest.kt
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── devfigas
│ │ │ └── gamesample
│ │ │ └── ExampleInstrumentedTest.kt
│ ├── proguard-rules.pro
│ └── build.gradle.kts
│ ├── gradle
│ ├── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ └── libs.versions.toml
│ ├── build.gradle.kts
│ ├── settings.gradle.kts
│ ├── gradle.properties
│ ├── gradlew.bat
│ └── gradlew
├── gradle-plugin
├── settings.gradle.kts
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── src
│ └── main
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── andrefigas
│ │ └── rustjni
│ │ ├── reflection
│ │ ├── MethodSignature.kt
│ │ ├── Visibility.kt
│ │ └── primitive
│ │ │ ├── PrimitiveJVM.kt
│ │ │ └── PrimitiveRust.kt
│ │ ├── Prebuilt.kt
│ │ ├── ArchitectureConfig.kt
│ │ ├── AndroidTarget.kt
│ │ ├── OSHelper.kt
│ │ ├── AndroidSettings.kt
│ │ ├── utils
│ │ └── FileUtils.kt
│ │ └── RustJniExtension.kt
├── build.gradle.kts
├── gradlew.bat
└── gradlew
├── gradle-plugin-test
├── settings.gradle.kts
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── src
│ └── main
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── andrefigas
│ │ └── rustjni
│ │ └── test
│ │ ├── RustJNITest.kt
│ │ ├── jvm
│ │ └── content
│ │ │ ├── JVMContentProvider.kt
│ │ │ ├── KotlinContentProvider.kt
│ │ │ └── JavaContentProvider.kt
│ │ ├── toml
│ │ └── TomlContentProvider.kt
│ │ ├── TestData.kt
│ │ └── TestRunner.kt
├── gradlew.bat
├── build.gradle.kts
└── gradlew
├── .gitattributes
├── doc
├── images
│ └── kt_to_cpp.png
└── CHANGELOG.md
├── .gitignore
└── README.md
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @andrefigas
--------------------------------------------------------------------------------
/sample/java/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/sample/kotlin/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/sample/game/app/src/main/rust/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 |
--------------------------------------------------------------------------------
/gradle-plugin/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "RustJNI"
--------------------------------------------------------------------------------
/gradle-plugin-test/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "RustJNI"
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/doc/images/kt_to_cpp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/doc/images/kt_to_cpp.png
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | sample
3 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | GameSample
3 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | sample
3 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/assets/enemy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/assets/enemy.png
--------------------------------------------------------------------------------
/sample/game/app/src/main/assets/player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/assets/player.png
--------------------------------------------------------------------------------
/sample/game/app/src/main/rust/src/player_state.rs:
--------------------------------------------------------------------------------
1 | #[derive(Debug, PartialEq)]
2 | pub enum PlayerState {
3 | Live,
4 | Dead
5 | }
--------------------------------------------------------------------------------
/gradle-plugin/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/gradle-plugin/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/sample/game/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/sample/java/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/sample/kotlin/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle-plugin-test/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/gradle-plugin-test/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/game/app/src/main/java/com/devfigas/gamesample/GameListener.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.gamesample
2 |
3 | interface GameListener {
4 |
5 | fun onGameEnd()
6 |
7 | }
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/game/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/java/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andrefigas/RustJNI/HEAD/sample/kotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF000000
4 | #FFFFFFFF
5 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF000000
4 | #FFFFFFFF
5 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/rust/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "my_rust_lib"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [lib]
7 | crate-type = ["cdylib"]
8 |
9 | [dependencies]
10 | jni = "0.21"
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF000000
4 | #FFFFFFFF
5 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/rust/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "my_rust_lib"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [lib]
7 | crate-type = ["cdylib"]
8 |
9 | [dependencies]
10 | jni = "0.21"
--------------------------------------------------------------------------------
/sample/game/app/src/main/rust/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "my_rust_lib"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [lib]
7 | crate-type = ["cdylib"]
8 |
9 | [dependencies]
10 | jni = "0.21"
11 | lazy_static = "1.4"
--------------------------------------------------------------------------------
/sample/game/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | alias(libs.plugins.android.application) apply false
4 | alias(libs.plugins.kotlin.android) apply false
5 | }
--------------------------------------------------------------------------------
/sample/kotlin/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {alias(libs.plugins.android.application) apply false
3 | alias(libs.plugins.jetbrains.kotlin.android) apply false
4 | }
--------------------------------------------------------------------------------
/sample/java/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | alias(libs.plugins.android.application) apply false
4 | alias(libs.plugins.jetbrains.kotlin.android) apply false
5 | }
--------------------------------------------------------------------------------
/gradle-plugin-test/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/reflection/MethodSignature.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.reflection
2 |
3 | internal data class MethodSignature(
4 | val methodName: String,
5 | val returnType: String,
6 | val parameters: List
7 | )
--------------------------------------------------------------------------------
/gradle-plugin/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Oct 23 10:55:23 EDT 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/sample/game/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Nov 02 21:28:05 WET 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/sample/java/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 05 01:38:14 BST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/sample/kotlin/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 05 01:38:14 BST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/sample/java/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/sample/kotlin/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/drawable/baseline_play_arrow_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/Prebuilt.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni
2 |
3 | object Prebuilt{
4 |
5 | const val LINUX_X86_64 = "linux-x86_64"
6 | const val LINUX_ARM64 = "linux-arm64"
7 | const val WINDOWS_X86_64 = "windows-x86_64"
8 | const val WINDOWS_ARM64 = "windows-arm64"
9 | const val DARWIN_X86_64 = "darwin-x86_64"
10 |
11 | }
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/drawable/baseline_file_upload_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/game/app/src/test/java/com/devfigas/gamesample/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.gamesample
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/sample/java/app/src/test/java/com/devfigas/rustjni/sample/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.rustjni.sample
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/ArchitectureConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni
2 |
3 | import io.github.andrefigas.rustjni.OSHelper.isWindows
4 |
5 | data class ArchitectureConfig(val target : String,
6 | val linker: String,
7 | val ar: String = DEFAULT_AR
8 | ){
9 |
10 | companion object {
11 |
12 | val DEFAULT_AR = if (isWindows()) "llvm-ar.exe" else "llvm-ar"
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/sample/kotlin/app/src/test/java/com/devfigas/rustjni/sample/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.rustjni.sample
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gradle
2 | .gradle/
3 | **/build/
4 | **/out/
5 |
6 | # IntelliJ IDEA
7 | **/.idea/
8 | *.iws
9 | *.iml
10 | *.ipr
11 |
12 | # Android/Gradle specific
13 | **/local.properties
14 | **/.gradle/
15 | **/build/
16 |
17 | # Eclipse
18 | .classpath
19 | .project
20 | .settings/
21 | **/bin/
22 |
23 | # NetBeans
24 | /nbproject/private/
25 | /nbbuild/
26 | /dist/
27 | /nbdist/
28 | /.nb-gradle/
29 |
30 | # VS Code
31 | .vscode/
32 |
33 | # Mac OS
34 | .DS_Store
35 |
36 | # Rust specific
37 | **/rust/target/
38 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/rust/src/lib.rs:
--------------------------------------------------------------------------------
1 | use jni::objects::JClass;
2 | use jni::JNIEnv;
3 | //
4 | // primitive imports
5 | use jni::sys::jstring;
6 | //
7 | #[no_mangle]
8 | pub extern "C" fn Java_com_devfigas_rustjni_sample_MainActivity_sayHello(
9 | env: JNIEnv,
10 | _class: JClass,
11 | ) -> jstring {
12 | println!("Parameters: {:?}", ());
13 |
14 | let output = r#"Rust Method: sayHello"#;
15 | env.new_string(output)
16 | .expect("Couldn't create Java string!")
17 | .into_raw()
18 | }
19 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/AndroidTarget.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni
2 |
3 | object AndroidTarget {
4 | const val ARMV7_LINUX_ANDROIDEABI = "armv7-linux-androideabi"
5 | const val AARCH64_LINUX_ANDROID = "aarch64-linux-android"
6 | const val I686_LINUX_ANDROID = "i686-linux-android"
7 | const val X86_64_LINUX_ANDROID = "x86_64-linux-android"
8 |
9 | val ALL = listOf(
10 | ARMV7_LINUX_ANDROIDEABI,
11 | AARCH64_LINUX_ANDROID,
12 | I686_LINUX_ANDROID,
13 | X86_64_LINUX_ANDROID
14 | )
15 | }
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/java/com/devfigas/rustjni/sample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.rustjni.sample
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 |
6 |
7 | class MainActivity : AppCompatActivity() {
8 |
9 | //
10 | // auto-generated code
11 |
12 | private external fun sayHello(): String
13 |
14 | init { System.loadLibrary("my_rust_lib") }
15 |
16 | //
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | setContentView(R.layout.activity_main)
21 | }
22 | }
--------------------------------------------------------------------------------
/sample/java/app/src/main/java/com/devfigas/rustjni/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.devfigas.rustjni.sample;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.appcompat.app.AppCompatActivity;
6 |
7 | public class MainActivity extends AppCompatActivity {
8 |
9 | //
10 | // auto-generated code
11 |
12 | private static native String sayHello();
13 |
14 | static { System.loadLibrary("my_rust_lib"); }
15 |
16 | //
17 |
18 | @Override
19 | public void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_main);
22 | }
23 |
24 | }
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/reflection/Visibility.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.reflection
2 |
3 | /**
4 | * Enum class that represents the visibility of a methods
5 | * Since internal visibility is only available in Kotlin, it is not supported here
6 | */
7 | enum class Visibility(private val label : String) {
8 | PUBLIC("public"),
9 | PROTECTED("protected"),
10 | PRIVATE("private"),
11 | // Default omits the visibility modifier and assume the default visibility of the Programming Language:
12 | // Java: package-private, Kotlin: public
13 | DEFAULT("");
14 |
15 | override fun toString() = label
16 |
17 | }
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/sample/game/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google {
4 | content {
5 | includeGroupByRegex("com\\.android.*")
6 | includeGroupByRegex("com\\.google.*")
7 | includeGroupByRegex("androidx.*")
8 | }
9 | }
10 | mavenCentral()
11 | gradlePluginPortal()
12 | mavenLocal()
13 | }
14 | }
15 | dependencyResolutionManagement {
16 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
17 | repositories {
18 | google()
19 | mavenCentral()
20 | mavenLocal()
21 | }
22 | }
23 |
24 | rootProject.name = "GameSample"
25 | include(":app")
26 |
--------------------------------------------------------------------------------
/sample/java/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google {
4 | content {
5 | includeGroupByRegex("com\\.android.*")
6 | includeGroupByRegex("com\\.google.*")
7 | includeGroupByRegex("androidx.*")
8 | }
9 | }
10 | mavenLocal()
11 | mavenCentral()
12 | gradlePluginPortal()
13 | }
14 | }
15 | dependencyResolutionManagement {
16 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
17 | repositories {
18 | google()
19 | mavenCentral()
20 | mavenLocal()
21 | }
22 | }
23 |
24 | rootProject.name = "sample"
25 | include(":app")
26 |
--------------------------------------------------------------------------------
/sample/kotlin/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | mavenLocal()
4 | google {
5 | content {
6 | includeGroupByRegex("com\\.android.*")
7 | includeGroupByRegex("com\\.google.*")
8 | includeGroupByRegex("androidx.*")
9 | }
10 | }
11 | mavenCentral()
12 | gradlePluginPortal()
13 | }
14 | }
15 | dependencyResolutionManagement {
16 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
17 | repositories {
18 | mavenLocal()
19 | google()
20 | mavenCentral()
21 | }
22 | }
23 |
24 | rootProject.name = "sample"
25 | include(":app")
26 |
--------------------------------------------------------------------------------
/sample/game/app/src/androidTest/java/com/devfigas/gamesample/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.gamesample
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.devfigas.gamesample", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/sample/game/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/sample/java/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/sample/java/app/src/androidTest/java/com/devfigas/rustjni/sample/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.rustjni.sample
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.devfigas.rustjni.sample", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/sample/kotlin/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/sample/kotlin/app/src/androidTest/java/com/devfigas/rustjni/sample/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.rustjni.sample
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.devfigas.rustjni.sample", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/sample/java/app/src/main/rust/src/lib.rs:
--------------------------------------------------------------------------------
1 | use jni::objects::JClass;
2 | use jni::JNIEnv;
3 | //
4 | // primitive imports
5 | use jni::sys::jstring;
6 | //
7 |
8 | #[no_mangle]
9 | pub extern "C" fn Java_com_devfigas_rustjni_sample_MainActivity_sayHello(
10 | env: JNIEnv,
11 | _class: JClass,
12 | ) -> jstring {
13 | let output = r#"
14 | __________________________
15 | < Hello RustJNI >
16 | --------------------------
17 | \\
18 | \\
19 | _~^~^~_
20 | \\) / o o \\ (/
21 | '_ - _'
22 | / '-----' \\
23 | _________________________________________________________
24 | Do your rust implementation there: /rust/src/lib.rs
25 | ---------------------------------------------------------"#;
26 |
27 | env.new_string(output)
28 | .expect("Couldn't create Java string!")
29 | .into_raw()
30 | }
31 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/reflection/primitive/PrimitiveJVM.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.reflection.primitive
2 |
3 | internal object PrimitiveJVM {
4 | // Java types
5 | const val JV_INT = "int"
6 | const val JV_LONG = "long"
7 | const val JV_BOOLEAN = "boolean"
8 | const val JV_BYTE = "byte"
9 | const val JV_CHAR = "char"
10 | const val JV_DOUBLE = "double"
11 | const val JV_FLOAT = "float"
12 | const val JV_SHORT = "short"
13 | const val JV_STRING = "String"
14 | const val JV_OBJECT = "Object"
15 | const val JV_VOID = "void"
16 |
17 | // Kotlin types
18 | const val KT_INT = "Int"
19 | const val KT_LONG = "Long"
20 | const val KT_BOOLEAN = "Boolean"
21 | const val KT_BYTE = "Byte"
22 | const val KT_CHAR = "Char"
23 | const val KT_DOUBLE = "Double"
24 | const val KT_FLOAT = "Float"
25 | const val KT_SHORT = "Short"
26 | const val KT_STRING = "String"
27 | const val KT_UNIT = "Unit"
28 | const val KT_ANY = "Any"
29 | }
30 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/java/com/devfigas/gamesample/NativeLib.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.gamesample
2 |
3 | object NativeLib {
4 |
5 | //
6 | // auto-generated code
7 |
8 | public external fun loadCanvas(width: Int, height: Int): Unit
9 |
10 | public external fun loadEnemySpriteTable(size: Int, height: Int, width: Int): Unit
11 |
12 | public external fun loadPlayerSpriteTable(size: Int, height: Int, width: Int): Unit
13 |
14 | public external fun actionJump(): Unit
15 |
16 | public external fun actionStart(): Unit
17 |
18 | public external fun isDead(): Boolean
19 |
20 | public external fun getPlayerX(): Float
21 |
22 | public external fun getPlayerY(): Float
23 |
24 | public external fun getEnemyX(): Float
25 |
26 | public external fun getEnemyY(): Float
27 |
28 | public external fun getPlayerSprite(): Int
29 |
30 | public external fun getEnemySprite(): Int
31 |
32 | init { System.loadLibrary("my_rust_lib") }
33 |
34 | //
35 |
36 | }
--------------------------------------------------------------------------------
/sample/java/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/OSHelper.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni
2 |
3 | import java.io.File
4 |
5 | object OSHelper {
6 |
7 | fun isWindows(): Boolean {
8 | return System.getProperty("os.name").toLowerCase().contains("win")
9 | }
10 |
11 | fun isMac(): Boolean {
12 | return System.getProperty("os.name").toLowerCase().contains("mac")
13 | }
14 |
15 | fun isLinux(): Boolean {
16 | return System.getProperty("os.name").toLowerCase().contains("linux")
17 | }
18 |
19 | fun doubleSeparatorIfNeeded(path: String): String {
20 | return if (isWindows()) {
21 | path.replace(File.separator, "${File.separator}${File.separator}")
22 | } else {
23 | path
24 | }
25 | }
26 |
27 | fun addLinkerExtensionIfNeeded(linker: String): String {
28 | val windowsLinkerExt = ".cmd"
29 | return if (isWindows() && !linker.endsWith(windowsLinkerExt)) {
30 | linker + windowsLinkerExt
31 | } else {
32 | linker
33 | }
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/gradle-plugin-test/src/main/kotlin/io/github/andrefigas/rustjni/test/RustJNITest.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.test
2 |
3 | import org.gradle.api.Plugin
4 | import org.gradle.api.Project
5 | import java.io.File
6 |
7 | class RustJNITest : Plugin {
8 |
9 | companion object{
10 | const val RUST_JNI_COMPILE_TEST = "rust-jni-compile-test"
11 | val JNI_HOST = "app${File.separator}" +
12 | "src${File.separator}" +
13 | "main${File.separator}" +
14 | "java${File.separator}" +
15 | "com${File.separator}" +
16 | "devfigas${File.separator}" +
17 | "rustjni${File.separator}" +
18 | "sample${File.separator}" +
19 | "MainActivity"
20 | }
21 |
22 | override fun apply(project: Project) {
23 |
24 | project.tasks.register(RUST_JNI_COMPILE_TEST) {
25 | group = "test"
26 | description = "Compiles Rust code for specified test cases"
27 |
28 | doFirst {
29 | JVMTestRunner.test(project, this)
30 | }
31 |
32 | }
33 |
34 | }
35 |
36 |
37 |
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
19 |
20 |
28 |
29 |
--------------------------------------------------------------------------------
/gradle-plugin/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | `maven-publish`
4 | id("com.gradle.plugin-publish") version "1.2.0"
5 | }
6 |
7 | repositories {
8 | mavenCentral()
9 | google()
10 | }
11 |
12 | version = "0.0.27"
13 | group = "io.github.andrefigas.rustjni"
14 |
15 | gradlePlugin {
16 | website.set("https://github.com/andrefigas/RustJNI")
17 | vcsUrl.set("https://github.com/andrefigas/RustJNI")
18 | plugins {
19 | create("rustJniPlugin") {
20 | id = "io.github.andrefigas.rustjni"
21 | implementationClass = "io.github.andrefigas.rustjni.RustJNI"
22 | displayName = "Rust JNI Gradle Plugin"
23 | description = "A Gradle plugin that simplifies the creation and compilation of Rust code integrated with Android applications via JNI."
24 | tags.set(listOf("rust", "jni", "android", "gradle-plugin", "native-code", "android-development", "rust-jni"))
25 | }
26 | }
27 | }
28 |
29 | dependencies {
30 | implementation(kotlin("stdlib"))
31 | implementation(gradleApi())
32 | implementation(localGroovy())
33 | compileOnly("com.android.tools.build:gradle:8.1.1")
34 | implementation("org.tomlj:tomlj:1.1.1")
35 | }
36 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/sample/game/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.7.2"
3 | kotlin = "1.9.24"
4 | coreKtx = "1.15.0"
5 | junit = "4.13.2"
6 | junitVersion = "1.2.1"
7 | espressoCore = "3.6.1"
8 | appcompat = "1.7.0"
9 | material = "1.12.0"
10 | activity = "1.9.3"
11 | constraintlayout = "2.2.0"
12 |
13 | [libraries]
14 | androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
15 | junit = { group = "junit", name = "junit", version.ref = "junit" }
16 | androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
17 | androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
18 | androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
19 | material = { group = "com.google.android.material", name = "material", version.ref = "material" }
20 | androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
21 | androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
22 |
23 | [plugins]
24 | android-application = { id = "com.android.application", version.ref = "agp" }
25 | kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
26 |
27 |
--------------------------------------------------------------------------------
/sample/java/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.7.1"
3 | kotlin = "1.9.0"
4 | coreKtx = "1.13.1"
5 | junit = "4.13.2"
6 | junitVersion = "1.2.1"
7 | espressoCore = "3.6.1"
8 | appcompat = "1.7.0"
9 | material = "1.12.0"
10 | activity = "1.9.2"
11 | constraintlayout = "2.1.4"
12 |
13 | [libraries]
14 | androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
15 | junit = { group = "junit", name = "junit", version.ref = "junit" }
16 | androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
17 | androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
18 | androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
19 | material = { group = "com.google.android.material", name = "material", version.ref = "material" }
20 | androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
21 | androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
22 |
23 | [plugins]
24 | android-application = { id = "com.android.application", version.ref = "agp" }
25 | jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
26 |
27 |
--------------------------------------------------------------------------------
/sample/kotlin/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.7.1"
3 | kotlin = "1.9.0"
4 | coreKtx = "1.13.1"
5 | junit = "4.13.2"
6 | junitVersion = "1.2.1"
7 | espressoCore = "3.6.1"
8 | appcompat = "1.7.0"
9 | material = "1.12.0"
10 | activity = "1.9.3"
11 | constraintlayout = "2.1.4"
12 |
13 | [libraries]
14 | androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
15 | junit = { group = "junit", name = "junit", version.ref = "junit" }
16 | androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
17 | androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
18 | androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
19 | material = { group = "com.google.android.material", name = "material", version.ref = "material" }
20 | androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
21 | androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
22 |
23 | [plugins]
24 | android-application = { id = "com.android.application", version.ref = "agp" }
25 | jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
26 |
27 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/rust/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | #
2 | #auto-generated code
3 |
4 | [target.armv7-linux-androideabi]
5 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
6 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi21-clang"
7 |
8 | [target.aarch64-linux-android]
9 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
10 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android21-clang"
11 |
12 | [target.i686-linux-android]
13 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
14 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/i686-linux-android21-clang"
15 |
16 | [target.x86_64-linux-android]
17 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
18 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/x86_64-linux-android21-clang"
19 |
20 | #
21 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/rust/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | #
2 | #auto-generated code
3 |
4 | [target.armv7-linux-androideabi]
5 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
6 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi21-clang"
7 |
8 | [target.aarch64-linux-android]
9 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
10 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android21-clang"
11 |
12 | [target.i686-linux-android]
13 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
14 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/i686-linux-android21-clang"
15 |
16 | [target.x86_64-linux-android]
17 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
18 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/x86_64-linux-android21-clang"
19 |
20 | #
21 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/rust/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | #
2 | #auto-generated code
3 |
4 | [target.armv7-linux-androideabi]
5 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
6 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi21-clang"
7 |
8 | [target.aarch64-linux-android]
9 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
10 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android21-clang"
11 |
12 | [target.i686-linux-android]
13 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
14 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/i686-linux-android21-clang"
15 |
16 | [target.x86_64-linux-android]
17 | ar = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar"
18 | linker = "/Users/andre.figueiredo/Library/Android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/darwin-x86_64/bin/x86_64-linux-android21-clang"
19 |
20 | #
21 |
--------------------------------------------------------------------------------
/sample/game/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. For more details, visit
12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/sample/java/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. For more details, visit
12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/sample/kotlin/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. For more details, visit
12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/sample/game/app/src/main/java/com/devfigas/gamesample/Sprite.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.gamesample
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.graphics.BitmapFactory
6 | import android.graphics.Point
7 |
8 | typealias SpriteData = Pair>
9 | fun Point.width() = this.x
10 | fun Point.height() = this.y
11 |
12 | enum class Sprite(
13 | private val resourceName : String,
14 | private val size : Int) {
15 | PLAYER("player.png", 6),
16 | ENEMY("enemy.png", 6);
17 |
18 | fun table(context: Context): SpriteData {
19 | return context.assets.open(resourceName).use { inputStream ->
20 | // Load the complete bitmap from the asset file
21 | val spriteSheet = BitmapFactory.decodeStream(inputStream)
22 |
23 | // Calculate the width and height of each sprite (1 row and 'size' columns)
24 | val spriteWidth = spriteSheet.width / size
25 | val spriteHeight = spriteSheet.height
26 |
27 | // Initialize the array of bitmaps
28 | Point(spriteHeight, spriteWidth) to Array(size) { index ->
29 | // Calculate the x position of the sprite in the row
30 | val x = index * spriteWidth
31 | // Extract and create a new bitmap for each sprite
32 | Bitmap.createBitmap(spriteSheet, x, 0, spriteWidth, spriteHeight)
33 | }
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/gradle-plugin-test/src/main/kotlin/io/github/andrefigas/rustjni/test/jvm/content/JVMContentProvider.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.test.jvm.content
2 |
3 | import java.lang.StringBuilder
4 |
5 | interface JVMContentProvider {
6 |
7 | fun generate(methods : Map, String>): String {
8 | val separator = "\n\n"
9 | val sb = StringBuilder()
10 | var ident = ""
11 | var i = 0;
12 | methods.forEach { (argType, returnType) ->
13 | sb.append(ident)
14 | sb.append(generateMethod(i, argType, returnType).trimIndent())
15 | sb.append(separator)
16 | ident = " "
17 | i++
18 | }
19 |
20 | val methods = sb.deleteRange(sb.length - separator.length, sb.length).toString()
21 | return generateJVMContent(methods).trimIndent()
22 | }
23 |
24 | fun generateMethod(index : Int, argType : Array, returnType : String) : String
25 |
26 | fun generateJVMContent(generated: String) : String
27 |
28 | val restoreJVMContent : String
29 |
30 | val primitiveInt: String
31 |
32 | val primitiveLong: String
33 |
34 | val primitiveBoolean: String
35 |
36 | val primitiveByte: String
37 |
38 | val primitiveChar: String
39 |
40 | val primitiveDouble: String
41 |
42 | val primitiveFloat: String
43 |
44 | val primitiveShort: String
45 |
46 | val primitiveString: String
47 |
48 | val primitiveObject: String
49 |
50 | val primitiveVoid: String
51 |
52 | }
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/reflection/primitive/PrimitiveRust.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.reflection.primitive
2 |
3 | internal object PrimitiveRust {
4 | const val RS_JSTRING = "jstring"
5 | const val RS_JINT = "jint"
6 | const val RS_JLONG = "jlong"
7 | const val RS_JBOOLEAN = "jboolean"
8 | const val RS_JBYTE = "jbyte"
9 | const val RS_JCHAR = "jchar"
10 | const val RS_JDOUBLE = "jdouble"
11 | const val RS_JFLOAT = "jfloat"
12 | const val RS_JSHORT = "jshort"
13 | const val RS_JOBJECT = "jobject"
14 | const val RS_JCLASS = "jclass"
15 | const val RS_VOID = ""
16 |
17 | // Function 'any' that performs some operation with the provided type
18 | fun any(type: String): String {
19 | // Return a sample value based on the provided type
20 | return when (type) {
21 | RS_JSTRING -> "Sample string"
22 | RS_JINT -> "42"
23 | RS_JLONG -> "1234567890"
24 | RS_JBOOLEAN -> "true"
25 | RS_JBYTE -> "42"
26 | RS_JCHAR -> "'A' as jchar"
27 | RS_JDOUBLE -> "3.14159"
28 | RS_JFLOAT -> "2.71828"
29 | RS_JSHORT -> "32767"
30 | RS_JOBJECT -> "null object"
31 | RS_JCLASS -> "class object"
32 | RS_VOID -> "void"
33 | else -> "Unknown type"
34 | }
35 | }
36 |
37 | // Function 'mock' that creates a pair of the provided type and its corresponding 'any' value
38 | fun mock(type: String) = type to any(type)
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/doc/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 0.0.27 (2025-08-07)
4 | ### Fixed
5 | - Fixed the support for Cargo checking on Windows
6 |
7 | ## 0.0.26 (2025-08-06)
8 | ### Added
9 | - Added support for a custom Rust path via
10 | e.g. `cargo.dir=/Users//cargo_tmp/.cargo/bin`
11 |
12 | ### Changed
13 | - Moved Rust version checking from initialization to Rust compilation time
14 |
15 | ## 0.0.25 (2025-07-20)
16 | ### Changed
17 | Improved Rust code generation: when importing a single JNI primitive type, the import now uses the form ```use jni::sys::;``` instead of ```use jni::sys::{};```.
18 | This change aligns better with Rust best practices and helps reduce lint warnings.
19 |
20 | ## 0.0.24 (2025-04-17)
21 | ### Added
22 | - Support for Rust version constraints in `rustJni` configuration.
23 | You can now define which Rust version is acceptable to compile your project using the `rustVersion` property.
24 | Supported patterns include:
25 | - Exact version: `1.86.0`
26 | - Minimum version: `>=1.64.0`
27 | - Wildcards: `1.86.*`, `1.*.*`
28 |
29 | ## 0.0.23 (2025-03-31)
30 | ### Added
31 |
32 | - Manual changes to the `config.toml` file are now preserved.
33 | The plugin no longer overrides existing content, allowing developers to customize their configuration safely.
34 |
35 | ## 0.0.22 (2024-11-05)
36 |
37 | ### Added
38 | - [Support configurable visibility for generated Java/Kotlin methods](https://github.com/andrefigas/RustJNI/issues/19)
39 | - [Support kotlin implicit return](https://github.com/andrefigas/RustJNI/issues/18)
40 | - Game sample
41 |
42 |
43 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/java/com/devfigas/gamesample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.gamesample
2 | import android.os.Bundle
3 | import android.widget.Toast
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.appcompat.widget.SwitchCompat
6 | import com.google.android.material.floatingactionbutton.FloatingActionButton
7 |
8 | class MainActivity : AppCompatActivity(), GameListener {
9 |
10 | private lateinit var fab : FloatingActionButton
11 | private lateinit var gameSurfaceView : GameSurfaceView
12 | private lateinit var swHitBox : SwitchCompat
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setContentView(R.layout.activity_main)
17 | fab = findViewById(R.id.fab)
18 | gameSurfaceView = findViewById(R.id.gameSurfaceView)
19 | swHitBox = findViewById(R.id.swHitBox)
20 | gameSurfaceView.gameListener = this
21 | swHitBox.setOnCheckedChangeListener { _, isChecked ->
22 | gameSurfaceView.hitBox = isChecked
23 | }
24 | enableStartButton()
25 | }
26 |
27 | private fun enableStartButton(){
28 | fab.setImageResource(R.drawable.baseline_play_arrow_24)
29 | fab.setOnClickListener {
30 | enableJumpButton()
31 | NativeLib.actionStart()
32 | }
33 | }
34 |
35 | private fun enableJumpButton(){
36 | fab.setImageResource(R.drawable.baseline_file_upload_24)
37 | fab.setOnClickListener {
38 | NativeLib.actionJump()
39 | }
40 | }
41 |
42 | override fun onGameEnd() {
43 | Toast.makeText(this, "Game Over", Toast.LENGTH_SHORT).show()
44 | enableStartButton()
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/gradle-plugin-test/src/main/kotlin/io/github/andrefigas/rustjni/test/toml/TomlContentProvider.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.test.toml
2 |
3 | class TomlContentProvider(ndkPath: String) {
4 |
5 | val osName = System.getProperty("os.name").toLowerCase()
6 | val defaultPrebuilt = when {
7 | osName.contains("win") -> "windows-x86_64"
8 | osName.contains("mac") -> "darwin-x86_64"
9 | osName.contains("linux") -> "linux-x86_64"
10 | else -> throw org.gradle.api.GradleException("Unsupported operating system: $osName")
11 | }
12 |
13 | private val binPath = "$ndkPath/27.1.12297006/toolchains/llvm/prebuilt/$defaultPrebuilt/bin"
14 |
15 | val armv7_linux_androideabi = "[target.armv7-linux-androideabi]\n" +
16 | "ar = \"$binPath/llvm-ar\"\n" +
17 | "linker = \"$binPath/armv7a-linux-androideabi21-clang\""
18 |
19 | val aarch64_linux_android = "[target.aarch64-linux-android]\n" +
20 | "ar = \"$binPath/llvm-ar\"\n" +
21 | "linker = \"$binPath/aarch64-linux-android21-clang\""
22 |
23 | val i686_linux_android = "[target.i686-linux-android]\n" +
24 | "ar = \"$binPath/llvm-ar\"\n" +
25 | "linker = \"$binPath/i686-linux-android21-clang\""
26 |
27 | val x86_64_linux_android = "[target.x86_64-linux-android]\n" +
28 | "ar = \"$binPath/llvm-ar\"\n" +
29 | "linker = \"$binPath/x86_64-linux-android21-clang\""
30 |
31 | val all = listOf(
32 | armv7_linux_androideabi,
33 | aarch64_linux_android,
34 | i686_linux_android,
35 | x86_64_linux_android
36 | )
37 |
38 | fun cargoConfig(): String {
39 | return buildString {
40 | appendLine("#")
41 | appendLine("#auto-generated code")
42 | all.forEach {
43 | appendLine(it)
44 | appendLine()
45 | }
46 | appendLine("#")
47 | }.trimStart()
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/sample/game/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import io.github.andrefigas.rustjni.reflection.Visibility
2 |
3 | plugins {
4 | alias(libs.plugins.android.application)
5 | alias(libs.plugins.kotlin.android)
6 | id("io.github.andrefigas.rustjni") version "0.0.22"
7 | }
8 |
9 | rustJni{
10 | jniHost = "com.devfigas.gamesample.NativeLib"
11 | jniMethodsVisibility = Visibility.PUBLIC
12 | rustPath = "./app/src/main/rust"
13 | ndkVersion = "27.1.12297006"
14 | architectures {
15 | armv7_linux_androideabi("armv7a-linux-androideabi21-clang")
16 | aarch64_linux_android("aarch64-linux-android21-clang")
17 | i686_linux_android("i686-linux-android21-clang")
18 | x86_64_linux_android("x86_64-linux-android21-clang")
19 | }
20 | }
21 |
22 | android {
23 | namespace = "com.devfigas.gamesample"
24 | compileSdk = 35
25 |
26 | defaultConfig {
27 | applicationId = "com.devfigas.gamesample"
28 | minSdk = 24
29 | targetSdk = 35
30 | versionCode = 1
31 | versionName = "1.0"
32 |
33 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
34 | }
35 |
36 | buildTypes {
37 | release {
38 | isMinifyEnabled = false
39 | proguardFiles(
40 | getDefaultProguardFile("proguard-android-optimize.txt"),
41 | "proguard-rules.pro"
42 | )
43 | }
44 | }
45 | compileOptions {
46 | sourceCompatibility = JavaVersion.VERSION_11
47 | targetCompatibility = JavaVersion.VERSION_11
48 | }
49 | kotlinOptions {
50 | jvmTarget = "11"
51 | }
52 | }
53 |
54 | dependencies {
55 |
56 | implementation(libs.androidx.core.ktx)
57 | implementation(libs.androidx.appcompat)
58 | implementation(libs.material)
59 | implementation(libs.androidx.activity)
60 | implementation(libs.androidx.constraintlayout)
61 | testImplementation(libs.junit)
62 | androidTestImplementation(libs.androidx.junit)
63 | androidTestImplementation(libs.androidx.espresso.core)
64 | }
65 |
--------------------------------------------------------------------------------
/sample/java/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import io.github.andrefigas.rustjni.reflection.Visibility
2 |
3 | plugins {
4 | alias(libs.plugins.android.application)
5 | alias(libs.plugins.jetbrains.kotlin.android)
6 | id("io.github.andrefigas.rustjni") version "0.0.27"
7 | }
8 |
9 | rustJni{
10 | rustPath = "./app/src/main/rust"
11 | jniHost = "com.devfigas.rustjni.sample.MainActivity"
12 | jniMethodsVisibility = Visibility.PRIVATE
13 | ndkVersion = "27.1.12297006"
14 | architectures {
15 | armv7_linux_androideabi("armv7a-linux-androideabi21-clang")
16 | aarch64_linux_android("aarch64-linux-android21-clang")
17 | i686_linux_android("i686-linux-android21-clang")
18 | x86_64_linux_android("x86_64-linux-android21-clang")
19 | }
20 | rustVersion = ">=1.0.0"
21 | }
22 |
23 | android {
24 | namespace = "com.devfigas.rustjni.sample"
25 | compileSdk = 34
26 |
27 | defaultConfig {
28 | applicationId = "com.devfigas.rustjni.sample"
29 | minSdk = 24
30 | targetSdk = 34
31 | versionCode = 1
32 | versionName = "1.0"
33 |
34 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
35 | }
36 |
37 | buildTypes {
38 | release {
39 | isMinifyEnabled = false
40 | proguardFiles(
41 | getDefaultProguardFile("proguard-android-optimize.txt"),
42 | "proguard-rules.pro"
43 | )
44 | }
45 | }
46 | compileOptions {
47 | sourceCompatibility = JavaVersion.VERSION_1_8
48 | targetCompatibility = JavaVersion.VERSION_1_8
49 | }
50 | kotlinOptions {
51 | jvmTarget = "1.8"
52 | }
53 | }
54 |
55 | dependencies {
56 | implementation(libs.androidx.core.ktx)
57 | implementation(libs.androidx.appcompat)
58 | implementation(libs.material)
59 | implementation(libs.androidx.activity)
60 | implementation(libs.androidx.constraintlayout)
61 | testImplementation(libs.junit)
62 | androidTestImplementation(libs.androidx.junit)
63 | androidTestImplementation(libs.androidx.espresso.core)
64 | }
65 |
--------------------------------------------------------------------------------
/sample/kotlin/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import io.github.andrefigas.rustjni.reflection.Visibility
2 |
3 | plugins {
4 | alias(libs.plugins.android.application)
5 | alias(libs.plugins.jetbrains.kotlin.android)
6 | id("io.github.andrefigas.rustjni") version "0.0.27"
7 | }
8 |
9 | rustJni{
10 | rustPath = "./app/src/main/rust"
11 | jniHost = "com.devfigas.rustjni.sample.MainActivity"
12 | jniMethodsVisibility = Visibility.PRIVATE
13 | ndkVersion = "27.1.12297006"
14 | architectures {
15 | armv7_linux_androideabi("armv7a-linux-androideabi21-clang")
16 | aarch64_linux_android("aarch64-linux-android21-clang")
17 | i686_linux_android("i686-linux-android21-clang")
18 | x86_64_linux_android("x86_64-linux-android21-clang")
19 | }
20 | rustVersion = ">=1.0.0"
21 | }
22 |
23 | android {
24 | namespace = "com.devfigas.rustjni.sample"
25 | compileSdk = 34
26 |
27 | defaultConfig {
28 | applicationId = "com.devfigas.rustjni.sample"
29 | minSdk = 24
30 | targetSdk = 34
31 | versionCode = 1
32 | versionName = "1.0"
33 |
34 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
35 | }
36 |
37 | buildTypes {
38 | release {
39 | isMinifyEnabled = false
40 | proguardFiles(
41 | getDefaultProguardFile("proguard-android-optimize.txt"),
42 | "proguard-rules.pro"
43 | )
44 | }
45 | }
46 | compileOptions {
47 | sourceCompatibility = JavaVersion.VERSION_1_8
48 | targetCompatibility = JavaVersion.VERSION_1_8
49 | }
50 | kotlinOptions {
51 | jvmTarget = "1.8"
52 | }
53 | }
54 |
55 | dependencies {
56 | implementation(libs.androidx.core.ktx)
57 | implementation(libs.androidx.appcompat)
58 | implementation(libs.material)
59 | implementation(libs.androidx.activity)
60 | implementation(libs.androidx.constraintlayout)
61 | testImplementation(libs.junit)
62 | androidTestImplementation(libs.androidx.junit)
63 | androidTestImplementation(libs.androidx.espresso.core)
64 | }
65 |
--------------------------------------------------------------------------------
/gradle-plugin-test/src/main/kotlin/io/github/andrefigas/rustjni/test/jvm/content/KotlinContentProvider.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.test.jvm.content
2 |
3 | object KotlinContentProvider : JVMContentProvider {
4 |
5 | override val primitiveInt = "Int"
6 | override val primitiveLong = "Long"
7 | override val primitiveBoolean = "Boolean"
8 | override val primitiveByte = "Byte"
9 | override val primitiveChar = "Char"
10 | override val primitiveDouble = "Double"
11 | override val primitiveFloat = "Float"
12 | override val primitiveShort = "Short"
13 | override val primitiveString = "String"
14 | override val primitiveObject = "Any"
15 | override val primitiveVoid = "Unit"
16 |
17 | override fun generateMethod(index : Int, argType: Array, returnType: String): String {
18 | val params = argType.mapIndexed { index, arg -> "param$index : $arg" }
19 | return """
20 | private external fun someMethod$index(${params.joinToString(separator = ", ")}) : $returnType
21 | """.trimIndent()
22 | }
23 |
24 | override fun generateJVMContent(generated: String) ="""
25 | package com.devfigas.rustjni.sample
26 |
27 | import android.os.Bundle
28 | import androidx.appcompat.app.AppCompatActivity
29 |
30 |
31 | class MainActivity : AppCompatActivity() {
32 |
33 | //
34 | // auto-generated code
35 |
36 | $generated
37 |
38 | init { System.loadLibrary("my_rust_lib") }
39 |
40 | //
41 |
42 | override fun onCreate(savedInstanceState: Bundle?) {
43 | super.onCreate(savedInstanceState)
44 | setContentView(R.layout.activity_main)
45 | }
46 | }
47 | """
48 |
49 | override val restoreJVMContent = """
50 | package com.devfigas.rustjni.sample
51 |
52 | import android.os.Bundle
53 | import androidx.appcompat.app.AppCompatActivity
54 |
55 |
56 | class MainActivity : AppCompatActivity() {
57 |
58 | override fun onCreate(savedInstanceState: Bundle?) {
59 | super.onCreate(savedInstanceState)
60 | setContentView(R.layout.activity_main)
61 | }
62 | }
63 | """
64 |
65 | }
--------------------------------------------------------------------------------
/gradle-plugin-test/src/main/kotlin/io/github/andrefigas/rustjni/test/jvm/content/JavaContentProvider.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.test.jvm.content
2 |
3 | object JavaContentProvider : JVMContentProvider {
4 |
5 | override val primitiveInt = "int"
6 | override val primitiveLong = "long"
7 | override val primitiveBoolean = "boolean"
8 | override val primitiveByte = "byte"
9 | override val primitiveChar = "char"
10 | override val primitiveDouble = "double"
11 | override val primitiveFloat = "float"
12 | override val primitiveShort = "short"
13 | override val primitiveString = "String"
14 | override val primitiveObject = "Object"
15 | override val primitiveVoid = "void"
16 |
17 | override fun generateMethod(index : Int, argType: Array, returnType: String) : String {
18 | val params = argType.mapIndexed { index, arg -> "$arg param$index" }
19 | return """
20 | private static native $returnType someMethod$index(${params.joinToString(separator = ", ")});
21 | """.trimIndent()
22 | }
23 |
24 | override fun generateJVMContent(generated: String) = """
25 | package com.devfigas.rustjni.sample;
26 |
27 | import android.os.Bundle;
28 | import androidx.appcompat.app.AppCompatActivity;
29 |
30 | public class MainActivity extends AppCompatActivity {
31 |
32 | //
33 | // auto-generated code
34 |
35 | $generated
36 |
37 | static { System.loadLibrary("my_rust_lib"); }
38 |
39 | //
40 |
41 | @Override
42 | public void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_main);
45 | }
46 |
47 | }
48 | """
49 |
50 | override val restoreJVMContent = """
51 | package com.devfigas.rustjni.sample;
52 |
53 | import android.os.Bundle;
54 |
55 | import androidx.appcompat.app.AppCompatActivity;
56 |
57 | public class MainActivity extends AppCompatActivity {
58 |
59 | @Override
60 | public void onCreate(Bundle savedInstanceState) {
61 | super.onCreate(savedInstanceState);
62 | setContentView(R.layout.activity_main);
63 | }
64 |
65 | }
66 | """
67 |
68 | }
--------------------------------------------------------------------------------
/.github/workflows/android-ci.yaml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 | - dev
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v3
16 |
17 | - name: Set up JDK 17
18 | uses: actions/setup-java@v3
19 | with:
20 | distribution: 'zulu'
21 | java-version: '17'
22 |
23 | - name: Install Rust
24 | run: |
25 | sudo apt update
26 | sudo apt install -y curl
27 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
28 | source $HOME/.cargo/env
29 |
30 | - name: Grant execute permission for all Gradle Wrappers
31 | run: |
32 | chmod +x gradle-plugin/gradlew
33 | chmod +x gradle-plugin-test/gradlew
34 | chmod +x sample/java/gradlew
35 | chmod +x sample/kotlin/gradlew
36 |
37 | - name: Cache Gradle dependencies
38 | uses: actions/cache@v3
39 | with:
40 | path: |
41 | ~/.gradle/caches
42 | ~/.gradle/wrapper
43 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
44 | restore-keys: |
45 | ${{ runner.os }}-gradle-
46 |
47 | - name: Install Android SDK and NDK
48 | run: |
49 | # Install Android SDK
50 | sudo apt-get install -y wget unzip
51 | wget https://dl.google.com/android/repository/commandlinetools-linux-8512546_latest.zip
52 | mkdir -p $ANDROID_SDK_ROOT/cmdline-tools
53 | unzip commandlinetools-linux-8512546_latest.zip -d $ANDROID_SDK_ROOT/cmdline-tools
54 | mv $ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools $ANDROID_SDK_ROOT/cmdline-tools/latest
55 | yes | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --licenses
56 |
57 | # Install the required version of NDK
58 | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager "ndk;27.1.12297006"
59 |
60 | # Configure local.properties in the sample directory with SDK and NDK paths
61 | echo "sdk.dir=$ANDROID_SDK_ROOT" > ./sample/java/local.properties
62 | echo "sdk.dir=$ANDROID_SDK_ROOT" > ./sample/kotlin/local.properties
63 | env:
64 | ANDROID_SDK_ROOT: /usr/local/lib/android/sdk
65 |
66 | - name: Publish locally JNI in gradle-rust-plugin directory
67 | run: |
68 | cd gradle-plugin
69 | ./gradlew publishToMavenLocal
70 | cd ..
71 |
72 | - name: Publish locally gradle-rust-plugin-test directory
73 | run: |
74 | cd gradle-plugin-test
75 | ./gradlew publishToMavenLocal
76 | cd ..
77 |
78 | - name: Compile Rust JNI Test
79 | run: |
80 | cd gradle-plugin-test
81 | ./gradlew executeTest
82 |
--------------------------------------------------------------------------------
/gradle-plugin-test/src/main/kotlin/io/github/andrefigas/rustjni/test/TestData.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.test
2 |
3 | import io.github.andrefigas.rustjni.test.jvm.content.JVMContentProvider
4 |
5 | object TestData {
6 |
7 | fun all(provider: JVMContentProvider) =
8 | provider.generate(
9 | mapOf(
10 | arrayOf(provider.primitiveInt) to provider.primitiveInt, // Int as argument and return
11 | arrayOf(provider.primitiveLong) to provider.primitiveDouble, // Long as argument, Double as return
12 | arrayOf(provider.primitiveBoolean) to provider.primitiveString,// Boolean as argument, String as return
13 | arrayOf(provider.primitiveByte) to provider.primitiveFloat, // Byte as argument, Float as return
14 | arrayOf(provider.primitiveChar) to provider.primitiveBoolean, // Char as argument, Boolean as return
15 | arrayOf(provider.primitiveDouble) to provider.primitiveChar, // Double as argument, Char as return
16 | arrayOf(provider.primitiveFloat) to provider.primitiveByte, // Float as argument, Byte as return
17 | arrayOf(provider.primitiveShort) to provider.primitiveVoid, // Short as argument, Void as return
18 | arrayOf(provider.primitiveString) to provider.primitiveShort, // String as argument, Short as return
19 | *generateRandomArgCombinations(provider, 2),
20 | *generateRandomArgCombinations(provider, 3),
21 | *generateRandomArgCombinations(provider, 4),
22 | *generateRandomArgCombinations(provider, 5),
23 | *generateRandomArgCombinations(provider, 6),
24 | *generateRandomArgCombinations(provider, 7),
25 | *generateRandomArgCombinations(provider, 8),
26 | *generateRandomArgCombinations(provider, 9),
27 | *generateRandomArgCombinations(provider, 10)
28 |
29 | )
30 | )
31 |
32 | private fun generateRandomArgCombinations(provider: JVMContentProvider, numArgs: Int): Array, String>> {
33 | val argumentTypes = listOf(
34 | provider.primitiveInt,
35 | provider.primitiveLong,
36 | provider.primitiveBoolean,
37 | provider.primitiveByte,
38 | provider.primitiveChar,
39 | provider.primitiveDouble,
40 | provider.primitiveFloat,
41 | provider.primitiveShort,
42 | provider.primitiveString
43 | )
44 |
45 | val returnTypes = argumentTypes + provider.primitiveVoid
46 |
47 | return Array(3) {
48 | val args = Array(numArgs) { argumentTypes.random() }
49 | args to returnTypes.random()
50 | }
51 | }
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/sample/game/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/sample/java/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/gradle-plugin/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/sample/kotlin/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/gradle-plugin-test/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/AndroidSettings.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni
2 |
3 | import org.gradle.api.Project
4 | import java.io.File
5 |
6 | internal object AndroidSettings {
7 |
8 | internal fun configureAndroidSourceSets(project: Project, extension: RustJniExtension) {
9 | project.afterEvaluate {
10 | val androidExtension = project.extensions.findByName("android")
11 | if (androidExtension is com.android.build.gradle.BaseExtension) {
12 | androidExtension.sourceSets.getByName("main").apply {
13 | val buildRust = File(buildDir, "rust")
14 | val buildSrcList = mutableListOf()
15 | buildSrcList.add(buildRust.toString())
16 | buildSrcList.addAll(jniLibs.srcDirs.map { it.toString() })
17 | jniLibs.setSrcDirs(buildSrcList)
18 | }
19 | project.logger.lifecycle("Configured jniLibs.srcDirs: ${androidExtension.sourceSets.getByName("main").jniLibs.srcDirs}")
20 | } else {
21 | throw org.gradle.api.GradleException("Android extension not found in project")
22 | }
23 | }
24 | }
25 |
26 | internal fun configureNdkAbiFilters(project: Project, extension: RustJniExtension) {
27 | project.afterEvaluate {
28 | val androidExtension = project.extensions.findByName("android")
29 |
30 | if (androidExtension is com.android.build.gradle.BaseExtension) {
31 | // Log the architectures list for debugging
32 | project.logger.lifecycle("Architectures list: ${extension.architecturesList.map { it.target }}")
33 |
34 | // Map architecture targets to corresponding ABI filters
35 | val pluginAbiFilters = extension.architecturesList.mapNotNull { archConfig ->
36 | when (archConfig.target) {
37 | AndroidTarget.ARMV7_LINUX_ANDROIDEABI -> "armeabi-v7a"
38 | AndroidTarget.AARCH64_LINUX_ANDROID -> "arm64-v8a"
39 | AndroidTarget.I686_LINUX_ANDROID -> "x86"
40 | AndroidTarget.X86_64_LINUX_ANDROID -> "x86_64"
41 | else -> {
42 | project.logger.lifecycle("Unknown architecture target: ${archConfig.target}")
43 | null
44 | }
45 | }
46 | }
47 |
48 | if (pluginAbiFilters.isNotEmpty()) {
49 | androidExtension.defaultConfig {
50 | ndk {
51 | abiFilters.addAll(pluginAbiFilters)
52 | project.logger.lifecycle("Configured ndk.abiFilters: $pluginAbiFilters")
53 | }
54 | }
55 | } else {
56 | project.logger.lifecycle("No valid architectures found to configure ndk.abiFilters.")
57 | }
58 | } else {
59 | throw org.gradle.api.GradleException("Android extension not found in project")
60 | }
61 | }
62 | }
63 |
64 | }
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/utils/FileUtils.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.utils
2 |
3 | import io.github.andrefigas.rustjni.RustJniExtension
4 | import org.gradle.api.Project
5 | import org.tomlj.Toml
6 | import java.io.File
7 |
8 | internal object FileUtils {
9 |
10 | /** This method retrieves the source directories of the project */
11 | fun getSourceDirs(project: Project): Set {
12 | return when (val androidExtension = project.extensions.findByName("android")) {
13 | is com.android.build.gradle.AppExtension -> androidExtension.sourceSets.getByName("main").java.srcDirs
14 | is com.android.build.gradle.LibraryExtension -> androidExtension.sourceSets.getByName("main").java.srcDirs
15 | else -> throw org.gradle.api.GradleException("Android extension not found in project")
16 | }
17 | }
18 |
19 | /** This method finds a class file within the source directories */
20 | fun findClassFile(project: Project, packagePath: String, className: String): File {
21 | val sourceDirs = getSourceDirs(project)
22 | val possibleExtensions = listOf("kt", "java")
23 |
24 | return sourceDirs
25 | .flatMap { srcDir ->
26 | possibleExtensions.map { ext ->
27 | File(srcDir, "$packagePath${File.separator}$className.$ext")
28 | }
29 | }
30 | .firstOrNull { it.exists() }
31 | ?: throw org.gradle.api.GradleException("Class file not found for jniHost: $packagePath.$className")
32 | }
33 |
34 | /** Reads the content of a given file */
35 | fun readFileContent(file: File): String {
36 | return file.readText()
37 | }
38 |
39 | /** Checks if a given file has a specific extension */
40 | fun isKotlinFile(file: File): Boolean {
41 | return file.extension.equals("kt", ignoreCase = true)
42 | }
43 |
44 | /** Extract class name from jniHost */
45 | fun extractClassName(jniHost: String): String {
46 | return jniHost.substringAfterLast('.')
47 | }
48 |
49 | /** Extract package path from jniHost */
50 | fun extractPackagePath(jniHost: String): String {
51 | return jniHost.substringBeforeLast('.').replace('.', File.separatorChar)
52 | }
53 |
54 | /** Gets the directory where the rust project lives. See [RustJniExtension.rustPath]. */
55 | fun getRustDir(project: Project, extension: RustJniExtension): File =
56 | project.file("${project.rootProject.projectDir}${File.separator}${extension.rustPath}")
57 |
58 | /** Gets the name of the rust */
59 | fun getLibName(project: Project, extension: RustJniExtension): String =
60 | extension.libName.ifEmpty {
61 | val toml = Toml.parse(File(getRustDir(project, extension), "Cargo.toml").toPath())
62 | toml.getString("lib.name")
63 | ?: toml.getString("package.name")
64 | ?: throw org.gradle.api.GradleException("Unable to get libName from Cargo.toml")
65 | }
66 |
67 | /** Gets the file that is used as the Rust library's main file,
68 | * i.e. where all the Java-to-Rust functions are defined. */
69 | fun getRustSrcFile(rustDir: File): File {
70 | // Get file's path from Cargo.toml
71 | val toml = try {
72 | Toml.parse(File(rustDir, "Cargo.toml").toPath())
73 | } catch (e: Exception) {
74 | null
75 | }
76 | val path = toml?.getString("lib.path")
77 | // Use the default if not specified
78 | ?: "./src/lib.rs"
79 | return File(rustDir, path)
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/gradle-plugin-test/src/main/kotlin/io/github/andrefigas/rustjni/test/TestRunner.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni.test
2 |
3 | import io.github.andrefigas.rustjni.test.cases.TestCases
4 | import io.github.andrefigas.rustjni.test.jvm.content.JVMContentProvider
5 | import io.github.andrefigas.rustjni.test.jvm.content.JavaContentProvider
6 | import io.github.andrefigas.rustjni.test.jvm.content.KotlinContentProvider
7 | import org.gradle.api.Project
8 | import org.gradle.api.Task
9 | import java.io.File
10 | import java.util.Properties
11 |
12 | object JVMTestRunner {
13 |
14 | private const val JAVA = ".java"
15 | internal const val KT = ".kt"
16 |
17 | fun test(project: Project, task: Task) {
18 | val jniHost = provideJNIHost(project)
19 | var contentProvider = contentProvider(jniHost)
20 |
21 | val rustFile = File(
22 | project.rootDir.toString(),
23 | "app${File.separator}" +
24 | "src${File.separator}" +
25 | "main${File.separator}" +
26 | "rust"
27 | )
28 |
29 | val props = Properties()
30 | project.file("${project.rootProject.projectDir}${File.separator}local.properties")
31 | .inputStream().use { props.load(it) }
32 |
33 | val ndkDir = "${props.getProperty("sdk.dir")}${File.separator}ndk"
34 |
35 | apply(
36 | project,
37 | task,
38 | ndkDir,
39 | rustFile,
40 | jniHost,
41 | contentProvider,
42 | TestData.all(contentProvider)
43 | )
44 | }
45 |
46 | private fun contentProvider(jniHost: File): JVMContentProvider {
47 | val path = jniHost.toString()
48 | return when {
49 | path.endsWith(KT) -> KotlinContentProvider
50 | path.endsWith(JAVA) -> JavaContentProvider
51 | else -> throw IllegalStateException("No printer found")
52 | }
53 | }
54 |
55 | private fun provideJNIHost(project: Project): File {
56 | var jvmFile = File(
57 | project.rootDir.toString(),
58 | RustJNITest.JNI_HOST + KT
59 | )
60 |
61 | if (jvmFile.exists()) {
62 | return jvmFile
63 | }
64 |
65 | jvmFile = File(
66 | project.rootDir.toString(),
67 | RustJNITest.JNI_HOST + JAVA
68 | )
69 |
70 | if (jvmFile.exists()) {
71 | return jvmFile
72 | }
73 |
74 | throw IllegalStateException("No JVM file found")
75 | }
76 |
77 | private fun clean(rustFile : File, jniHost : File, provider : JVMContentProvider){
78 | if(rustFile.exists()){
79 | rustFile.deleteRecursively()
80 | }
81 |
82 | jniHost.writeText(
83 | provider.restoreJVMContent.trimIndent()
84 | )
85 | }
86 |
87 | private fun apply(project: Project,
88 | task: Task,
89 | ndkDir: String,
90 | rustFile : File,
91 | jniHost : File,
92 | provider : JVMContentProvider,
93 | data: String
94 | ) {
95 | clean(rustFile, jniHost, provider)
96 | jniHost.writeText(data)
97 |
98 | TestCases(project,
99 | task,
100 | jniHost,
101 | ndkDir = ndkDir,
102 | rustFile = File(rustFile, "src${File.separator}lib.rs"),
103 | cargoConfigFile = File(rustFile,".cargo/config.toml"),
104 | ).apply {
105 | all()
106 | finish()
107 | }
108 |
109 | clean(rustFile, jniHost, provider)
110 | }
111 |
112 | }
113 |
114 |
115 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/java/com/devfigas/gamesample/GameSurfaceView.kt:
--------------------------------------------------------------------------------
1 | package com.devfigas.gamesample
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.graphics.Canvas
6 | import android.graphics.Color
7 | import android.graphics.Paint
8 | import android.os.Handler
9 | import android.os.Looper
10 | import android.util.AttributeSet
11 | import android.view.SurfaceHolder
12 | import android.view.SurfaceView
13 | import kotlin.concurrent.thread
14 |
15 | class GameSurfaceView @JvmOverloads constructor(
16 | context: Context, attrs: AttributeSet? = null
17 | ) : SurfaceView(context, attrs), SurfaceHolder.Callback {
18 |
19 | companion object{
20 | private val hitBoxPaint = Paint().apply {
21 | color = Color.argb(128, 255, 0, 0)
22 | style = Paint.Style.STROKE
23 | strokeWidth = 5f
24 | }
25 | }
26 |
27 | private val mainHandler: Handler = Handler(Looper.getMainLooper())
28 |
29 | private var playerSprites: Array
30 | private var enemySprites: Array
31 |
32 | private var updateThread: Thread? = null
33 | private var isRunning = false
34 |
35 | var gameListener: GameListener? = null
36 | var hitBox : Boolean = false
37 |
38 | init {
39 | holder.addCallback(this)
40 | playerSprites = Sprite.PLAYER.table(context).let { (dim, sprites) ->
41 | NativeLib.loadPlayerSpriteTable(sprites.size, dim.height(), dim.width())
42 | sprites
43 | }
44 |
45 | enemySprites = Sprite.ENEMY.table(context).let { (dim, sprites) ->
46 | NativeLib.loadEnemySpriteTable(sprites.size, dim.height(), dim.width())
47 | sprites
48 | }
49 |
50 | }
51 |
52 | override fun surfaceCreated(holder: SurfaceHolder) {
53 | isRunning = true
54 | updateThread = thread {
55 | loadCanvas()
56 | while (isRunning) {
57 | if (NativeLib.isDead()) {
58 | onGameEnd()
59 | }
60 |
61 | val canvas = holder.lockCanvas()
62 | canvas.drawColor(Color.WHITE)
63 |
64 | if (canvas != null) {
65 | drawPlayer(canvas)
66 | drawEnemy(canvas)
67 | holder.unlockCanvasAndPost(canvas)
68 | }
69 | }
70 | }
71 | }
72 |
73 | private fun loadCanvas(){
74 | val canvas = holder.lockCanvas()
75 | NativeLib.loadCanvas(canvas.width, canvas.height)
76 | canvas.drawColor(Color.WHITE)
77 | holder.unlockCanvasAndPost(canvas)
78 | }
79 |
80 | override fun surfaceDestroyed(holder: SurfaceHolder) {
81 | isRunning = false
82 | updateThread?.join()
83 | }
84 |
85 | override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
86 |
87 | }
88 |
89 | private fun drawPlayer(canvas: Canvas) {
90 | val sprite = playerSprites[NativeLib.getPlayerSprite()]
91 | val left = NativeLib.getPlayerX()
92 | val top = NativeLib.getPlayerY()
93 | drawHitBox(canvas, left, top, sprite)
94 | canvas.drawBitmap(sprite, left, top, null)
95 | }
96 |
97 | private fun drawEnemy(canvas: Canvas) {
98 | val sprite = enemySprites[NativeLib.getEnemySprite()]
99 | val left = NativeLib.getEnemyX()
100 | val top = NativeLib.getEnemyY()
101 | drawHitBox(canvas, left, top, sprite)
102 | canvas.drawBitmap(sprite, left, top, null)
103 | }
104 |
105 | private fun onGameEnd() {
106 | mainHandler.post {
107 | gameListener?.onGameEnd()
108 | }
109 | }
110 |
111 | private fun drawHitBox(canvas: Canvas, left: Float, top: Float, bitmap: Bitmap) {
112 | if(!hitBox) return
113 | canvas.drawRect(left, top, left + bitmap.width, top + bitmap.height, hitBoxPaint)
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/rust/src/lib.rs:
--------------------------------------------------------------------------------
1 | use jni::JNIEnv;
2 | use jni::objects::JClass;
3 | //
4 | // primitive imports
5 | use jni::sys::{jint, jboolean, jfloat};
6 | //
7 | use crate::game_controller::GameController;
8 | use crate::player_state::PlayerState;
9 | use std::sync::Mutex;
10 | use lazy_static::lazy_static;
11 |
12 | mod game_controller;
13 | mod player_state;
14 |
15 | lazy_static! {
16 | static ref GAME_CONTROLLER: Mutex = Mutex::new(GameController::new());
17 | }
18 |
19 | #[no_mangle]
20 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_loadCanvas(
21 | _env: JNIEnv,
22 | _class: JClass,
23 | width: jint,
24 | height: jint,
25 | ) {
26 | println!("Canvas loaded with width: {} and height: {}", width, height);
27 | let mut controller = GAME_CONTROLLER.lock().unwrap();
28 | controller.set_canvas_dimensions(width as f32, height as f32);
29 | }
30 |
31 | #[no_mangle]
32 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_loadEnemySpriteTable(
33 | _env: JNIEnv,
34 | _class: JClass,
35 | size: jint,
36 | height: jint,
37 | width: jint,
38 | ) {
39 | println!("Loading enemy sprite table with size: {}, height: {}, width: {}", size, height, width);
40 | let mut controller = GAME_CONTROLLER.lock().unwrap();
41 | controller.load_enemy_sprite_table(size as usize, width as f32, height as f32);
42 | }
43 |
44 | #[no_mangle]
45 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_loadPlayerSpriteTable(
46 | _env: JNIEnv,
47 | _class: JClass,
48 | size: jint,
49 | height: jint,
50 | width: jint,
51 | ) {
52 | println!("Loading run sprite table with size: {}, height: {}, width: {}", size, height, width);
53 | let mut controller = GAME_CONTROLLER.lock().unwrap();
54 | controller.load_player_sprite_table(size as usize, width as f32, height as f32);
55 | }
56 |
57 | #[no_mangle]
58 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_actionJump(
59 | _env: JNIEnv,
60 | _class: JClass,
61 | ) {
62 | let mut controller = GAME_CONTROLLER.lock().unwrap();
63 | controller.jump();
64 | }
65 |
66 | #[no_mangle]
67 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_actionStart(
68 | _env: JNIEnv,
69 | _class: JClass,
70 | ) {
71 | let mut controller = GAME_CONTROLLER.lock().unwrap();
72 | controller.start();
73 | }
74 |
75 | #[no_mangle]
76 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_isDead(
77 | _env: JNIEnv,
78 | _class: JClass,
79 | ) -> jboolean {
80 | let mut controller = GAME_CONTROLLER.lock().unwrap();
81 | if controller.player_state() == PlayerState::Dead {
82 | jni::sys::JNI_TRUE
83 | } else {
84 | jni::sys::JNI_FALSE
85 | }
86 | }
87 |
88 | #[no_mangle]
89 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_getPlayerX(
90 | _env: JNIEnv,
91 | _class: JClass,
92 | ) -> jfloat {
93 | let controller = GAME_CONTROLLER.lock().unwrap();
94 | controller.player_x()
95 | }
96 |
97 | #[no_mangle]
98 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_getPlayerY(
99 | _env: JNIEnv,
100 | _class: JClass,
101 | ) -> jfloat {
102 | let controller = GAME_CONTROLLER.lock().unwrap();
103 | controller.player_y()
104 | }
105 |
106 | #[no_mangle]
107 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_getEnemyX(
108 | _env: JNIEnv,
109 | _class: JClass,
110 | ) -> jfloat {
111 | let controller = GAME_CONTROLLER.lock().unwrap();
112 | controller.enemy_x()
113 | }
114 |
115 | #[no_mangle]
116 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_getEnemyY(
117 | _env: JNIEnv,
118 | _class: JClass,
119 | ) -> jfloat {
120 | let controller = GAME_CONTROLLER.lock().unwrap();
121 | controller.enemy_y()
122 | }
123 |
124 | #[no_mangle]
125 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_getPlayerSprite(
126 | _env: JNIEnv,
127 | _class: JClass,
128 | ) -> jint {
129 | let controller = GAME_CONTROLLER.lock().unwrap();
130 | controller.get_player_frame() as jint
131 | }
132 |
133 | #[no_mangle]
134 | pub extern "C" fn Java_com_devfigas_gamesample_NativeLib_getEnemySprite(
135 | _env: JNIEnv,
136 | _class: JClass,
137 | ) -> jint {
138 | println!("Fetching enemy sprite");
139 | let controller = GAME_CONTROLLER.lock().unwrap();
140 | controller.get_enemy_frame() as jint
141 | }
--------------------------------------------------------------------------------
/gradle-plugin/src/main/kotlin/io/github/andrefigas/rustjni/RustJniExtension.kt:
--------------------------------------------------------------------------------
1 | package io.github.andrefigas.rustjni
2 |
3 | import io.github.andrefigas.rustjni.AndroidTarget.AARCH64_LINUX_ANDROID
4 | import io.github.andrefigas.rustjni.AndroidTarget.ARMV7_LINUX_ANDROIDEABI
5 | import io.github.andrefigas.rustjni.AndroidTarget.I686_LINUX_ANDROID
6 | import io.github.andrefigas.rustjni.AndroidTarget.X86_64_LINUX_ANDROID
7 | import io.github.andrefigas.rustjni.reflection.Visibility
8 |
9 | open class RustJniExtension {
10 |
11 | companion object {
12 | internal const val DEFAULT_JNI_HOST = "com.yourpackage.YourClass"
13 | internal const val DEFAULT_LIB_NAME = "my_rust_lib"
14 |
15 | fun shouldSkipAddingMethods(jniHost: String, extension: RustJniExtension): Boolean {
16 | return jniHost == DEFAULT_JNI_HOST || !extension.exportFunctions
17 | }
18 | }
19 |
20 | // -- Settings for the user of the plugin
21 | /** The *name* of the Rust library. Same value as `package.name` in `Cargo.toml`. */
22 | var libName = ""
23 | /** The *version* of the Rust library. Same value as `package.version` in `Cargo.toml`.
24 | *
25 | * Is only used to generate Rust project if it doesn't exist. */
26 | var libVersion = "0.1.0"
27 | /** The path to the Rust library, i.e. the directory where `Cargo.toml` is in,
28 | * relative to the project's root directory. */
29 | var rustPath = "./rust"
30 | /** The version of NDK to use.
31 | * This is one of the directories found in `{sdk.dir}/ndk/`.
32 | *
33 | * Automatically uses the latest version if a value is not provided. */
34 | var ndkVersion = ""
35 | /** Corresponds to the OS you are building with.
36 | *
37 | * Value is automatically assigned to the host OS. */
38 | var preBuilt = ""
39 | /** The **Class** in your project that will load the Rust library and have all the `native`/`extern` functions.
40 | *
41 | * This is used to generated Rust code and library loader in the named Class. */
42 | var jniHost = DEFAULT_JNI_HOST
43 |
44 | /** The visibility of the generated functions in the Class [jniHost].
45 | * Default is [Visibility.DEFAULT].
46 | * Options are [Visibility.PUBLIC], [Visibility.PROTECTED], [Visibility.PRIVATE], [Visibility.DEFAULT].
47 | * Disclaimer: DEFAULT will omit the visibility modifier and assume the default visibility of the Programming Language.
48 | */
49 | var jniMethodsVisibility : Visibility = Visibility.DEFAULT
50 |
51 | /** Whether `native`/`extern` functions should be generated in the Class [jniHost].
52 | *
53 | * Default is `true`. */
54 | var exportFunctions = true
55 | var applyAsCompileDependency = true
56 |
57 | /**
58 | * Specifies the required Rust version for this project.
59 | *
60 | * This field accepts the following formats:
61 | *
62 | * 1. Exact version:
63 | * - Example: "1.76.0"
64 | * - The build will require exactly this Rust version.
65 | *
66 | * 2. Minimum version (range):
67 | * - Example: ">=1.64.0"
68 | * - Indicates that the project requires at least version 1.64.0 of Rust or newer.
69 | *
70 | * 3. Wildcard version:
71 | * - Example: "1.76.*"
72 | * - Allows any patch version within the specified minor version (e.g., 1.76.0, 1.76.1, etc).
73 | */
74 | var rustVersion: String = ""
75 |
76 | private var architectures: (ArchitectureListScope.() -> Unit)? = null
77 |
78 | fun architectures(architectures: ArchitectureListScope.() -> Unit) {
79 | this.architectures = architectures
80 | }
81 |
82 | internal val architecturesList: List
83 | get() {
84 | val list = mutableListOf()
85 | val scope = ArchitectureListScope(list)
86 | architectures?.let { scope.it() }
87 | return list.toList()
88 | }
89 |
90 | }
91 |
92 | class ArchitectureListScope(private val list: MutableList) {
93 |
94 | fun custom(
95 | target: String, linker: String,
96 | ar: String = ArchitectureConfig.DEFAULT_AR
97 | ) {
98 | list.add(
99 | ArchitectureConfig(
100 | target,
101 | linker,
102 | ar
103 | )
104 | )
105 | }
106 |
107 | fun armv7_linux_androideabi(
108 | linker: String,
109 | ar: String = ArchitectureConfig.DEFAULT_AR
110 | ) {
111 | list.add(
112 | ArchitectureConfig(
113 | ARMV7_LINUX_ANDROIDEABI,
114 | linker,
115 | ar
116 | )
117 | )
118 | }
119 |
120 | fun aarch64_linux_android(
121 | linker: String,
122 | ar: String = ArchitectureConfig.DEFAULT_AR
123 | ) {
124 | list.add(
125 | ArchitectureConfig(
126 | AARCH64_LINUX_ANDROID,
127 | linker,
128 | ar
129 | )
130 | )
131 | }
132 |
133 | fun i686_linux_android(
134 | linker: String,
135 | ar: String = ArchitectureConfig.DEFAULT_AR
136 | ) {
137 | list.add(
138 | ArchitectureConfig(
139 | I686_LINUX_ANDROID,
140 | linker,
141 | ar
142 | )
143 | )
144 | }
145 |
146 | fun x86_64_linux_android(
147 | linker: String,
148 | ar: String = ArchitectureConfig.DEFAULT_AR
149 | ) {
150 | list.add(
151 | ArchitectureConfig(
152 | X86_64_LINUX_ANDROID,
153 | linker,
154 | ar
155 | )
156 | )
157 | }
158 |
159 | }
160 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/sample/java/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/sample/kotlin/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/sample/game/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/sample/java/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/sample/kotlin/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/sample/game/app/src/main/rust/src/game_controller.rs:
--------------------------------------------------------------------------------
1 | use crate::player_state::PlayerState;
2 | use std::time::{Duration, Instant};
3 |
4 | pub struct GameController {
5 | canvas_width: f32,
6 | canvas_height: f32,
7 | player_sprite_width: f32,
8 | player_sprite_height: f32,
9 | enemy_sprite_width: f32,
10 | enemy_sprite_height: f32,
11 |
12 | // Jump and run properties
13 | player_frame_duration: Duration,
14 | game_start_time: Option,
15 | player_frames: usize,
16 | jump_height: f32, // 0.0 to 1.0
17 | jump_duration: Duration,
18 | jump_start_time: Option,
19 |
20 | // Enemy properties
21 | enemy_frame_duration: Duration,
22 | enemy_frames: usize,
23 | enemy_route_duration: Duration,
24 | }
25 |
26 | impl GameController {
27 | pub fn new() -> Self {
28 | GameController {
29 | canvas_width: 0.0,
30 | canvas_height: 0.0,
31 | player_sprite_width: 0.0,
32 | player_sprite_height: 0.0,
33 | enemy_sprite_width: 0.0,
34 | enemy_sprite_height: 0.0,
35 | player_frame_duration: Duration::from_millis(50), // 50 ms per frame
36 | game_start_time: None,
37 | player_frames: 0,
38 | jump_height: 0.5, // default max jump height factor
39 | jump_duration: Duration::from_millis(3000), // 1.5 sec jump duration
40 | jump_start_time: None,
41 | enemy_frame_duration: Duration::from_millis(50),
42 | enemy_frames: 0,
43 | enemy_route_duration: Duration::from_secs(5),
44 | }
45 | }
46 |
47 | pub fn player_state(&mut self) -> PlayerState {
48 |
49 | if self.detect_collision() {
50 | self.game_start_time = None; // Reset game start time upon collision
51 | PlayerState::Dead
52 | } else {
53 | PlayerState::Live
54 | }
55 | }
56 |
57 | fn detect_collision(&self) -> bool {
58 | if self.game_start_time.is_none() {
59 | return false;
60 | }
61 |
62 | let player_x1 = self.player_x();
63 | let player_x2 = player_x1 + self.player_sprite_width;
64 | let player_y1 = self.player_y();
65 | let player_y2 = player_y1 + self.player_sprite_height;
66 |
67 | let enemy_x1 = self.enemy_x();
68 | let enemy_x2 = enemy_x1 + self.enemy_sprite_width;
69 | let enemy_y1 = self.enemy_y();
70 | let enemy_y2 = enemy_y1 + self.enemy_sprite_height;
71 |
72 | let x_collision = player_x1 < enemy_x2 && player_x2 > enemy_x1;
73 | let y_collision = player_y1 < enemy_y2 && player_y2 > enemy_y1;
74 |
75 | x_collision && y_collision
76 | }
77 |
78 |
79 | pub fn jump(&mut self) {
80 | if let Some(start_time) = self.jump_start_time {
81 | if start_time.elapsed() < self.jump_duration {
82 | return; // Ignore the new jump command
83 | }
84 | }
85 | self.jump_start_time = Some(Instant::now());
86 | }
87 |
88 | pub fn start(&mut self) {
89 | self.game_start_time = Some(Instant::now());
90 | }
91 |
92 | pub fn set_canvas_dimensions(&mut self, width: f32, height: f32) {
93 | self.canvas_width = width;
94 | self.canvas_height = height;
95 | }
96 |
97 | pub fn load_player_sprite_table(&mut self, total_frames: usize, sprite_width: f32, sprite_height: f32) {
98 | self.player_frames = total_frames;
99 | self.set_player_sprite_dimensions(sprite_width, sprite_height);
100 | }
101 |
102 | pub fn set_player_sprite_dimensions(&mut self, width: f32, height: f32) {
103 | self.player_sprite_width = width;
104 | self.player_sprite_height = height;
105 | }
106 |
107 | pub fn load_enemy_sprite_table(&mut self, total_frames: usize, sprite_width: f32, sprite_height: f32) {
108 | self.enemy_frames = total_frames;
109 | self.set_enemy_sprite_dimensions(sprite_width, sprite_height);
110 | }
111 |
112 | pub fn set_enemy_sprite_dimensions(&mut self, width: f32, height: f32) {
113 | self.enemy_sprite_width = width;
114 | self.enemy_sprite_height = height;
115 | }
116 |
117 | pub fn get_player_frame(&self) -> usize {
118 | if let Some(start_time) = self.game_start_time {
119 | let elapsed = start_time.elapsed();
120 | let frame_count = (elapsed.as_millis() / self.player_frame_duration.as_millis()) as usize;
121 | frame_count % self.player_frames
122 | } else {
123 | 0
124 | }
125 | }
126 |
127 | pub fn player_x(&self) -> f32 {
128 | (self.canvas_width / 2.0) - (self.player_sprite_width / 2.0)
129 | }
130 |
131 | pub fn player_y(&self) -> f32 {
132 | let default_y = (self.canvas_height / 2.0) - (self.player_sprite_height / 2.0);
133 |
134 | if let Some(start_time) = self.jump_start_time {
135 | let elapsed = start_time.elapsed();
136 |
137 | // If the jump duration is complete, return to the default y position
138 | if elapsed >= self.jump_duration {
139 | return default_y;
140 | }
141 |
142 | // Normalize `t` to range from 0.0 to 1.0 over the jump duration
143 | let t = elapsed.as_secs_f32() / self.jump_duration.as_secs_f32();
144 |
145 | // Calculate the peak height of the jump (occurs at the midpoint of the jump duration)
146 | let jump_peak_y = default_y - (self.jump_height * default_y);
147 |
148 | // Parabolic interpolation for a smooth ascent and descent
149 | return default_y + (jump_peak_y - default_y) * (1.0 - 4.0 * (t - 0.5).powi(2));
150 | }
151 |
152 | // Return `default_y` if no jump is active
153 | default_y
154 | }
155 |
156 | pub fn get_enemy_frame(&self) -> usize {
157 | if let Some(start_time) = self.game_start_time {
158 | let elapsed = start_time.elapsed();
159 | let frame_count = (elapsed.as_millis() / self.enemy_frame_duration.as_millis()) as usize;
160 | frame_count % self.enemy_frames
161 | } else {
162 | 0
163 | }
164 | }
165 |
166 | pub fn enemy_x(&self) -> f32 {
167 | if let Some(start_time) = self.game_start_time {
168 | let elapsed_secs = start_time.elapsed().as_secs_f32();
169 | let route_duration_secs = self.enemy_route_duration.as_secs_f32();
170 | let t = (elapsed_secs % route_duration_secs) / route_duration_secs;
171 | let start_x = self.canvas_width;
172 | let end_x = 0.0 - self.enemy_sprite_width;
173 | start_x + (end_x - start_x) * t
174 | } else {
175 | self.canvas_width
176 | }
177 | }
178 |
179 | pub fn enemy_y(&self) -> f32 {
180 | (self.canvas_height / 2.0) - (self.enemy_sprite_height / 2.0)
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/gradle-plugin-test/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | `maven-publish`
4 | id("com.gradle.plugin-publish") version "1.2.0"
5 | }
6 |
7 | repositories {
8 | mavenCentral()
9 | google()
10 | }
11 |
12 | version = "0.0.1"
13 | group = "io.github.andrefigas.rustjni-test"
14 |
15 | gradlePlugin {
16 | plugins {
17 | create("rustJniPlugin") {
18 | id = "io.github.andrefigas.rustjni-test"
19 | implementationClass = "io.github.andrefigas.rustjni.test.RustJNITest"
20 | displayName = "Rust JNI Gradle Plugin"
21 | description = "A Gradle plugin that simplifies the creation and compilation of Rust code integrated with Android applications via JNI."
22 | }
23 | }
24 | }
25 |
26 | dependencies {
27 | implementation(kotlin("stdlib"))
28 | implementation(gradleApi())
29 | implementation(localGroovy())
30 | compileOnly("com.android.tools.build:gradle:8.1.1")
31 | }
32 |
33 | // Function to insert the plugin line into the build.gradle.kts file
34 | fun insertPluginLine(projectDir: File, pluginLine: String) {
35 | val buildGradleFile = File(projectDir, "app/build.gradle.kts")
36 | val trimmedPlugin = pluginLine.trim().replace("\n", "").replace("\r", "")
37 |
38 | if (buildGradleFile.exists()) {
39 | val buildGradleContent = buildGradleFile.readText()
40 |
41 | // Escape special characters in the plugin line for use in the regex
42 | val escapedPluginLine = Regex.escape(trimmedPlugin)
43 |
44 | // Check if the plugin is already present by using the plugin line passed as an argument
45 | if (!Regex(escapedPluginLine).containsMatchIn(buildGradleContent)) {
46 | // Ensure there is a newline after the opening brace
47 | val updatedContent = buildGradleContent.replaceFirst(
48 | Regex("""plugins\s*\{\s*"""), // Match "plugins {" and ensure a newline is added
49 | """plugins {
50 |
51 | """ // Add an explicit newline and indentation
52 | )
53 |
54 | // Insert the plugin line after the first brace
55 | val finalContent = updatedContent.replaceFirst(
56 | Regex("""plugins\s*\{\s*"""),
57 | """plugins {
58 | $trimmedPlugin
59 | """
60 | )
61 |
62 | // Write the modified content back to the build.gradle.kts file
63 | buildGradleFile.writeText(finalContent)
64 | println("Plugin line successfully inserted!")
65 | } else {
66 | println("The plugin is already present in build.gradle.kts.")
67 | }
68 | } else {
69 | throw GradleException("build.gradle.kts file not found!")
70 | }
71 | }
72 |
73 | // Function to remove the plugin line from the build.gradle.kts file
74 | fun removePluginLine(projectDir: File, pluginLine: String) {
75 | val buildGradleFile = File(projectDir, "app/build.gradle.kts")
76 | val trimmedPlugin = pluginLine.trim().replace("\n", "").replace("\r", "")
77 |
78 | if (buildGradleFile.exists()) {
79 | val buildGradleContent = buildGradleFile.readText()
80 |
81 | // Escape special characters in the plugin line for use in the regex
82 | val escapedPluginLine = Regex.escape(trimmedPlugin)
83 |
84 | // Create a flexible regex to capture the plugin line, allowing variations in spaces and line breaks,
85 | // but preserving surrounding newlines
86 | val pluginRegex = Regex("""^\s*$escapedPluginLine\s*$\n?""", RegexOption.MULTILINE)
87 |
88 | // Check if the plugin is present
89 | if (pluginRegex.containsMatchIn(buildGradleContent)) {
90 | // Remove only the plugin line and leave the surrounding structure intact
91 | val updatedContent = buildGradleContent.replace(pluginRegex, "")
92 |
93 | // Write the modified content back to build.gradle.kts
94 | buildGradleFile.writeText(updatedContent.trimEnd() + "\n") // Ensures proper formatting with a newline at the end
95 | println("Plugin line successfully removed!")
96 | } else {
97 | println("The plugin line was not found in build.gradle.kts.")
98 | }
99 | } else {
100 | throw GradleException("build.gradle.kts file not found!")
101 | }
102 | }
103 |
104 | // Function to execute a gradle task in another project
105 | fun executeGradleTask(projectDir: File, taskName: String) {
106 | val gradleCmd = if (System.getProperty("os.name").toLowerCase().contains("windows")) {
107 | "gradlew.bat"
108 | } else {
109 | "./gradlew"
110 | }
111 |
112 | val gradleWrapperFile = File(projectDir, gradleCmd)
113 | if (!gradleWrapperFile.exists()) {
114 | throw GradleException("Gradle wrapper not found in the project directory")
115 | }
116 |
117 | // Ensure execution permissions on Unix-like systems
118 | if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
119 | exec {
120 | commandLine("chmod", "+x", gradleWrapperFile.absolutePath)
121 | }
122 | }
123 |
124 | // Execute the Gradle task
125 | exec {
126 | workingDir = projectDir
127 | commandLine(gradleWrapperFile.absolutePath, taskName)
128 | }
129 | }
130 |
131 | tasks.register("executeTest") {
132 | doLast {
133 | // Define the project directories and task names
134 | val kotlinDir = file("$projectDir/../sample/kotlin")
135 | val javaDir = file("$projectDir/../sample/java")
136 | val pluginDir = file("$projectDir/../gradle-plugin")
137 | val pluginLine = """id("io.github.andrefigas.rustjni-test") version "0.0.1""""
138 | val testTaskKotlin = ":app:rust-jni-compile-test"
139 | val testTaskJava = ":app:rust-jni-compile-test"
140 | val publishLocalTask = "publishToMavenLocal"
141 |
142 | // Step 1: Publish local dependencies
143 | println("Publishing test plugin to Maven local...")
144 | tasks.getByPath(publishLocalTask).actions.forEach {
145 | it.execute(this)
146 | }
147 |
148 | executeGradleTask(pluginDir, publishLocalTask)
149 |
150 | // Step 2: Insert the plugin line in both Kotlin and Java sample projects
151 | println("Inserting plugin line in Kotlin project...")
152 | insertPluginLine(kotlinDir, pluginLine)
153 |
154 | println("Inserting plugin line in Java project...")
155 | insertPluginLine(javaDir, pluginLine)
156 |
157 | // Step 3: Execute the test tasks in both Kotlin and Java projects
158 | println("🦀 Executing test task in Kotlin project...")
159 | executeGradleTask(kotlinDir, testTaskKotlin)
160 |
161 | println("🦀 Executing test task in Java project...")
162 | executeGradleTask(javaDir, testTaskJava)
163 |
164 | // Step 4: Remove the plugin line after the tasks are executed
165 | println("Removing plugin line in Kotlin project...")
166 | removePluginLine(kotlinDir, pluginLine)
167 |
168 | println("Removing plugin line in Java project...")
169 | removePluginLine(javaDir, pluginLine)
170 | }
171 |
172 | }
173 |
174 |
175 |
176 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rust JNI
2 |
3 | Although Android Studio does not offer robust support for Rust, this plugin provides a solid solution to integrate Rust with Android. Rather than reinventing the wheel, it replicates some of the conveniences that Android Studio offers when integrating Java with C++, but tailored for Rust.
4 |
5 | ## Requirements
6 |
7 | | Requirement | Min. Version |
8 | |-----------------------------------------------------|--------------|
9 | | [Rust](https://www.rust-lang.org/learn/get-started) | 1.79.0 |
10 | | NDK (Tools -> SDK Manager -> SDK Tools -> NDK) | |
11 |
12 | ## Setup
13 |
14 | ### Import Plugin
15 |
16 | **build.gradle.kts** (module level)
17 | ```kotlin
18 | plugins {
19 | //...
20 | id("io.github.andrefigas.rustjni") version ""
21 | }
22 | ```
23 | Check the latest version [here](https://plugins.gradle.org/plugin/io.github.andrefigas.rustjni) (recommend) or maybe the [CHANGELOG.md](./doc/CHANGELOG.md) can help you to choose a version.
24 |
25 | ### Configure architecture
26 |
27 | **build.gradle.kts** (module level)
28 | ```kotlin
29 | rustJni{
30 | rustPath = "./app/src/main/rust"
31 | ndkVersion = "25.2.9519653"
32 | architectures {
33 | armv7_linux_androideabi("armv7a-linux-androideabi21-clang")
34 | aarch64_linux_android("aarch64-linux-android21-clang")
35 | i686_linux_android("i686-linux-android21-clang")
36 | x86_64_linux_android("x86_64-linux-android21-clang")
37 | }
38 | }
39 | ```
40 | Here, you define the architectures you want to target when compiling your Rust code, along with the respective linkers.
41 |
42 | You can find the available linkers in this directory:
43 | ```
44 | //toolchains/llvm/prebuilt//bin/
45 | ```
46 | *The `` folder will correspond to your OS, such as: linux-x86_64, linux-arm64, windows-x86_64, or darwin-x86_64.*
47 |
48 | Let’s break down the sample argument:
49 |
50 | ```aarch64_linux_android("aarch64-linux-android21-clang")```
51 |
52 | This configures the Rust library to be compiled for the `aarch64_linux_android` architecture using the `aarch64-linux-android21-clang` linker, targeting Android API level 21.
53 |
54 | ### How to create or compile a Rust library for Android?
55 |
56 | Once the setup is finished, you only need to compile your project to ensure the Rust code is compiled before the Android code.
57 |
58 |
59 | This will compile your Rust project. If you don't have one, a new project will be created here:
60 | `app/src/main/rust/src/rust_jni.rs`
61 |
62 | ### How to link the Rust library with the Android project
63 |
64 | Inform the plugin which Kotlin/Java class will load the Rust library.
65 |
66 | ```kotlin
67 | rustJni{
68 | rustPath = "./app/src/main/rust"
69 | ndkVersion = "25.2.9519653"
70 | jniHost = "com.devfigas.rustjni.sample.MainActivity"
71 | architectures {
72 | armv7_linux_androideabi("armv7a-linux-androideabi21-clang")
73 | aarch64_linux_android("aarch64-linux-android21-clang")
74 | i686_linux_android("i686-linux-android21-clang")
75 | x86_64_linux_android("x86_64-linux-android21-clang")
76 | }
77 | }
78 | ```
79 |
80 | Compile your project again, and it will generate the JNI code for you.
81 |
82 | ```kotlin
83 | class MainActivity : AppCompatActivity() {
84 |
85 | //
86 | // auto-generated code
87 | // Checkout the source: rust/src/rust_jni.rs
88 | private external fun sayHello(): String
89 |
90 | init {
91 | System.loadLibrary("my_rust_lib")
92 | }
93 | //
94 |
95 | override fun onCreate(savedInstanceState: Bundle?) {
96 | super.onCreate(savedInstanceState)
97 | setContentView(R.layout.activity_main)
98 | println(
99 | sayHello()
100 | )
101 | }
102 |
103 | }
104 | ```
105 | Check your console log for something like this:
106 | ```
107 | __________________________
108 | < Hello RustJNI >
109 | --------------------------
110 | \\
111 | \\
112 | _~^~^~_
113 | \\) / o o \\ (/
114 | '_ - _'
115 | / '-----' \\
116 | _________________________________________________________
117 | Do your rust implementation there: app/src/main/rust/src/rust_jni.rs
118 | ---------------------------------------------------------
119 | ```
120 |
121 | ### How to generate Rust code ?
122 |
123 | If you already used c++ in Android, you already saw something like this:
124 | 
125 |
126 | If you opt to use the use rust, there are a easier solution: It will be generated automatically when you compile your project:
127 |
128 | You just have to:
129 | - Make sure you filled the [jniHost](#how-to-link-the-rust-library-with-the-android-project) in the rustJni configuration
130 | - Make sure your method follows that pattern:
131 |
132 | **kotlin**
133 | ```kotlin
134 | private external fun foo(): String
135 | ```
136 |
137 | **java**
138 | ```java
139 | private static native String foo();
140 | ```
141 |
142 | - Your code have to be placed between the comments `//` and `//`
143 |
144 | ```
145 | //
146 | // auto-generated code
147 |
148 | //
149 |
150 | static { System.loadLibrary("my_rust_lib"); }
151 |
152 | //
153 | ```
154 |
155 | ### How to generate Java/Kotlin code ?
156 |
157 | You can do the opposite, you can generate you JNI code first and let this plugin mirror it in your Kotlin/Java code.
158 | You just have to follow same [instructions](#how-to-generate-rust-code) as above.
159 |
160 | When you compile your project, the plugin will create those methods in your Kotlin/Java code.
161 |
162 | Additionally, you may want to change the methods visibility:
163 |
164 | - Visibility.PUBLIC
165 | - Visibility.PRIVATE
166 | - Visibility.PROTECTED
167 | - Visibility.DEFAULT: this one will omit the this modifier and assume default visibility by programming language: Kotlin (**public**) and Java (**package-private**)
168 |
169 | ```kotlin
170 | rustJni{
171 | //...
172 | jniMethodsVisibility = Visibility.PUBLIC
173 | //...
174 | }
175 | ```
176 |
177 | ### How to define what Rust version is acceptable to compile your project ?
178 |
179 | You can define the Rust version that is acceptable to compile your project.
180 | This is useful if you want to ensure that your project is always compiled with a specific version of Rust.
181 |
182 | ```kotlin
183 | rustJni{
184 | //...
185 | rustVersion = "1.86.0"
186 | //...
187 | }
188 | ```
189 |
190 | #### Supported `rustVersion` patterns
191 |
192 | | Feature | Pattern Example | Description |
193 | |------------------|-------------------------------|-----------------------------------------------------|
194 | | Exact version | `1.86.0` | Only this exact Rust version is accepted |
195 | | Minimum version | `>=1.64.0` | Accepts any version greater than or equal to this |
196 | | Wildcard version | `1.86.*`, `1.*.*` | Allows flexibility within minor and/or patch versions |
197 |
198 | ### How to define a custom path for rust?
199 |
200 | By default, Rust is installed in the following directory:
201 |
202 | - **macOS/Linux**: `~/.cargo/bin`
203 | - **Windows**: `%USERPROFILE%\.cargo\bin`
204 |
205 | However, you can specify a custom installation directory by setting it in your **`local.properties`** file. For example:
206 |
207 | `cargo.dir=/Users//cargo_tmp/.cargo/bin`
208 |
209 | ### How can I take a look at some samples?
210 |
211 | - [Java](./sample/java) - A java sample with 1 method
212 | - [Kotlin](./sample/kotlin) - A kotlin sample with 1 method
213 | - [Game](./sample/game) - A simple game without any engine like cocos2d, just Rust and Android
214 |
--------------------------------------------------------------------------------
/gradle-plugin/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/gradle-plugin-test/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------