Package the Rust mobile core and generated Kotlin API for Android (#92)
Dependency security audit / rustsec (push) Failing after 24s
Dependency security audit / rustsec (push) Failing after 24s
This commit is contained in:
1 parent
e079b82b15
commit
fcb36a0684
42 files changed
+1586
-172
No files matched your search
Generated
+12
@@ -5433,12 +5433,22 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ironstorage-android"
|
||||||
|
version = "1.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"ironstorage-apple",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ironstorage-android-build"
|
name = "ironstorage-android-build"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ironstorage",
|
"ironstorage",
|
||||||
|
"object",
|
||||||
"regex",
|
"regex",
|
||||||
|
"uniffi",
|
||||||
|
"zip",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -10550,7 +10560,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "a782a48d72cfd7a2d65cfc7c691dbf5375c43104b3c195f7eccc716dcc3540c8"
|
checksum = "a782a48d72cfd7a2d65cfc7c691dbf5375c43104b3c195f7eccc716dcc3540c8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"camino",
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
|
"clap",
|
||||||
"uniffi_bindgen",
|
"uniffi_bindgen",
|
||||||
"uniffi_core",
|
"uniffi_core",
|
||||||
"uniffi_macros",
|
"uniffi_macros",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ members = [
|
|||||||
"apps/desktop",
|
"apps/desktop",
|
||||||
"apps/tui",
|
"apps/tui",
|
||||||
"crates/apple",
|
"crates/apple",
|
||||||
|
"crates/android",
|
||||||
"crates/storage",
|
"crates/storage",
|
||||||
"crates/watch-apple",
|
"crates/watch-apple",
|
||||||
"tools/android-build",
|
"tools/android-build",
|
||||||
|
|||||||
+14
-2
@@ -31,7 +31,7 @@ The current direct dependencies are:
|
|||||||
| [regex 1.13](https://crates.io/crates/regex/1.13.1) | Linear-time byte-oriented decrypted grep matching | MIT OR Apache-2.0 |
|
| [regex 1.13](https://crates.io/crates/regex/1.13.1) | Linear-time byte-oriented decrypted grep matching | MIT OR Apache-2.0 |
|
||||||
| [tempfile 3](https://crates.io/crates/tempfile) | Permission-restricted CLI editor session directories and cleanup | MIT OR Apache-2.0 |
|
| [tempfile 3](https://crates.io/crates/tempfile) | Permission-restricted CLI editor session directories and cleanup | MIT OR Apache-2.0 |
|
||||||
| [Serde 1](https://crates.io/crates/serde), [TOML 0.9](https://crates.io/crates/toml), [shlex 1.3](https://crates.io/crates/shlex), [url 2.5](https://crates.io/crates/url) | Strict configuration and command values | MIT OR Apache-2.0 |
|
| [Serde 1](https://crates.io/crates/serde), [TOML 0.9](https://crates.io/crates/toml), [shlex 1.3](https://crates.io/crates/shlex), [url 2.5](https://crates.io/crates/url) | Strict configuration and command values | MIT OR Apache-2.0 |
|
||||||
| [UniFFI 0.32](https://crates.io/crates/uniffi/0.32.0) | Swift bridge | MPL-2.0 |
|
| [UniFFI 0.32](https://crates.io/crates/uniffi/0.32.0) | Swift and Kotlin bridge | MPL-2.0 |
|
||||||
| [zeroize 1.9](https://crates.io/crates/zeroize/1.9.0) | Clear decrypted bytes on drop | MIT OR Apache-2.0 |
|
| [zeroize 1.9](https://crates.io/crates/zeroize/1.9.0) | Clear decrypted bytes on drop | MIT OR Apache-2.0 |
|
||||||
|
|
||||||
The activated transitive graph has no dependency that forces a GPL or LGPL
|
The activated transitive graph has no dependency that forces a GPL or LGPL
|
||||||
@@ -115,4 +115,16 @@ version catalog pins stable AndroidX, Kotlin, Hilt/KSP and formatting tools.
|
|||||||
Espresso 3.7.0 is pinned explicitly because Compose's older transitive Espresso
|
Espresso 3.7.0 is pinned explicitly because Compose's older transitive Espresso
|
||||||
cannot initialize input injection on API 37. AndroidX Test is Apache-2.0;
|
cannot initialize input injection on API 37. AndroidX Test is Apache-2.0;
|
||||||
JUnit 4.13.2 is EPL-1.0 and test-only. ktlint and its Gradle plugin are MIT,
|
JUnit 4.13.2 is EPL-1.0 and test-only. ktlint and its Gradle plugin are MIT,
|
||||||
build-only tools. Native runtime dependency/ABI review belongs to #92.
|
build-only tools.
|
||||||
|
|
||||||
|
#92 packages [JNA 5.19.1](https://repo.maven.apache.org/maven2/net/java/dev/jna/jna/5.19.1/jna-5.19.1.pom)
|
||||||
|
as the Android AAR under its Apache-2.0 option (dual-licensed with LGPL-2.1-or-later).
|
||||||
|
It is the OS FFI runtime required by generated UniFFI Kotlin, not a competing
|
||||||
|
storage implementation. Its Android native libraries are subject to the same
|
||||||
|
three-ABI, ELF and 16 KB APK alignment checks as Rust. Exact resolved AAR/POM
|
||||||
|
checksums and locks are committed. cargo-ndk 4.1.2 (MIT OR Apache-2.0) is build-only;
|
||||||
|
NDK 30.0.16248370 and Rust 1.97.1 are pinned and checked. The build-only ELF/ZIP
|
||||||
|
auditor reuses locked object 0.36.7 (Apache-2.0 OR MIT) and zip 2.4.2 (MIT)
|
||||||
|
versions already present in the workspace. UniFFI's MPL-2.0 source remains available
|
||||||
|
at its recorded upstream crate version. Release attribution assembly is owned by
|
||||||
|
#112; the dependency policy and runtime matrix are in android/README.md.
|
||||||
+95
-15
@@ -1,13 +1,13 @@
|
|||||||
# Native Android build
|
# Native Android build
|
||||||
|
|
||||||
Architecture and issue ownership: [ADR](../docs/android/architecture.md) and
|
Architecture and issue ownership: [ADR](../docs/android/architecture.md) and
|
||||||
[parity matrix](../docs/android/parity.md). This scaffold implements #89. It is
|
[parity matrix](../docs/android/parity.md). The native foundation implements #89 and #92. Onboarding and secure storage
|
||||||
an installable native Compose foundation; onboarding, secure storage and native
|
are implemented by their milestone issues. Both variants now invoke Rust through
|
||||||
runtime packaging are implemented by their milestone issues.
|
the generated UniFFI API.
|
||||||
|
|
||||||
## Reproducible setup
|
## Reproducible setup
|
||||||
|
|
||||||
Use a stable workspace Rust toolchain satisfying Cargo.toml, a JDK 25 installation
|
Use Rust 1.97.1 (pinned in rust-toolchain.toml), cargo-ndk 4.1.2, a JDK 25 installation
|
||||||
(Android Studio's JetBrains Runtime 25 is suitable), Android SDK Platform 37,
|
(Android Studio's JetBrains Runtime 25 is suitable), Android SDK Platform 37,
|
||||||
build-tools 36.0.0 and NDK 30.0.16248370. The app emits JVM 17-compatible code
|
build-tools 36.0.0 and NDK 30.0.16248370. The app emits JVM 17-compatible code
|
||||||
and supports minSdk 26. Set JAVA_HOME and ANDROID_HOME/ANDROID_SDK_ROOT or create
|
and supports minSdk 26. Set JAVA_HOME and ANDROID_HOME/ANDROID_SDK_ROOT or create
|
||||||
@@ -19,14 +19,14 @@ The committed Gradle 9.8.1 wrapper verifies the distribution SHA-256. Its JAR
|
|||||||
SHA-256 is 3b8a25775a69158b5ad2b1d17a80a88dc7b40a352a73eb27d06c612a7ce68e98,
|
SHA-256 is 3b8a25775a69158b5ad2b1d17a80a88dc7b40a352a73eb27d06c612a7ce68e98,
|
||||||
verified against the official Gradle version metadata. AGP 9.4.1 includes Kotlin
|
verified against the official Gradle version metadata. AGP 9.4.1 includes Kotlin
|
||||||
support; the Kotlin JVM/Compose plugin pin upgrades its classpath consistently
|
support; the Kotlin JVM/Compose plugin pin upgrades its classpath consistently
|
||||||
to 2.4.20. Do not additionally apply kotlin-android with built-in Kotlin enabled.
|
to 2.4.21. Do not additionally apply kotlin-android with built-in Kotlin enabled.
|
||||||
The version catalog is the single source for Android dependency/SDK/NDK pins.
|
The version catalog is the single source for Android dependency/SDK/NDK pins.
|
||||||
|
|
||||||
From this directory:
|
From this directory:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./gradlew :app:assembleDebug :app:assembleRelease :app:testDebugUnitTest :app:lintDebug ktlintCheck
|
./gradlew auditNativePackages :core:testDebugUnitTest :app:testDebugUnitTest :app:lintDebug :app:lintRelease ktlintCheck
|
||||||
./gradlew :app:connectedDebugAndroidTest
|
./gradlew :app:connectedDebugAndroidTest :rust-bridge:connectedDebugAndroidTest
|
||||||
```
|
```
|
||||||
|
|
||||||
Repeat the first command to verify configuration-cache reuse. Dependency
|
Repeat the first command to verify configuration-cache reuse. Dependency
|
||||||
@@ -50,12 +50,11 @@ source/import boundaries and subprocess paths before every Android build.
|
|||||||
These static checks accompany code review; they do not prove arbitrary Kotlin
|
These static checks accompany code review; they do not prove arbitrary Kotlin
|
||||||
code cannot conceal a domain implementation.
|
code cannot conceal a domain implementation.
|
||||||
|
|
||||||
Debug-only Loading/Empty/Ready/Locked/Error fixtures are generated from the
|
Debug controls invoke the storage-owned MobileShell::fixture through the native
|
||||||
storage-owned MobileShell::fixture by the Rust build tool. Debug controls select
|
API for Loading/Empty/Ready/Locked/Error. A build-generated fixture inventory is
|
||||||
the fixture and native tabs; these controls and generated fake states are absent
|
used only as the test oracle. Release calls the same Rust Empty fixture without
|
||||||
from release. Release displays the scaffold state and does not pretend to have
|
debug controls; repository initialization is owned by #90. Feature code consumes
|
||||||
opened/decrypted a repository. Future #92 replaces scaffold wiring with generated
|
only the facade, including typed native recovery states.
|
||||||
UniFFI calls; feature code continues to consume the facade.
|
|
||||||
|
|
||||||
## Identity, signing and update
|
## Identity, signing and update
|
||||||
|
|
||||||
@@ -64,8 +63,8 @@ Version code 1 and name 1.0.1 are deterministic initial metadata. Debug signing
|
|||||||
uses the standard local debug key. Release has no configured signing key and
|
uses the standard local debug key. Release has no configured signing key and
|
||||||
produces an unsigned APK; #112 configures protected upload signing. Do not add
|
produces an unsigned APK; #112 configures protected upload signing. Do not add
|
||||||
signing secrets or store passwords to the repository. Native symbol level FULL
|
signing secrets or store passwords to the repository. Native symbol level FULL
|
||||||
and the selected three ABIs are declared for later Rust packaging; the scaffold
|
and the selected three ABIs are packaged. Native runtime packaging is described
|
||||||
ships no native secret runtime or development network endpoint.
|
below; no development network endpoint is included.
|
||||||
|
|
||||||
The manifest has only the exported launcher activity. Backup/cloud/device-transfer
|
The manifest has only the exported launcher activity. Backup/cloud/device-transfer
|
||||||
exclusions and cleartext denial are explicit. Feature-specific services/permissions
|
exclusions and cleartext denial are explicit. Feature-specific services/permissions
|
||||||
@@ -87,3 +86,84 @@ app-data package as an update. After closing an issue, clean its project build
|
|||||||
outputs and Cargo target; preserve the emulator and shared SDK/toolchain caches.
|
outputs and Cargo target; preserve the emulator and shared SDK/toolchain caches.
|
||||||
AGP's leaveApksInstalledAfterRun option is enabled so instrumented checks do not
|
AGP's leaveApksInstalledAfterRun option is enabled so instrumented checks do not
|
||||||
uninstall the app after running. Keep it enabled for this persistent test device.
|
uninstall the app after running. Keep it enabled for this persistent test device.
|
||||||
|
|
||||||
|
## Rust packaging and integrity
|
||||||
|
|
||||||
|
Install the pinned build tools once:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
rustup toolchain install 1.97.1 --profile minimal
|
||||||
|
rustup target add --toolchain 1.97.1 aarch64-linux-android armv7-linux-androideabi x86_64-linux-android
|
||||||
|
cargo install cargo-ndk --version 4.1.2 --locked
|
||||||
|
```
|
||||||
|
|
||||||
|
Gradle checks the actual Cargo/cargo-ndk/NDK revisions before building. Each
|
||||||
|
variant compiles crates/android with cargo-ndk into its own generated jniLibs,
|
||||||
|
then verifies ELF architecture, 16 KB LOAD alignment, and byte-identical UniFFI
|
||||||
|
metadata across all three ABIs. A packaging step selects only the Android library
|
||||||
|
and rejects accidental inclusion of the dependency Apple cdylib. The thin Android crate re-exports the existing
|
||||||
|
UniFFI component; it duplicates no storage rules or converters. #91 owns the
|
||||||
|
platform-neutral contract extraction. No handwritten JNI or unsafe Rust is added.
|
||||||
|
|
||||||
|
The workspace's UniFFI 0.32.0 CLI generates Android-mode immutable Kotlin
|
||||||
|
records from the arm64 library, using the global defaults in uniffi.toml.
|
||||||
|
A version-checked preparation step redacts record toString, typed/internal
|
||||||
|
exception diagnostics and unexpected callback stack traces, mechanically renames
|
||||||
|
Rust error message fields to rustMessage in Kotlin,
|
||||||
|
and translates every integrity guard to a typed failure. Checksums remain enabled
|
||||||
|
and retain every native function and expected value. UniFFI checksums are u16:
|
||||||
|
JNA's generated Int return is normalized to its lower 16 bits before comparison;
|
||||||
|
AArch64 may leave unrelated upper bits in the return register. Contract versions
|
||||||
|
are compared at their full width. A failed initializer remains failed until an
|
||||||
|
app restart/update, rather than reporting a different error on each retry.
|
||||||
|
|
||||||
|
NativeRuntime performs OS library/ABI preflight, loads the library and initializes
|
||||||
|
UniFFI before entering Rust. Missing/unsupported libraries, broken APKs, contract
|
||||||
|
or checksum mismatch, and load failures yield typed, non-secret recovery states.
|
||||||
|
It rejects main-thread calls. The core facade schedules blocking native calls on
|
||||||
|
Dispatchers.IO; cancellation propagates and a superseded result cannot overwrite
|
||||||
|
newer state. Blocking fixture calls finish in Rust when a coroutine is cancelled;
|
||||||
|
no thread is forcibly stopped. Long storage operations must use their Rust-owned
|
||||||
|
cancellation methods when their feature is integrated.
|
||||||
|
|
||||||
|
No Rust-to-Kotlin platform callbacks are installed by #92. When #93 adds them,
|
||||||
|
use generated UniFFI/JNA callback adapters only: JNA attaches a calling native
|
||||||
|
thread to the JVM; retain the callback for the full Rust owner lifetime, release
|
||||||
|
it after unregistering, never assume the callback runs on the Android main thread,
|
||||||
|
and marshal UI/Activity work onto Main. Keep storage decisions in Rust and avoid
|
||||||
|
blocking the main thread or calling back into a held Rust lock.
|
||||||
|
|
||||||
|
JNA 5.19.1 is packaged as its Android AAR, filtered to arm64-v8a, armeabi-v7a and
|
||||||
|
x86_64. The release set may only be narrowed by changing the support decision in
|
||||||
|
#88, not by silently omitting an ABI. All source/lock/config files are task inputs;
|
||||||
|
outputs live only under build/. Debug and release compile independently, and
|
||||||
|
unchanged builds reuse their outputs. R8 keeps generated/JNA reflection entry
|
||||||
|
points. AGP strips release libraries and exports FULL native symbols to
|
||||||
|
app/build/outputs/native-debug-symbols/release/native-debug-symbols.zip; retain
|
||||||
|
that file and outputs/mapping/release/mapping.txt with the matching release.
|
||||||
|
AAB base/lib entries let Play produce per-ABI splits.
|
||||||
|
|
||||||
|
The auditNativePackages gate inspects every native dependency in both APKs and
|
||||||
|
the AAB, checks all three ABI directories and both Rust/JNA libraries, and rejects
|
||||||
|
ELF segments below 16 KB alignment or APK native entries that are compressed or
|
||||||
|
not ZIP-aligned to 16 KB. Follow the official [16 KB runtime validation](https://developer.android.com/guide/practices/page-sizes):
|
||||||
|
use an actual 16 KB system image, check adb shell getconf PAGE_SIZE is 16384,
|
||||||
|
disable page-size compatibility mode, and run both instrumented test suites.
|
||||||
|
An ELF/ZIP audit is not a substitute for that runtime test. Milestone validation
|
||||||
|
is emulator-only per the user instruction of 2026-10-08; physical devices are
|
||||||
|
outside the test scope for every issue. Keep x86_64 emulator evidence separate
|
||||||
|
from the Apple Silicon arm64 emulator run.
|
||||||
|
|
||||||
|
Validation recorded on 2026-10-08 for #92:
|
||||||
|
|
||||||
|
| Environment | Verified |
|
||||||
|
| --- | --- |
|
||||||
|
| API 37 arm64 emulator, 4 KB | Generated API fixture/error/redaction tests; 25 UI states; release APK and AAB split launch; update-state preservation |
|
||||||
|
| API 37 arm64 emulator, 16 KB, compatibility disabled | Same native/UI tests, release APK/AAB launch and update-state preservation |
|
||||||
|
| Fresh source export | Three ABI debug builds with pinned tools, locked dependencies and strict artifact verification |
|
||||||
|
| All three ABI release outputs | ELF alignment and identical UniFFI metadata; stripped APK libraries and separate FULL Rust symbols; nine bundletool ABI split APKs audited |
|
||||||
|
| Physical devices | Excluded from milestone testing by user instruction |
|
||||||
|
| x86_64 runtime | System image installed; QEMU2 rejects x86_64 on this aarch64 Mac, including with acceleration disabled |
|
||||||
|
|
||||||
|
The outstanding x86_64 emulator check needs a compatible host; cross-compilation
|
||||||
|
and static package checks do not establish x86_64 runtime coverage.
|
||||||
+18
-15
@@ -6,8 +6,10 @@ androidx.activity:activity-compose:1.13.0=debugAndroidTestCompileClasspath,debug
|
|||||||
androidx.activity:activity-ktx:1.13.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.activity:activity-ktx:1.13.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.activity:activity:1.13.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.activity:activity:1.13.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation-experimental:1.5.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation-experimental:1.5.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation-jvm:1.9.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation-jvm:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation:1.9.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation-jvm:1.9.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
androidx.annotation:annotation:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation:1.9.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
androidx.arch.core:core-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.arch.core:core-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.arch.core:core-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.arch.core:core-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.autofill:autofill:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.autofill:autofill:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -208,6 +210,7 @@ jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool
|
|||||||
javax.inject:javax.inject:1=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,androidLintTool,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
javax.inject:javax.inject:1=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,androidLintTool,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
junit:junit:4.13.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
junit:junit:4.13.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
||||||
|
net.java.dev.jna:jna:5.19.1=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
net.java.dev.jna:jna:5.6.0=androidLintTool
|
net.java.dev.jna:jna:5.6.0=androidLintTool
|
||||||
net.ltgt.gradle.incap:incap:0.2=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
net.ltgt.gradle.incap:incap:0.2=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
net.sf.kxml:kxml2:2.3.0=androidLintTool
|
net.sf.kxml:kxml2:2.3.0=androidLintTool
|
||||||
@@ -228,31 +231,31 @@ org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
|||||||
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
||||||
org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
org.jetbrains.kotlin:compose-group-mapping:2.4.20=composeMappingProducerClasspath
|
org.jetbrains.kotlin:compose-group-mapping:2.4.21=composeMappingProducerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.20=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable:2.4.20=kotlin-extension,kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathRelease
|
org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable:2.4.21=kotlin-extension,kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathRelease
|
||||||
org.jetbrains.kotlin:kotlin-daemon-client:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-daemon-client:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-client:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-daemon-client:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-metadata-jvm:2.3.21=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
org.jetbrains.kotlin:kotlin-metadata-jvm:2.3.21=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
org.jetbrains.kotlin:kotlin-reflect:1.6.10=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-reflect:1.6.10=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool
|
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-script-runtime:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-script-runtime:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-script-runtime:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0=ktlintReporter
|
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0=ktlintReporter
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,ktlintReporter
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,ktlintReporter
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
@@ -264,8 +267,8 @@ org.jetbrains.kotlin:kotlin-stdlib:2.2.21=composeMappingProducerClasspath
|
|||||||
org.jetbrains.kotlin:kotlin-stdlib:2.3.20=kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathRelease,kspPluginClasspath,kspPluginClasspathNonEmbeddable
|
org.jetbrains.kotlin:kotlin-stdlib:2.3.20=kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathRelease,kspPluginClasspath,kspPluginClasspathNonEmbeddable
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.3.21=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.3.21=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorRelease,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.20=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-tooling-core:2.4.20=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ class ShellScreenTest {
|
|||||||
hasText(tab.name) and androidx.compose.ui.test.isSelectable()
|
hasText(tab.name) and androidx.compose.ui.test.isSelectable()
|
||||||
).performClick()
|
).performClick()
|
||||||
val page = ShellFixtures.all.getValue(state).first { it.tab == tab }
|
val page = ShellFixtures.all.getValue(state).first { it.tab == tab }
|
||||||
|
compose.waitUntil(timeoutMillis = 10_000) {
|
||||||
|
compose.onAllNodes(hasText(page.stateTitle) and isHeading())
|
||||||
|
.fetchSemanticsNodes().size == 1
|
||||||
|
}
|
||||||
compose.onNode(hasText(page.stateTitle) and isHeading()).assertIsDisplayed()
|
compose.onNode(hasText(page.stateTitle) and isHeading()).assertIsDisplayed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
package de.rfc1437.ironstorage
|
|
||||||
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.Provides
|
|
||||||
import dagger.hilt.InstallIn
|
|
||||||
import dagger.hilt.components.SingletonComponent
|
|
||||||
import de.rfc1437.ironstorage.core.ShellFixtures
|
|
||||||
import de.rfc1437.ironstorage.core.ShellRepository
|
|
||||||
import de.rfc1437.ironstorage.core.ShellSnapshot
|
|
||||||
import de.rfc1437.ironstorage.core.ShellState
|
|
||||||
import de.rfc1437.ironstorage.core.ShellTab
|
|
||||||
import javax.inject.Singleton
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
|
|
||||||
class DebugShellRepository : ShellRepository {
|
|
||||||
private val mutableSnapshot =
|
|
||||||
MutableStateFlow(
|
|
||||||
ShellSnapshot(ShellState.Empty, ShellFixtures.all.getValue(ShellState.Empty))
|
|
||||||
)
|
|
||||||
override val snapshot: StateFlow<ShellSnapshot> = mutableSnapshot
|
|
||||||
|
|
||||||
override fun selectTab(tab: ShellTab) {
|
|
||||||
mutableSnapshot.value = mutableSnapshot.value.copy(selectedTab = tab)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun showFixture(state: ShellState) {
|
|
||||||
mutableSnapshot.value =
|
|
||||||
mutableSnapshot.value.copy(state = state, pages = ShellFixtures.all.getValue(state))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Module
|
|
||||||
@InstallIn(SingletonComponent::class)
|
|
||||||
object DebugShellModule {
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun shellRepository(): ShellRepository = DebugShellRepository()
|
|
||||||
}
|
|
||||||
@@ -9,6 +9,7 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import de.rfc1437.ironstorage.core.NativeFixtureShellRepository
|
||||||
import de.rfc1437.ironstorage.core.ShellRepository
|
import de.rfc1437.ironstorage.core.ShellRepository
|
||||||
import de.rfc1437.ironstorage.core.ShellState
|
import de.rfc1437.ironstorage.core.ShellState
|
||||||
import de.rfc1437.ironstorage.features.ShellScreen
|
import de.rfc1437.ironstorage.features.ShellScreen
|
||||||
@@ -19,7 +20,9 @@ fun VariantContent(viewModel: ShellViewModel, repository: ShellRepository) {
|
|||||||
Column(Modifier.statusBarsPadding()) {
|
Column(Modifier.statusBarsPadding()) {
|
||||||
Row(Modifier.horizontalScroll(rememberScrollState())) {
|
Row(Modifier.horizontalScroll(rememberScrollState())) {
|
||||||
ShellState.entries.forEach { state ->
|
ShellState.entries.forEach { state ->
|
||||||
TextButton(onClick = { (repository as DebugShellRepository).showFixture(state) }) {
|
TextButton(onClick = {
|
||||||
|
(repository as NativeFixtureShellRepository).showFixture(state)
|
||||||
|
}) {
|
||||||
Text("Fixture: ${state.name}")
|
Text("Fixture: ${state.name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package de.rfc1437.ironstorage
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import de.rfc1437.ironstorage.core.NativeFixtureShellRepository
|
||||||
|
import de.rfc1437.ironstorage.core.ShellRepository
|
||||||
|
import javax.inject.Singleton
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
object ShellModule {
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun shellRepository(@ApplicationContext context: Context): ShellRepository =
|
||||||
|
NativeFixtureShellRepository(
|
||||||
|
context,
|
||||||
|
CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package de.rfc1437.ironstorage
|
|
||||||
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.Provides
|
|
||||||
import dagger.hilt.InstallIn
|
|
||||||
import dagger.hilt.components.SingletonComponent
|
|
||||||
import de.rfc1437.ironstorage.core.ShellRepository
|
|
||||||
import de.rfc1437.ironstorage.core.ShellSnapshot
|
|
||||||
import de.rfc1437.ironstorage.core.ShellState
|
|
||||||
import de.rfc1437.ironstorage.core.ShellTab
|
|
||||||
import javax.inject.Singleton
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
|
|
||||||
class ScaffoldShellRepository : ShellRepository {
|
|
||||||
private val mutableSnapshot = MutableStateFlow(ShellSnapshot(ShellState.Empty, emptyList()))
|
|
||||||
override val snapshot: StateFlow<ShellSnapshot> = mutableSnapshot
|
|
||||||
|
|
||||||
override fun selectTab(tab: ShellTab) {
|
|
||||||
mutableSnapshot.value = mutableSnapshot.value.copy(selectedTab = tab)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Module
|
|
||||||
@InstallIn(SingletonComponent::class)
|
|
||||||
object ReleaseShellModule {
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun shellRepository(): ShellRepository = ScaffoldShellRepository()
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package de.rfc1437.ironstorage
|
package de.rfc1437.ironstorage
|
||||||
|
|
||||||
|
import de.rfc1437.ironstorage.core.ShellFixtures
|
||||||
import de.rfc1437.ironstorage.core.ShellState
|
import de.rfc1437.ironstorage.core.ShellState
|
||||||
import de.rfc1437.ironstorage.core.ShellTab
|
import de.rfc1437.ironstorage.core.ShellTab
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
@@ -7,14 +8,12 @@ import org.junit.Test
|
|||||||
|
|
||||||
class DebugShellRepositoryTest {
|
class DebugShellRepositoryTest {
|
||||||
@Test
|
@Test
|
||||||
fun everyFixtureHasFivePagesAndSelectionSurvivesStateChanges() {
|
fun fixtureInventorySupportsEveryNativeTab() {
|
||||||
val repository = DebugShellRepository()
|
val selected = ShellTab.Totp
|
||||||
repository.selectTab(ShellTab.Totp)
|
|
||||||
ShellState.entries.forEach { state ->
|
ShellState.entries.forEach { state ->
|
||||||
repository.showFixture(state)
|
val pages = ShellFixtures.all.getValue(state)
|
||||||
assertEquals(state, repository.snapshot.value.state)
|
assertEquals(ShellTab.entries, pages.map { it.tab })
|
||||||
assertEquals(ShellTab.entries, repository.snapshot.value.pages.map { it.tab })
|
assertEquals(selected, pages.first { it.tab == selected }.tab)
|
||||||
assertEquals(ShellTab.Totp, repository.snapshot.value.selectedTab)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,3 +62,20 @@ val checkArchitecture = tasks.register<Exec>("checkArchitecture") {
|
|||||||
subprojects {
|
subprojects {
|
||||||
tasks.matching { it.name == "preBuild" || it.name == "check" }.configureEach { dependsOn(rootProject.tasks.named("checkArchitecture")) }
|
tasks.matching { it.name == "preBuild" || it.name == "check" }.configureEach { dependsOn(rootProject.tasks.named("checkArchitecture")) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register<Exec>("auditNativePackages") {
|
||||||
|
dependsOn(":app:assembleDebug", ":app:assembleRelease", ":app:bundleRelease")
|
||||||
|
workingDir = workspace
|
||||||
|
val packages = listOf(
|
||||||
|
layout.projectDirectory.file("app/build/outputs/apk/debug/app-debug.apk"),
|
||||||
|
layout.projectDirectory.file("app/build/outputs/apk/release/app-release-unsigned.apk"),
|
||||||
|
layout.projectDirectory.file("app/build/outputs/bundle/release/app-release.aab")
|
||||||
|
)
|
||||||
|
inputs.files(packages)
|
||||||
|
commandLine(
|
||||||
|
listOf(
|
||||||
|
cargoExecutable.get(), "+${libs.versions.rust.get()}", "run", "--locked",
|
||||||
|
"--package", "ironstorage-android-build", "--", "audit-package"
|
||||||
|
) + packages.map { it.asFile.absolutePath }
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
# Manual edits can break the build and are not advised.
|
# Manual edits can break the build and are not advised.
|
||||||
# This file is expected to be part of source control.
|
# This file is expected to be part of source control.
|
||||||
# To regenerate this file, run: ./gradlew :core:dependencies --write-locks
|
# To regenerate this file, run: ./gradlew :core:dependencies --write-locks
|
||||||
|
androidx.annotation:annotation-jvm:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
ch.qos.logback:logback-classic:1.3.15=ktlint
|
ch.qos.logback:logback-classic:1.3.15=ktlint
|
||||||
ch.qos.logback:logback-core:1.3.15=ktlint
|
ch.qos.logback:logback-core:1.3.15=ktlint
|
||||||
com.android.tools.analytics-library:protos:32.4.1=androidLintTool
|
com.android.tools.analytics-library:protos:32.4.1=androidLintTool
|
||||||
@@ -75,6 +77,7 @@ jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool
|
|||||||
javax.inject:javax.inject:1=androidLintTool
|
javax.inject:javax.inject:1=androidLintTool
|
||||||
junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
||||||
|
net.java.dev.jna:jna:5.19.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
net.java.dev.jna:jna:5.6.0=androidLintTool
|
net.java.dev.jna:jna:5.6.0=androidLintTool
|
||||||
net.sf.kxml:kxml2:2.3.0=androidLintTool
|
net.sf.kxml:kxml2:2.3.0=androidLintTool
|
||||||
org.apache.commons:commons-compress:1.27.1=androidLintTool
|
org.apache.commons:commons-compress:1.27.1=androidLintTool
|
||||||
@@ -93,27 +96,27 @@ org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
|||||||
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
||||||
org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.20=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-client:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-daemon-client:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-client:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-daemon-client:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool
|
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-script-runtime:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-script-runtime:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-script-runtime:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0=ktlintReporter
|
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0=ktlintReporter
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=ktlintReporter
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=ktlintReporter
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
@@ -122,8 +125,8 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.10=androidLintTool,unified-test-plat
|
|||||||
org.jetbrains.kotlin:kotlin-stdlib:2.2.0=ktlint,ktlintBaselineReporter,ktlintReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-stdlib:2.2.0=ktlint,ktlintBaselineReporter,ktlintReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlin:kotlin-stdlib:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.20=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-tooling-core:2.4.20=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
|
|||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
package de.rfc1437.ironstorage.core
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import de.rfc1437.ironstorage.bridge.NativeBridgeException
|
||||||
|
import de.rfc1437.ironstorage.bridge.NativeFailureKind
|
||||||
|
import de.rfc1437.ironstorage.bridge.NativeRuntime
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileShellState
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileTab
|
||||||
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
/** #92's native fixture integration; repository initialization is owned by #90. */
|
||||||
|
class NativeFixtureShellRepository internal constructor(
|
||||||
|
private val scope: CoroutineScope,
|
||||||
|
private val load: suspend (ShellState) -> ShellSnapshot
|
||||||
|
) : ShellRepository {
|
||||||
|
constructor(context: Context, scope: CoroutineScope) : this(scope, nativeLoader(context))
|
||||||
|
private val mutableSnapshot = MutableStateFlow(ShellSnapshot(ShellState.Loading, emptyList()))
|
||||||
|
override val snapshot: StateFlow<ShellSnapshot> = mutableSnapshot
|
||||||
|
private val revision = AtomicLong()
|
||||||
|
private var job: Job? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
showFixture(ShellState.Empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun selectTab(tab: ShellTab) {
|
||||||
|
mutableSnapshot.update { it.copy(selectedTab = tab) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showFixture(state: ShellState) {
|
||||||
|
val operation = revision.incrementAndGet()
|
||||||
|
job?.cancel()
|
||||||
|
job = scope.launch {
|
||||||
|
val result = try {
|
||||||
|
load(state)
|
||||||
|
} catch (error: NativeBridgeException) {
|
||||||
|
ShellSnapshot(ShellState.Error, emptyList(), nativeFailure = error.kind.toFacade())
|
||||||
|
}
|
||||||
|
if (revision.get() == operation) {
|
||||||
|
mutableSnapshot.update { result.copy(selectedTab = it.selectedTab) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nativeLoader(context: Context): suspend (ShellState) -> ShellSnapshot {
|
||||||
|
val runtime = NativeRuntime(context)
|
||||||
|
return { state ->
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val shell = runtime.fixture(state.toNative())
|
||||||
|
val pages = shell.pages.map { page ->
|
||||||
|
ShellPage(page.tab.toFacade(), page.title, page.stateTitle, page.stateDetail)
|
||||||
|
}
|
||||||
|
val actual = shell.pages.firstOrNull()?.state
|
||||||
|
?: throw NativeBridgeException(NativeFailureKind.RustFailure)
|
||||||
|
ShellSnapshot(actual.toFacade(), pages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MobileShellState.toFacade(): ShellState = when (this) {
|
||||||
|
MobileShellState.LOADING -> ShellState.Loading
|
||||||
|
MobileShellState.EMPTY -> ShellState.Empty
|
||||||
|
MobileShellState.READY -> ShellState.Ready
|
||||||
|
MobileShellState.LOCKED -> ShellState.Locked
|
||||||
|
MobileShellState.ERROR -> ShellState.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ShellState.toNative(): MobileShellState = when (this) {
|
||||||
|
ShellState.Loading -> MobileShellState.LOADING
|
||||||
|
ShellState.Empty -> MobileShellState.EMPTY
|
||||||
|
ShellState.Ready -> MobileShellState.READY
|
||||||
|
ShellState.Locked -> MobileShellState.LOCKED
|
||||||
|
ShellState.Error -> MobileShellState.ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MobileTab.toFacade(): ShellTab = when (this) {
|
||||||
|
MobileTab.HOME -> ShellTab.Home
|
||||||
|
MobileTab.PASSWORDS -> ShellTab.Passwords
|
||||||
|
MobileTab.SEARCH -> ShellTab.Search
|
||||||
|
MobileTab.TOTP -> ShellTab.Totp
|
||||||
|
MobileTab.PREFERENCES -> ShellTab.Preferences
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NativeFailureKind.toFacade(): NativeFailure = when (this) {
|
||||||
|
NativeFailureKind.UnsupportedAbi -> NativeFailure.UnsupportedAbi
|
||||||
|
NativeFailureKind.MissingLibrary -> NativeFailure.MissingLibrary
|
||||||
|
NativeFailureKind.ContractMismatch -> NativeFailure.ContractMismatch
|
||||||
|
NativeFailureKind.ChecksumMismatch -> NativeFailure.ChecksumMismatch
|
||||||
|
NativeFailureKind.LoadFailure -> NativeFailure.LoadFailure
|
||||||
|
NativeFailureKind.RustFailure -> NativeFailure.RustFailure
|
||||||
|
NativeFailureKind.MainThreadCall -> NativeFailure.MainThreadCall
|
||||||
|
}
|
||||||
@@ -14,9 +14,20 @@ data class ShellPage(
|
|||||||
data class ShellSnapshot(
|
data class ShellSnapshot(
|
||||||
val state: ShellState,
|
val state: ShellState,
|
||||||
val pages: List<ShellPage>,
|
val pages: List<ShellPage>,
|
||||||
val selectedTab: ShellTab = ShellTab.Home
|
val selectedTab: ShellTab = ShellTab.Home,
|
||||||
|
val nativeFailure: NativeFailure? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum class NativeFailure {
|
||||||
|
UnsupportedAbi,
|
||||||
|
MissingLibrary,
|
||||||
|
ContractMismatch,
|
||||||
|
ChecksumMismatch,
|
||||||
|
LoadFailure,
|
||||||
|
RustFailure,
|
||||||
|
MainThreadCall
|
||||||
|
}
|
||||||
|
|
||||||
interface ShellRepository {
|
interface ShellRepository {
|
||||||
val snapshot: StateFlow<ShellSnapshot>
|
val snapshot: StateFlow<ShellSnapshot>
|
||||||
fun selectTab(tab: ShellTab)
|
fun selectTab(tab: ShellTab)
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package de.rfc1437.ironstorage.core
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
|
import kotlinx.coroutines.NonCancellable
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
|
||||||
|
class NativeFixtureShellRepositoryTest {
|
||||||
|
@Test
|
||||||
|
fun cancelledNativeCompletionCannotReplaceNewerStateOrTabSelection() = runTest {
|
||||||
|
val pending = CompletableDeferred<Unit>()
|
||||||
|
val repository = NativeFixtureShellRepository(backgroundScope) { state ->
|
||||||
|
if (state == ShellState.Ready) withContext(NonCancellable) { pending.await() }
|
||||||
|
ShellSnapshot(state, listOf(ShellPage(ShellTab.Home, "Home", state.name, "Fixture")))
|
||||||
|
}
|
||||||
|
runCurrent()
|
||||||
|
repository.showFixture(ShellState.Ready)
|
||||||
|
runCurrent()
|
||||||
|
repository.selectTab(ShellTab.Search)
|
||||||
|
repository.showFixture(ShellState.Locked)
|
||||||
|
runCurrent()
|
||||||
|
pending.complete(Unit)
|
||||||
|
runCurrent()
|
||||||
|
assertEquals(ShellState.Locked, repository.snapshot.value.state)
|
||||||
|
assertEquals(ShellTab.Search, repository.snapshot.value.selectedTab)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,10 @@ androidx.activity:activity-compose:1.12.0=debugAndroidTestCompileClasspath,debug
|
|||||||
androidx.activity:activity-ktx:1.12.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.activity:activity-ktx:1.12.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.activity:activity:1.12.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.activity:activity:1.12.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation-experimental:1.5.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation-experimental:1.5.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation-jvm:1.9.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation-jvm:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation:1.9.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation-jvm:1.9.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
androidx.annotation:annotation:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation:1.9.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
androidx.arch.core:core-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.arch.core:core-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.arch.core:core-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.arch.core:core-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.autofill:autofill:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.autofill:autofill:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -192,6 +194,7 @@ jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool
|
|||||||
javax.inject:javax.inject:1=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,androidLintTool,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
javax.inject:javax.inject:1=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,androidLintTool,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
||||||
|
net.java.dev.jna:jna:5.19.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
net.java.dev.jna:jna:5.6.0=androidLintTool
|
net.java.dev.jna:jna:5.6.0=androidLintTool
|
||||||
net.ltgt.gradle.incap:incap:0.2=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
net.ltgt.gradle.incap:incap:0.2=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
net.sf.kxml:kxml2:2.3.0=androidLintTool
|
net.sf.kxml:kxml2:2.3.0=androidLintTool
|
||||||
@@ -212,29 +215,29 @@ org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
|||||||
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
||||||
org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.20=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable:2.4.20=kotlin-extension,kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathRelease
|
org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable:2.4.21=kotlin-extension,kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathRelease
|
||||||
org.jetbrains.kotlin:kotlin-daemon-client:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-daemon-client:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-client:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-daemon-client:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-metadata-jvm:2.3.21=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
org.jetbrains.kotlin:kotlin-metadata-jvm:2.3.21=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
org.jetbrains.kotlin:kotlin-reflect:1.6.10=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-reflect:1.6.10=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool
|
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-script-runtime:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-script-runtime:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-script-runtime:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0=ktlintReporter
|
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0=ktlintReporter
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,ktlintReporter
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,ktlintReporter
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
@@ -245,8 +248,8 @@ org.jetbrains.kotlin:kotlin-stdlib:2.2.10=androidLintTool,unified-test-platform-
|
|||||||
org.jetbrains.kotlin:kotlin-stdlib:2.3.20=kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathRelease,kspPluginClasspath,kspPluginClasspathNonEmbeddable
|
org.jetbrains.kotlin:kotlin-stdlib:2.3.20=kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathRelease,kspPluginClasspath,kspPluginClasspathNonEmbeddable
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.3.21=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.3.21=_agp_internal_debug_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,kspDebugKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.20=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-tooling-core:2.4.20=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import androidx.compose.ui.semantics.heading
|
|||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import de.rfc1437.ironstorage.core.NativeFailure
|
||||||
import de.rfc1437.ironstorage.core.ShellState
|
import de.rfc1437.ironstorage.core.ShellState
|
||||||
import de.rfc1437.ironstorage.core.ShellTab
|
import de.rfc1437.ironstorage.core.ShellTab
|
||||||
|
|
||||||
@@ -44,12 +45,33 @@ fun ShellScreen(viewModel: ShellViewModel) {
|
|||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.app_name), style = MaterialTheme.typography.headlineLarge)
|
Text(stringResource(R.string.app_name), style = MaterialTheme.typography.headlineLarge)
|
||||||
val page = snapshot.pages.firstOrNull { it.tab == snapshot.selectedTab }
|
val page = snapshot.pages.firstOrNull { it.tab == snapshot.selectedTab }
|
||||||
|
val nativeFailure = snapshot.nativeFailure
|
||||||
|
val title = if (nativeFailure != null) {
|
||||||
|
stringResource(R.string.native_failure_title)
|
||||||
|
} else {
|
||||||
|
page?.stateTitle ?: stringResource(R.string.scaffold_title)
|
||||||
|
}
|
||||||
|
val detail = if (nativeFailure == null) {
|
||||||
|
page?.detail ?: stringResource(R.string.scaffold_detail)
|
||||||
|
} else {
|
||||||
|
stringResource(
|
||||||
|
when (nativeFailure) {
|
||||||
|
NativeFailure.UnsupportedAbi -> R.string.native_unsupported_device
|
||||||
|
NativeFailure.MissingLibrary,
|
||||||
|
NativeFailure.ContractMismatch,
|
||||||
|
NativeFailure.ChecksumMismatch,
|
||||||
|
NativeFailure.LoadFailure -> R.string.native_update_required
|
||||||
|
NativeFailure.RustFailure,
|
||||||
|
NativeFailure.MainThreadCall -> R.string.native_operation_failed
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
Text(
|
Text(
|
||||||
page?.stateTitle ?: stringResource(R.string.scaffold_title),
|
title,
|
||||||
modifier = Modifier.semantics { heading() },
|
modifier = Modifier.semantics { heading() },
|
||||||
style = MaterialTheme.typography.headlineSmall
|
style = MaterialTheme.typography.headlineSmall
|
||||||
)
|
)
|
||||||
Text(page?.detail ?: stringResource(R.string.scaffold_detail))
|
Text(detail)
|
||||||
if (snapshot.state == ShellState.Loading) CircularProgressIndicator()
|
if (snapshot.state == ShellState.Loading) CircularProgressIndicator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,8 @@
|
|||||||
<string name="app_name">IronStorage</string>
|
<string name="app_name">IronStorage</string>
|
||||||
<string name="scaffold_title">No Password Store</string>
|
<string name="scaffold_title">No Password Store</string>
|
||||||
<string name="scaffold_detail">Your password store has not been configured.</string>
|
<string name="scaffold_detail">Your password store has not been configured.</string>
|
||||||
|
<string name="native_failure_title">IronStorage Is Unavailable</string>
|
||||||
|
<string name="native_unsupported_device">This device is not supported by this app build.</string>
|
||||||
|
<string name="native_update_required">The installed app components could not be loaded or do not match. Install a complete update without clearing app data.</string>
|
||||||
|
<string name="native_operation_failed">The app could not complete this operation. Try again.</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[versions]
|
[versions]
|
||||||
agp = "9.4.1"
|
agp = "9.4.1"
|
||||||
kotlin = "2.4.20"
|
kotlin = "2.4.21"
|
||||||
ksp = "2.3.12"
|
ksp = "2.3.12"
|
||||||
hilt = "2.60.1"
|
hilt = "2.60.1"
|
||||||
compose = "2026.09.00"
|
compose = "2026.09.00"
|
||||||
@@ -17,6 +17,10 @@ ktlint = "1.7.1"
|
|||||||
compileSdk = "37"
|
compileSdk = "37"
|
||||||
minSdk = "26"
|
minSdk = "26"
|
||||||
ndk = "30.0.16248370"
|
ndk = "30.0.16248370"
|
||||||
|
rust = "1.97.1"
|
||||||
|
cargoNdk = "4.1.2"
|
||||||
|
jna = "5.19.1"
|
||||||
|
annotation = "1.11.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose" }
|
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose" }
|
||||||
@@ -37,6 +41,8 @@ hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hil
|
|||||||
junit = { module = "junit:junit", version.ref = "junit" }
|
junit = { module = "junit:junit", version.ref = "junit" }
|
||||||
android-test-runner = { module = "androidx.test:runner", version.ref = "androidTest" }
|
android-test-runner = { module = "androidx.test:runner", version.ref = "androidTest" }
|
||||||
android-test-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
|
android-test-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
|
||||||
|
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
|
||||||
|
annotation = { module = "androidx.annotation:annotation", version.ref = "annotation" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|||||||
@@ -63,6 +63,11 @@
|
|||||||
<sha256 value="f4001a709b6f7132b22a5e17c24f8b8a9b3c462a598de3b0f16cc57a4344bab6" origin="Generated by Gradle"/>
|
<sha256 value="f4001a709b6f7132b22a5e17c24f8b8a9b3c462a598de3b0f16cc57a4344bab6" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.annotation" name="annotation" version="1.11.0">
|
||||||
|
<artifact name="annotation-1.11.0.module">
|
||||||
|
<sha256 value="ac8410bea7adaabc9e71285f0627c9cb929c5addd00cfc6d0ebd421dc2da1ee0" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.annotation" name="annotation" version="1.7.0">
|
<component group="androidx.annotation" name="annotation" version="1.7.0">
|
||||||
<artifact name="annotation-1.7.0.module">
|
<artifact name="annotation-1.7.0.module">
|
||||||
<sha256 value="530708656d380605077ea8bca9ae1372fbd1af38e375f411d4e43263bd510c3c" origin="Generated by Gradle"/>
|
<sha256 value="530708656d380605077ea8bca9ae1372fbd1af38e375f411d4e43263bd510c3c" origin="Generated by Gradle"/>
|
||||||
@@ -91,6 +96,22 @@
|
|||||||
<sha256 value="ae1ff29a7f3965e6589acfe7f07ef39d36405d7ab278472327afd92fc6d72a3f" origin="Generated by Gradle"/>
|
<sha256 value="ae1ff29a7f3965e6589acfe7f07ef39d36405d7ab278472327afd92fc6d72a3f" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.annotation" name="annotation-jvm" version="1.11.0">
|
||||||
|
<artifact name="annotation-jvm-1.11.0.jar">
|
||||||
|
<sha256 value="a83b827cc17fd6b41c7bf5e7a2a2b40a0895b00b3e30fdfdb820b49dc7b667f3" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="annotation-jvm-1.11.0.module">
|
||||||
|
<sha256 value="0c8a86f2a8e20120cc13544f101047f42284de1f1dd7ca26c90056901de4c2da" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.annotation" name="annotation-jvm" version="1.7.0">
|
||||||
|
<artifact name="annotation-jvm-1.7.0.jar">
|
||||||
|
<sha256 value="e36b8e4b8393a4adc74e3d4ab22ad5a36396f0cea2e40b5734eae14937dfd224" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="annotation-jvm-1.7.0.module">
|
||||||
|
<sha256 value="07ce60c377ab94e47c8c902589b9776030064fd1a7e4d5a01a38d700e35e5db4" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.annotation" name="annotation-jvm" version="1.9.1">
|
<component group="androidx.annotation" name="annotation-jvm" version="1.9.1">
|
||||||
<artifact name="annotation-jvm-1.9.1.jar">
|
<artifact name="annotation-jvm-1.9.1.jar">
|
||||||
<sha256 value="1e343917ebf27ba96fe4dc52b1cad7fd32b738fbc6355bb6cd5b3b305d7212d0" origin="Generated by Gradle"/>
|
<sha256 value="1e343917ebf27ba96fe4dc52b1cad7fd32b738fbc6355bb6cd5b3b305d7212d0" origin="Generated by Gradle"/>
|
||||||
@@ -2180,6 +2201,14 @@
|
|||||||
<sha256 value="569b6977ee4603c965c1c46c3058fa6e969291b0160eb6964dd092cd89eadd94" origin="Generated by Gradle"/>
|
<sha256 value="569b6977ee4603c965c1c46c3058fa6e969291b0160eb6964dd092cd89eadd94" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="net.java.dev.jna" name="jna" version="5.19.1">
|
||||||
|
<artifact name="jna-5.19.1.aar">
|
||||||
|
<sha256 value="b57125cb7d16253f0d65a80f7d3a4c3664effa711b8bdbb7f87fb572ce1624ed" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="jna-5.19.1.pom">
|
||||||
|
<sha256 value="911b754a03b66af0fed2bbdfdc3a86807360dd036ad3b481ef5162c685e456bf" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="net.java.dev.jna" name="jna" version="5.6.0">
|
<component group="net.java.dev.jna" name="jna" version="5.6.0">
|
||||||
<artifact name="jna-5.6.0.jar">
|
<artifact name="jna-5.6.0.jar">
|
||||||
<sha256 value="5557e235a8aa2f9766d5dc609d67948f2a8832c2d796cea9ef1d6cbe0b3b7eaf" origin="Generated by Gradle"/>
|
<sha256 value="5557e235a8aa2f9766d5dc609d67948f2a8832c2d796cea9ef1d6cbe0b3b7eaf" origin="Generated by Gradle"/>
|
||||||
@@ -2522,6 +2551,14 @@
|
|||||||
<sha256 value="6e3d3c8d2a375393d64395882ac80c9c3a44e90008801a34fd99a13cbcc96bfd" origin="Generated by Gradle"/>
|
<sha256 value="6e3d3c8d2a375393d64395882ac80c9c3a44e90008801a34fd99a13cbcc96bfd" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="compose-compiler-gradle-plugin" version="2.4.21">
|
||||||
|
<artifact name="compose-compiler-gradle-plugin-2.4.21-gradle96.jar">
|
||||||
|
<sha256 value="17b7d35e53e23f4820e0fb9f3ad71f7ab463970d68bcd8ba7f8d71498b50395f" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="compose-compiler-gradle-plugin-2.4.21.module">
|
||||||
|
<sha256 value="e7bc61dabd4381f4a8f53c7be30bfb5cccd971af27d55b7c39b0a37b28bef24d" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="compose-group-mapping" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="compose-group-mapping" version="2.4.20">
|
||||||
<artifact name="compose-group-mapping-2.4.20.jar">
|
<artifact name="compose-group-mapping-2.4.20.jar">
|
||||||
<sha256 value="0205146299c4c02e19b62620e5a0276aaecc3ecd7711cf274e86e36e6a73f4ca" origin="Generated by Gradle"/>
|
<sha256 value="0205146299c4c02e19b62620e5a0276aaecc3ecd7711cf274e86e36e6a73f4ca" origin="Generated by Gradle"/>
|
||||||
@@ -2530,6 +2567,14 @@
|
|||||||
<sha256 value="2fba7c50bc1933a70f6ed6d8d3b574a8e97d86912c28caa96fe7ce648a87eb48" origin="Generated by Gradle"/>
|
<sha256 value="2fba7c50bc1933a70f6ed6d8d3b574a8e97d86912c28caa96fe7ce648a87eb48" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="compose-group-mapping" version="2.4.21">
|
||||||
|
<artifact name="compose-group-mapping-2.4.21.jar">
|
||||||
|
<sha256 value="45bb5caf737fb50cf96fd67f4a45aff8a75cae387333a5be80ad29523442d327" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="compose-group-mapping-2.4.21.pom">
|
||||||
|
<sha256 value="a1c461dc79493649a9d1eee167c172dd32aa3260a48735751de30ee169cf4620" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="fus-statistics-gradle-plugin" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="fus-statistics-gradle-plugin" version="2.4.20">
|
||||||
<artifact name="fus-statistics-gradle-plugin-2.4.20-gradle96.jar">
|
<artifact name="fus-statistics-gradle-plugin-2.4.20-gradle96.jar">
|
||||||
<sha256 value="0c050825d65654d0ac8f6ba9409fba824f87100df00e76300242abfe9a1b989f" origin="Generated by Gradle"/>
|
<sha256 value="0c050825d65654d0ac8f6ba9409fba824f87100df00e76300242abfe9a1b989f" origin="Generated by Gradle"/>
|
||||||
@@ -2538,6 +2583,14 @@
|
|||||||
<sha256 value="cfe6fb1af3f7da01428ef4bf4e38e1c76637f4e108ac22f15dfe4c733df408d4" origin="Generated by Gradle"/>
|
<sha256 value="cfe6fb1af3f7da01428ef4bf4e38e1c76637f4e108ac22f15dfe4c733df408d4" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="fus-statistics-gradle-plugin" version="2.4.21">
|
||||||
|
<artifact name="fus-statistics-gradle-plugin-2.4.21-gradle96.jar">
|
||||||
|
<sha256 value="44a07b9203eb2c75ceb2d33327f89b991f2d35095a96a0f1c224a012c5465367" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="fus-statistics-gradle-plugin-2.4.21.module">
|
||||||
|
<sha256 value="3090b4e873054cdc29991ae94c92fa45afb4c145d460441d803baf6ef165bbb8" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-bom" version="2.3.21">
|
<component group="org.jetbrains.kotlin" name="kotlin-bom" version="2.3.21">
|
||||||
<artifact name="kotlin-bom-2.3.21.pom">
|
<artifact name="kotlin-bom-2.3.21.pom">
|
||||||
<sha256 value="950704bad04c5143656cfca1d2c574f25fcad9cac33905ab22a57e9fdf7bfd88" origin="Generated by Gradle"/>
|
<sha256 value="950704bad04c5143656cfca1d2c574f25fcad9cac33905ab22a57e9fdf7bfd88" origin="Generated by Gradle"/>
|
||||||
@@ -2551,6 +2604,14 @@
|
|||||||
<sha256 value="184af9ac1aaf68d0c96875465e9d398926586d83119abbfe1be5979398b8916f" origin="Generated by Gradle"/>
|
<sha256 value="184af9ac1aaf68d0c96875465e9d398926586d83119abbfe1be5979398b8916f" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-build-statistics" version="2.4.21">
|
||||||
|
<artifact name="kotlin-build-statistics-2.4.21.jar">
|
||||||
|
<sha256 value="f917249997fe48d1eb1204906b4cabc8230bf32a1d9fb385e52311acaa6ebc68" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-build-statistics-2.4.21.pom">
|
||||||
|
<sha256 value="4ac9fe3a27069f9ad87dc36ede15fc06335663d4ae46fac09a16bb090e16038c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-api" version="2.4.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-api" version="2.4.0">
|
||||||
<artifact name="kotlin-build-tools-api-2.4.0.jar">
|
<artifact name="kotlin-build-tools-api-2.4.0.jar">
|
||||||
<sha256 value="66917335497f9ab75a36c34b3d90bad2bc8dc256c34b2413ecd0c9467fcf597d" origin="Generated by Gradle"/>
|
<sha256 value="66917335497f9ab75a36c34b3d90bad2bc8dc256c34b2413ecd0c9467fcf597d" origin="Generated by Gradle"/>
|
||||||
@@ -2567,6 +2628,14 @@
|
|||||||
<sha256 value="e8cd9ffd7d0886ba1a1795cbf4a34a06681f184aa50f25686effeefb3c1f56f5" origin="Generated by Gradle"/>
|
<sha256 value="e8cd9ffd7d0886ba1a1795cbf4a34a06681f184aa50f25686effeefb3c1f56f5" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-api" version="2.4.21">
|
||||||
|
<artifact name="kotlin-build-tools-api-2.4.21.jar">
|
||||||
|
<sha256 value="c5cd6a49bd072b529ae10809111c16a7aa0f92147e95d288354017fd65799461" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-build-tools-api-2.4.21.pom">
|
||||||
|
<sha256 value="4b909e42d55242520278d5397eca1edd58921fe128942eeff95a6da279c2eb27" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-compat" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-compat" version="2.4.20">
|
||||||
<artifact name="kotlin-build-tools-compat-2.4.20.jar">
|
<artifact name="kotlin-build-tools-compat-2.4.20.jar">
|
||||||
<sha256 value="937d2961fc0b957a50c3d85a14fcc1bd0585f2229164136895b623691660c9b4" origin="Generated by Gradle"/>
|
<sha256 value="937d2961fc0b957a50c3d85a14fcc1bd0585f2229164136895b623691660c9b4" origin="Generated by Gradle"/>
|
||||||
@@ -2575,6 +2644,14 @@
|
|||||||
<sha256 value="f8e9f647a00bfbc237e3ddff3891b2d4e4a947611b949281658f836def304002" origin="Generated by Gradle"/>
|
<sha256 value="f8e9f647a00bfbc237e3ddff3891b2d4e4a947611b949281658f836def304002" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-compat" version="2.4.21">
|
||||||
|
<artifact name="kotlin-build-tools-compat-2.4.21.jar">
|
||||||
|
<sha256 value="9e71ba89b6d26e46a087d4f8b64bc2f0a774282ea779fc08b26527d0a80d4fe8" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-build-tools-compat-2.4.21.pom">
|
||||||
|
<sha256 value="9d9b4627d5b7bb8631457061275f21524d874b865550addec4f3b029d8265817" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-cri-impl" version="2.4.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-cri-impl" version="2.4.0">
|
||||||
<artifact name="kotlin-build-tools-cri-impl-2.4.0.jar">
|
<artifact name="kotlin-build-tools-cri-impl-2.4.0.jar">
|
||||||
<sha256 value="5168b866945f6ac1ffcb6d4c88cf582497249469c2e4a4eafc0bcd35b5a264a9" origin="Generated by Gradle"/>
|
<sha256 value="5168b866945f6ac1ffcb6d4c88cf582497249469c2e4a4eafc0bcd35b5a264a9" origin="Generated by Gradle"/>
|
||||||
@@ -2591,6 +2668,14 @@
|
|||||||
<sha256 value="8af52efa886eed45c54d568b692e339b70ddc7c768bee9ab9c2d2f96ed8bb0e1" origin="Generated by Gradle"/>
|
<sha256 value="8af52efa886eed45c54d568b692e339b70ddc7c768bee9ab9c2d2f96ed8bb0e1" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-cri-impl" version="2.4.21">
|
||||||
|
<artifact name="kotlin-build-tools-cri-impl-2.4.21.jar">
|
||||||
|
<sha256 value="d1849f9b98033f5333905409074ca90e6a0e17258cd0eb8befa47d795e695841" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-build-tools-cri-impl-2.4.21.pom">
|
||||||
|
<sha256 value="57f3c430dfec2e575bb1b64055412ace12d4ed5d9a02eb97a85dd47f53701ef1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-impl" version="2.4.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-impl" version="2.4.0">
|
||||||
<artifact name="kotlin-build-tools-impl-2.4.0.jar">
|
<artifact name="kotlin-build-tools-impl-2.4.0.jar">
|
||||||
<sha256 value="076c0a7f84d303f1e390774410c8678b8b584faa3f642435f93d2e4e81dabe7c" origin="Generated by Gradle"/>
|
<sha256 value="076c0a7f84d303f1e390774410c8678b8b584faa3f642435f93d2e4e81dabe7c" origin="Generated by Gradle"/>
|
||||||
@@ -2607,6 +2692,14 @@
|
|||||||
<sha256 value="7a13ab2d818a5de92afa23004aa9baed99671bb48553b7098cf920fa785c3351" origin="Generated by Gradle"/>
|
<sha256 value="7a13ab2d818a5de92afa23004aa9baed99671bb48553b7098cf920fa785c3351" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-build-tools-impl" version="2.4.21">
|
||||||
|
<artifact name="kotlin-build-tools-impl-2.4.21.jar">
|
||||||
|
<sha256 value="3152b3e1fbaa4d48f3681734a2c0efc438359a48c8a3c5cac00d874670de1377" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-build-tools-impl-2.4.21.pom">
|
||||||
|
<sha256 value="6ef5cb90e2d8ea75faf9ec668d306b6be7628f11ebd41878a82cae3e17dbedfb" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-compiler-embeddable" version="2.2.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-compiler-embeddable" version="2.2.0">
|
||||||
<artifact name="kotlin-compiler-embeddable-2.2.0.jar">
|
<artifact name="kotlin-compiler-embeddable-2.2.0.jar">
|
||||||
<sha256 value="b2f743ea5ba12f69e0f35e5d8d46069d74c8e2861087548a7e0e14a784bc4cf1" origin="Generated by Gradle"/>
|
<sha256 value="b2f743ea5ba12f69e0f35e5d8d46069d74c8e2861087548a7e0e14a784bc4cf1" origin="Generated by Gradle"/>
|
||||||
@@ -2631,6 +2724,14 @@
|
|||||||
<sha256 value="269d98cc4c68670c11e4aeb404e1c7c6f31b782321908d7268ba25cd236d59b2" origin="Generated by Gradle"/>
|
<sha256 value="269d98cc4c68670c11e4aeb404e1c7c6f31b782321908d7268ba25cd236d59b2" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-compiler-embeddable" version="2.4.21">
|
||||||
|
<artifact name="kotlin-compiler-embeddable-2.4.21.jar">
|
||||||
|
<sha256 value="ef19419c765e7ac8404465fa026ca8fc4dbb8a822de0fc79aa53c8dce29f1d02" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-compiler-embeddable-2.4.21.pom">
|
||||||
|
<sha256 value="e1620d2b18319cf7495dc67697ab03ba23a7d6d9da685285884a7a8aa08ae891" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-compiler-runner" version="2.4.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-compiler-runner" version="2.4.0">
|
||||||
<artifact name="kotlin-compiler-runner-2.4.0.jar">
|
<artifact name="kotlin-compiler-runner-2.4.0.jar">
|
||||||
<sha256 value="ad9608152740e92d94a278b4ff2ca82c4bf5ff8ef219220e3c07aeb554638cee" origin="Generated by Gradle"/>
|
<sha256 value="ad9608152740e92d94a278b4ff2ca82c4bf5ff8ef219220e3c07aeb554638cee" origin="Generated by Gradle"/>
|
||||||
@@ -2647,6 +2748,14 @@
|
|||||||
<sha256 value="4566946280971fe8d67990ee83480af480e846590f325a40951f62657e26a40a" origin="Generated by Gradle"/>
|
<sha256 value="4566946280971fe8d67990ee83480af480e846590f325a40951f62657e26a40a" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-compiler-runner" version="2.4.21">
|
||||||
|
<artifact name="kotlin-compiler-runner-2.4.21.jar">
|
||||||
|
<sha256 value="75cd5956405697559e6925ebc5808449a2e12002d4f017275281ad3d4c0c7985" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-compiler-runner-2.4.21.pom">
|
||||||
|
<sha256 value="619d17c885321949eaa167af0842cad8f7aa83a4a9ca1051e5de04d11a6c0f40" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-compose-compiler-plugin-embeddable" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-compose-compiler-plugin-embeddable" version="2.4.20">
|
||||||
<artifact name="kotlin-compose-compiler-plugin-embeddable-2.4.20.jar">
|
<artifact name="kotlin-compose-compiler-plugin-embeddable-2.4.20.jar">
|
||||||
<sha256 value="e6fc101fd0b8592911de57f96a75b09e0b6158eaccbc71ddd6ca82e05e0386a2" origin="Generated by Gradle"/>
|
<sha256 value="e6fc101fd0b8592911de57f96a75b09e0b6158eaccbc71ddd6ca82e05e0386a2" origin="Generated by Gradle"/>
|
||||||
@@ -2655,6 +2764,14 @@
|
|||||||
<sha256 value="413bc7cb82d49d020e3fca2f6cb9e905954b5324a86bb941b9113dd83bd77673" origin="Generated by Gradle"/>
|
<sha256 value="413bc7cb82d49d020e3fca2f6cb9e905954b5324a86bb941b9113dd83bd77673" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-compose-compiler-plugin-embeddable" version="2.4.21">
|
||||||
|
<artifact name="kotlin-compose-compiler-plugin-embeddable-2.4.21.jar">
|
||||||
|
<sha256 value="634f5c17bed5854548208f2901071f2ead5993ffad25b34fea1668ee9e314b53" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-compose-compiler-plugin-embeddable-2.4.21.pom">
|
||||||
|
<sha256 value="d5af6aa743ce0fa940b004a6cbd1777db0a76319e1daa1fded9b03c361aa03a3" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-daemon-client" version="2.4.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-daemon-client" version="2.4.0">
|
||||||
<artifact name="kotlin-daemon-client-2.4.0.jar">
|
<artifact name="kotlin-daemon-client-2.4.0.jar">
|
||||||
<sha256 value="f546f0b3699c4984f320dd03080de05cad61064208ba8f37df0d3f8f4a7fd14a" origin="Generated by Gradle"/>
|
<sha256 value="f546f0b3699c4984f320dd03080de05cad61064208ba8f37df0d3f8f4a7fd14a" origin="Generated by Gradle"/>
|
||||||
@@ -2671,6 +2788,14 @@
|
|||||||
<sha256 value="37cff66ae34c924f0f738106eeb7234e7ace880f199de3362e993f4987025adc" origin="Generated by Gradle"/>
|
<sha256 value="37cff66ae34c924f0f738106eeb7234e7ace880f199de3362e993f4987025adc" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-daemon-client" version="2.4.21">
|
||||||
|
<artifact name="kotlin-daemon-client-2.4.21.jar">
|
||||||
|
<sha256 value="095903c4c4713bf91a562d226d7ba0464cf5424e76342d487deec494451ab29b" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-daemon-client-2.4.21.pom">
|
||||||
|
<sha256 value="c2f18065fa18f5e92eff14f34029e4f70052011070655120796adbce7167ad65" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-daemon-embeddable" version="2.2.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-daemon-embeddable" version="2.2.0">
|
||||||
<artifact name="kotlin-daemon-embeddable-2.2.0.jar">
|
<artifact name="kotlin-daemon-embeddable-2.2.0.jar">
|
||||||
<sha256 value="a26cc8e2d8619197cc4d115bea7766e9aa8e0f1e7876ea044ee1b9f305654601" origin="Generated by Gradle"/>
|
<sha256 value="a26cc8e2d8619197cc4d115bea7766e9aa8e0f1e7876ea044ee1b9f305654601" origin="Generated by Gradle"/>
|
||||||
@@ -2695,6 +2820,14 @@
|
|||||||
<sha256 value="ca631ce7c7cc2a8ecb47d3462b429004c1cd3488437b3f739e35eafea2033bfb" origin="Generated by Gradle"/>
|
<sha256 value="ca631ce7c7cc2a8ecb47d3462b429004c1cd3488437b3f739e35eafea2033bfb" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-daemon-embeddable" version="2.4.21">
|
||||||
|
<artifact name="kotlin-daemon-embeddable-2.4.21.jar">
|
||||||
|
<sha256 value="7b3ef24674e5bcffcadfc4e43202ea314194939ecbcdd90a4770b2f1b04e0d07" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-daemon-embeddable-2.4.21.pom">
|
||||||
|
<sha256 value="95236a3a7e9953545e2ff7c6dc0ea7ffeb27560000f20abe89dc53790fec3c7e" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin" version="2.4.20">
|
||||||
<artifact name="kotlin-gradle-plugin-2.4.20-gradle96.jar">
|
<artifact name="kotlin-gradle-plugin-2.4.20-gradle96.jar">
|
||||||
<sha256 value="6f49688f2c6715d60f5dc52d4c1ada992ce4bed6053d1bd6e579c9392d7ba0ed" origin="Generated by Gradle"/>
|
<sha256 value="6f49688f2c6715d60f5dc52d4c1ada992ce4bed6053d1bd6e579c9392d7ba0ed" origin="Generated by Gradle"/>
|
||||||
@@ -2703,6 +2836,14 @@
|
|||||||
<sha256 value="8a88cf52de5fb9c829730b0f5aec1fcd35633e697871e256230f09903c74dd43" origin="Generated by Gradle"/>
|
<sha256 value="8a88cf52de5fb9c829730b0f5aec1fcd35633e697871e256230f09903c74dd43" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin" version="2.4.21">
|
||||||
|
<artifact name="kotlin-gradle-plugin-2.4.21-gradle96.jar">
|
||||||
|
<sha256 value="d0a11912936c8801f1773a47e8fc51835a6ab568d73e4e1d188281955a7f575b" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-gradle-plugin-2.4.21.module">
|
||||||
|
<sha256 value="a412aecabbb40c7ed2fad5311d0114d4ca0e3a9690658ad3c4caed619e400d94" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-annotations" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-annotations" version="2.4.20">
|
||||||
<artifact name="kotlin-gradle-plugin-annotations-2.4.20.jar">
|
<artifact name="kotlin-gradle-plugin-annotations-2.4.20.jar">
|
||||||
<sha256 value="fd400d73f635ed83875e75093c40a587840d4af399dcf6931239ba8fe469ef85" origin="Generated by Gradle"/>
|
<sha256 value="fd400d73f635ed83875e75093c40a587840d4af399dcf6931239ba8fe469ef85" origin="Generated by Gradle"/>
|
||||||
@@ -2711,6 +2852,14 @@
|
|||||||
<sha256 value="d903e1b1b633cdd7c85e557a4426b0c7b8584065a46fe626826a4da3790f945d" origin="Generated by Gradle"/>
|
<sha256 value="d903e1b1b633cdd7c85e557a4426b0c7b8584065a46fe626826a4da3790f945d" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-annotations" version="2.4.21">
|
||||||
|
<artifact name="kotlin-gradle-plugin-annotations-2.4.21.jar">
|
||||||
|
<sha256 value="5c386b0fa287584497b07d62af954e30d05907e6da867221124d0bb936989bbd" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-gradle-plugin-annotations-2.4.21.pom">
|
||||||
|
<sha256 value="b0f6b87a35d4be7ae06e554efdb261ea4bc5d59fa282c23ee28061d30805ddd6" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-api" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-api" version="2.4.20">
|
||||||
<artifact name="kotlin-gradle-plugin-api-2.4.20-gradle96.jar">
|
<artifact name="kotlin-gradle-plugin-api-2.4.20-gradle96.jar">
|
||||||
<sha256 value="fc9e18f84f1a5805532932f5293ec11121769263b396641f779e7b67fb4250a6" origin="Generated by Gradle"/>
|
<sha256 value="fc9e18f84f1a5805532932f5293ec11121769263b396641f779e7b67fb4250a6" origin="Generated by Gradle"/>
|
||||||
@@ -2719,6 +2868,14 @@
|
|||||||
<sha256 value="4bea3899dada541c1e482246b2573678eaedf611af7f1674ce0a17d5c3effdc0" origin="Generated by Gradle"/>
|
<sha256 value="4bea3899dada541c1e482246b2573678eaedf611af7f1674ce0a17d5c3effdc0" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-api" version="2.4.21">
|
||||||
|
<artifact name="kotlin-gradle-plugin-api-2.4.21-gradle96.jar">
|
||||||
|
<sha256 value="43b8c73f3e4f123b1a5e4bc8e62bd9b258dfa84129e6564bebb03c5fada84d23" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-gradle-plugin-api-2.4.21.module">
|
||||||
|
<sha256 value="b8ae1c9ee5976145d4fd7925012e5699e2df5df7fe9613bac41d59404a58e815" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-idea" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-idea" version="2.4.20">
|
||||||
<artifact name="kotlin-gradle-plugin-idea-2.4.20.jar">
|
<artifact name="kotlin-gradle-plugin-idea-2.4.20.jar">
|
||||||
<sha256 value="086734484c7edf19a620ab1a617d097c40e03bc52602e77840ea5ebd6380e514" origin="Generated by Gradle"/>
|
<sha256 value="086734484c7edf19a620ab1a617d097c40e03bc52602e77840ea5ebd6380e514" origin="Generated by Gradle"/>
|
||||||
@@ -2727,6 +2884,14 @@
|
|||||||
<sha256 value="7a8c8d128782b4f46b5d831c7eda2513d871d321a483a43aadbe77f97224cb64" origin="Generated by Gradle"/>
|
<sha256 value="7a8c8d128782b4f46b5d831c7eda2513d871d321a483a43aadbe77f97224cb64" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-idea" version="2.4.21">
|
||||||
|
<artifact name="kotlin-gradle-plugin-idea-2.4.21.jar">
|
||||||
|
<sha256 value="086734484c7edf19a620ab1a617d097c40e03bc52602e77840ea5ebd6380e514" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-gradle-plugin-idea-2.4.21.module">
|
||||||
|
<sha256 value="ddd2bb8f319a7c468ba2fb5a404b795c69e066bd5ad2d565b47b86fa2a337606" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-idea-proto" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-idea-proto" version="2.4.20">
|
||||||
<artifact name="kotlin-gradle-plugin-idea-proto-2.4.20.jar">
|
<artifact name="kotlin-gradle-plugin-idea-proto-2.4.20.jar">
|
||||||
<sha256 value="a3a5535287930428ecbd4a326cb9d7d7c477e9f1a81e9573c3c973940c8f1477" origin="Generated by Gradle"/>
|
<sha256 value="a3a5535287930428ecbd4a326cb9d7d7c477e9f1a81e9573c3c973940c8f1477" origin="Generated by Gradle"/>
|
||||||
@@ -2735,6 +2900,14 @@
|
|||||||
<sha256 value="d059dace6e76f36808ce94e8588a603324716d07767bc874206036794ba3bd05" origin="Generated by Gradle"/>
|
<sha256 value="d059dace6e76f36808ce94e8588a603324716d07767bc874206036794ba3bd05" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugin-idea-proto" version="2.4.21">
|
||||||
|
<artifact name="kotlin-gradle-plugin-idea-proto-2.4.21.jar">
|
||||||
|
<sha256 value="4559d92c5c1758a3e1ec5728822b059b2eb4aebef13c701ee86c7688acf164d5" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-gradle-plugin-idea-proto-2.4.21.pom">
|
||||||
|
<sha256 value="3c6eff2166eb46a8474b7bcccaa7d1ca5074260c866cc4bb2ba3678216a7bc15" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugins-bom" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugins-bom" version="2.4.20">
|
||||||
<artifact name="kotlin-gradle-plugins-bom-2.4.20.module">
|
<artifact name="kotlin-gradle-plugins-bom-2.4.20.module">
|
||||||
<sha256 value="6dfa7dfda619ad248e413cf313c313705db0aa0dbc410b3a8e0d922acfa82c94" origin="Generated by Gradle"/>
|
<sha256 value="6dfa7dfda619ad248e413cf313c313705db0aa0dbc410b3a8e0d922acfa82c94" origin="Generated by Gradle"/>
|
||||||
@@ -2743,6 +2916,14 @@
|
|||||||
<sha256 value="70b071dc4074995076c97c749792ebcff69f10e636d1e2f2c68de0de023e0239" origin="Generated by Gradle"/>
|
<sha256 value="70b071dc4074995076c97c749792ebcff69f10e636d1e2f2c68de0de023e0239" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-gradle-plugins-bom" version="2.4.21">
|
||||||
|
<artifact name="kotlin-gradle-plugins-bom-2.4.21.module">
|
||||||
|
<sha256 value="04f6a73a2c34217ac31599b8ed5ff24b85ebd410d32242eb27965c7b213f56c3" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-gradle-plugins-bom-2.4.21.pom">
|
||||||
|
<sha256 value="624c0c869b3fcf1665afec9c5c51a807be0a8c983931ebb188548ddcdb055780" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-klib-commonizer-api" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-klib-commonizer-api" version="2.4.20">
|
||||||
<artifact name="kotlin-klib-commonizer-api-2.4.20.jar">
|
<artifact name="kotlin-klib-commonizer-api-2.4.20.jar">
|
||||||
<sha256 value="e13c80f2f96afce37d776e77ae8a2f5c4d3c72f4b0526271694b36786f27d331" origin="Generated by Gradle"/>
|
<sha256 value="e13c80f2f96afce37d776e77ae8a2f5c4d3c72f4b0526271694b36786f27d331" origin="Generated by Gradle"/>
|
||||||
@@ -2751,6 +2932,14 @@
|
|||||||
<sha256 value="b1edb50183d4549ad0fb449498535ab4186d491d86ad315e0187bcb9f9c7496d" origin="Generated by Gradle"/>
|
<sha256 value="b1edb50183d4549ad0fb449498535ab4186d491d86ad315e0187bcb9f9c7496d" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-klib-commonizer-api" version="2.4.21">
|
||||||
|
<artifact name="kotlin-klib-commonizer-api-2.4.21.jar">
|
||||||
|
<sha256 value="62ebe32fcf69600125b28388f0a80781276784d90e14d333bbd5080b4807220c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-klib-commonizer-api-2.4.21.pom">
|
||||||
|
<sha256 value="186a53ce6f218e43472808dc32cab627e19c144df2517398794bdb53d2df14a0" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-metadata-jvm" version="2.3.21">
|
<component group="org.jetbrains.kotlin" name="kotlin-metadata-jvm" version="2.3.21">
|
||||||
<artifact name="kotlin-metadata-jvm-2.3.21.jar">
|
<artifact name="kotlin-metadata-jvm-2.3.21.jar">
|
||||||
<sha256 value="00590f26a5a768777f04252c6cf93c016a3361a6bc93636df67375ad4d19557d" origin="Generated by Gradle"/>
|
<sha256 value="00590f26a5a768777f04252c6cf93c016a3361a6bc93636df67375ad4d19557d" origin="Generated by Gradle"/>
|
||||||
@@ -2767,6 +2956,14 @@
|
|||||||
<sha256 value="453ba071c89165cbdfc877ca733a4f38c01fc2f4894e9a259d7651f1176cd80c" origin="Generated by Gradle"/>
|
<sha256 value="453ba071c89165cbdfc877ca733a4f38c01fc2f4894e9a259d7651f1176cd80c" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-native-utils" version="2.4.21">
|
||||||
|
<artifact name="kotlin-native-utils-2.4.21.jar">
|
||||||
|
<sha256 value="e1858bf1fb5bbb1738c4fa0f9cfb502b911cabf313a5de4cae686d6c50d74814" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-native-utils-2.4.21.pom">
|
||||||
|
<sha256 value="9882156113d96f7911101a721cce2adefe2c8d9acc8844fb6397b8523538db37" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-reflect" version="1.6.10">
|
<component group="org.jetbrains.kotlin" name="kotlin-reflect" version="1.6.10">
|
||||||
<artifact name="kotlin-reflect-1.6.10.jar">
|
<artifact name="kotlin-reflect-1.6.10.jar">
|
||||||
<sha256 value="3277ac102ae17aad10a55abec75ff5696c8d109790396434b496e75087854203" origin="Generated by Gradle"/>
|
<sha256 value="3277ac102ae17aad10a55abec75ff5696c8d109790396434b496e75087854203" origin="Generated by Gradle"/>
|
||||||
@@ -2815,6 +3012,14 @@
|
|||||||
<sha256 value="dd0e3846b61a6d641300958cc52e4693cd7b47bd1d626505f383b2f9d23ade0e" origin="Generated by Gradle"/>
|
<sha256 value="dd0e3846b61a6d641300958cc52e4693cd7b47bd1d626505f383b2f9d23ade0e" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-script-runtime" version="2.4.21">
|
||||||
|
<artifact name="kotlin-script-runtime-2.4.21.jar">
|
||||||
|
<sha256 value="a658cf5902a1525a06c264a5e42b437e97a6679ddeef8ca641246f270cf6a013" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-script-runtime-2.4.21.pom">
|
||||||
|
<sha256 value="425d1683a903d085a1718122918242ad6ad0246c79283786697395e4d3a8c801" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-stdlib" version="2.2.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-stdlib" version="2.2.0">
|
||||||
<artifact name="kotlin-stdlib-2.2.0.jar">
|
<artifact name="kotlin-stdlib-2.2.0.jar">
|
||||||
<sha256 value="65d12d85a3b865c160db9147851712a64b10dadd68b22eea22a95bf8a8670dca" origin="Generated by Gradle"/>
|
<sha256 value="65d12d85a3b865c160db9147851712a64b10dadd68b22eea22a95bf8a8670dca" origin="Generated by Gradle"/>
|
||||||
@@ -2879,6 +3084,14 @@
|
|||||||
<sha256 value="afb28052ac6c3d605c0f661816ea653e073eb039682fed35bfa6cdc704c0911c" origin="Generated by Gradle"/>
|
<sha256 value="afb28052ac6c3d605c0f661816ea653e073eb039682fed35bfa6cdc704c0911c" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-stdlib" version="2.4.21">
|
||||||
|
<artifact name="kotlin-stdlib-2.4.21.jar">
|
||||||
|
<sha256 value="bd8250210584cb659847dce9cda660f8e9906e5def7fbebcea93dc6dcb6a88a3" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-stdlib-2.4.21.module">
|
||||||
|
<sha256 value="03b0df67c0cd74a948a45c5b03c4bbcfb31ab9b9879fb380adf7c187b6594b7f" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-common" version="2.2.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-common" version="2.2.0">
|
||||||
<artifact name="kotlin-stdlib-common-2.2.0.module">
|
<artifact name="kotlin-stdlib-common-2.2.0.module">
|
||||||
<sha256 value="58fc0d664fc3a67e7e6be9fdbeaedbd212dfa3e527f744f861e792cda72c0e47" origin="Generated by Gradle"/>
|
<sha256 value="58fc0d664fc3a67e7e6be9fdbeaedbd212dfa3e527f744f861e792cda72c0e47" origin="Generated by Gradle"/>
|
||||||
@@ -2924,6 +3137,14 @@
|
|||||||
<sha256 value="29dd79ed2bc1e64f6bfd5ccf0c1336c6b6c11ee2a69e0c585e3fad2f45b5325d" origin="Generated by Gradle"/>
|
<sha256 value="29dd79ed2bc1e64f6bfd5ccf0c1336c6b6c11ee2a69e0c585e3fad2f45b5325d" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-tooling-core" version="2.4.21">
|
||||||
|
<artifact name="kotlin-tooling-core-2.4.21.jar">
|
||||||
|
<sha256 value="5fc5db083803232857408ed5c25bcc307c703b04bdef6cb2c34ebf4db611a622" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-tooling-core-2.4.21.pom">
|
||||||
|
<sha256 value="b26b1cb6480001519d4650586cdc6054ea2d2d486ff332431c543eb8f76f41ce" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-util-io" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-util-io" version="2.4.20">
|
||||||
<artifact name="kotlin-util-io-2.4.20.jar">
|
<artifact name="kotlin-util-io-2.4.20.jar">
|
||||||
<sha256 value="944edbec0f4438b40999e81872f6b05b0604abac6ed11d72c27846d19835f24c" origin="Generated by Gradle"/>
|
<sha256 value="944edbec0f4438b40999e81872f6b05b0604abac6ed11d72c27846d19835f24c" origin="Generated by Gradle"/>
|
||||||
@@ -2932,6 +3153,14 @@
|
|||||||
<sha256 value="840f888f360f4395c0967e17620b96d8b0cf5180efe2a214fdabd4d66677665b" origin="Generated by Gradle"/>
|
<sha256 value="840f888f360f4395c0967e17620b96d8b0cf5180efe2a214fdabd4d66677665b" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-util-io" version="2.4.21">
|
||||||
|
<artifact name="kotlin-util-io-2.4.21.jar">
|
||||||
|
<sha256 value="5821175f24578ca8f1ef405bc982b3668f3f40f1a5dd28bb3283dd5215a922d1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-util-io-2.4.21.pom">
|
||||||
|
<sha256 value="a16f898aa8c686dc0b83d556ac4adecfcadbb6662ca547fca7802bf536d6d3d3" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-util-klib" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-util-klib" version="2.4.20">
|
||||||
<artifact name="kotlin-util-klib-2.4.20.jar">
|
<artifact name="kotlin-util-klib-2.4.20.jar">
|
||||||
<sha256 value="3a58f9a82378e13ea5045266de2c09a8e5a05c44dd92131c4a83794fd3d1ceca" origin="Generated by Gradle"/>
|
<sha256 value="3a58f9a82378e13ea5045266de2c09a8e5a05c44dd92131c4a83794fd3d1ceca" origin="Generated by Gradle"/>
|
||||||
@@ -2940,6 +3169,14 @@
|
|||||||
<sha256 value="7fb051f47bbe01f318a1f434e2a7ed61a446fcc7a4d3ccb5a44c2b5105b0fd6b" origin="Generated by Gradle"/>
|
<sha256 value="7fb051f47bbe01f318a1f434e2a7ed61a446fcc7a4d3ccb5a44c2b5105b0fd6b" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-util-klib" version="2.4.21">
|
||||||
|
<artifact name="kotlin-util-klib-2.4.21.jar">
|
||||||
|
<sha256 value="f01f79d54968941dfa83a525ae173be93460bb85b0bf2cc9ff06f6eb0864691e" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-util-klib-2.4.21.pom">
|
||||||
|
<sha256 value="97b59495de92c789c6963e4e70d5545ceccd2f0fab67d7ce72f7c5a87b948030" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-util-klib-metadata" version="2.4.20">
|
<component group="org.jetbrains.kotlin" name="kotlin-util-klib-metadata" version="2.4.20">
|
||||||
<artifact name="kotlin-util-klib-metadata-2.4.20.jar">
|
<artifact name="kotlin-util-klib-metadata-2.4.20.jar">
|
||||||
<sha256 value="75027fd053a594ab1ff64aa360cb1d6d13e9a7e3775583508b4811e0333823d8" origin="Generated by Gradle"/>
|
<sha256 value="75027fd053a594ab1ff64aa360cb1d6d13e9a7e3775583508b4811e0333823d8" origin="Generated by Gradle"/>
|
||||||
@@ -2948,16 +3185,34 @@
|
|||||||
<sha256 value="90c5c8092955a601898c74f7dae3945fb0d041d5191d009bab41d530f8402f4f" origin="Generated by Gradle"/>
|
<sha256 value="90c5c8092955a601898c74f7dae3945fb0d041d5191d009bab41d530f8402f4f" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-util-klib-metadata" version="2.4.21">
|
||||||
|
<artifact name="kotlin-util-klib-metadata-2.4.21.jar">
|
||||||
|
<sha256 value="a47f883b82fc3b99fe3d666498b22312628afb5cc1b9b26e8188175be2da6060" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlin-util-klib-metadata-2.4.21.pom">
|
||||||
|
<sha256 value="a0f7f315c9f60b53458cc1e034a7c55e17619ce7db51db43efb7d3cdacbb5c6c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin.jvm" name="org.jetbrains.kotlin.jvm.gradle.plugin" version="2.4.20">
|
<component group="org.jetbrains.kotlin.jvm" name="org.jetbrains.kotlin.jvm.gradle.plugin" version="2.4.20">
|
||||||
<artifact name="org.jetbrains.kotlin.jvm.gradle.plugin-2.4.20.pom">
|
<artifact name="org.jetbrains.kotlin.jvm.gradle.plugin-2.4.20.pom">
|
||||||
<sha256 value="f3b27910045c1e1e21cb48d68a7e177ea1a4a3dda467e546c15c30b9c098187c" origin="Generated by Gradle"/>
|
<sha256 value="f3b27910045c1e1e21cb48d68a7e177ea1a4a3dda467e546c15c30b9c098187c" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin.jvm" name="org.jetbrains.kotlin.jvm.gradle.plugin" version="2.4.21">
|
||||||
|
<artifact name="org.jetbrains.kotlin.jvm.gradle.plugin-2.4.21.pom">
|
||||||
|
<sha256 value="8e08073d123182e69c07d24c6dca7b98cc53a37707a73a6af7be88e38218b42b" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin.plugin.compose" name="org.jetbrains.kotlin.plugin.compose.gradle.plugin" version="2.4.20">
|
<component group="org.jetbrains.kotlin.plugin.compose" name="org.jetbrains.kotlin.plugin.compose.gradle.plugin" version="2.4.20">
|
||||||
<artifact name="org.jetbrains.kotlin.plugin.compose.gradle.plugin-2.4.20.pom">
|
<artifact name="org.jetbrains.kotlin.plugin.compose.gradle.plugin-2.4.20.pom">
|
||||||
<sha256 value="9ed1b04a99d38243a15a42b37d4dc4ba84ca77f35d77c081a7c2208d439e1220" origin="Generated by Gradle"/>
|
<sha256 value="9ed1b04a99d38243a15a42b37d4dc4ba84ca77f35d77c081a7c2208d439e1220" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin.plugin.compose" name="org.jetbrains.kotlin.plugin.compose.gradle.plugin" version="2.4.21">
|
||||||
|
<artifact name="org.jetbrains.kotlin.plugin.compose.gradle.plugin-2.4.21.pom">
|
||||||
|
<sha256 value="ee66712b1006e971636f11554af63c56835caf315382ce23e54f59f5b8b9d4f9" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-android" version="1.11.0">
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-android" version="1.11.0">
|
||||||
<artifact name="kotlinx-coroutines-android-1.11.0.jar">
|
<artifact name="kotlinx-coroutines-android-1.11.0.jar">
|
||||||
<sha256 value="c2cb206d27017c7d1bf5ff179787397543d13748dbabb0d7237e1585e0b29044" origin="Generated by Gradle"/>
|
<sha256 value="c2cb206d27017c7d1bf5ff179787397543d13748dbabb0d7237e1585e0b29044" origin="Generated by Gradle"/>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
# Manual edits can break the build and are not advised.
|
# Manual edits can break the build and are not advised.
|
||||||
# This file is expected to be part of source control.
|
# This file is expected to be part of source control.
|
||||||
# To regenerate this file, run: ./gradlew :platform:dependencies --write-locks
|
# To regenerate this file, run: ./gradlew :platform:dependencies --write-locks
|
||||||
|
androidx.annotation:annotation-jvm:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
ch.qos.logback:logback-classic:1.3.15=ktlint
|
ch.qos.logback:logback-classic:1.3.15=ktlint
|
||||||
ch.qos.logback:logback-core:1.3.15=ktlint
|
ch.qos.logback:logback-core:1.3.15=ktlint
|
||||||
com.android.tools.analytics-library:protos:32.4.1=androidLintTool
|
com.android.tools.analytics-library:protos:32.4.1=androidLintTool
|
||||||
@@ -75,6 +77,7 @@ jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool
|
|||||||
javax.inject:javax.inject:1=androidLintTool
|
javax.inject:javax.inject:1=androidLintTool
|
||||||
junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
||||||
|
net.java.dev.jna:jna:5.19.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
net.java.dev.jna:jna:5.6.0=androidLintTool
|
net.java.dev.jna:jna:5.6.0=androidLintTool
|
||||||
net.sf.kxml:kxml2:2.3.0=androidLintTool
|
net.sf.kxml:kxml2:2.3.0=androidLintTool
|
||||||
org.apache.commons:commons-compress:1.27.1=androidLintTool
|
org.apache.commons:commons-compress:1.27.1=androidLintTool
|
||||||
@@ -93,27 +96,27 @@ org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
|||||||
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
||||||
org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.20=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-client:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-daemon-client:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-client:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-daemon-client:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool
|
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-script-runtime:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-script-runtime:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-script-runtime:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0=ktlintReporter
|
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0=ktlintReporter
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=ktlintReporter
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=ktlintReporter
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
@@ -122,8 +125,8 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.10=androidLintTool,unified-test-plat
|
|||||||
org.jetbrains.kotlin:kotlin-stdlib:2.2.0=ktlint,ktlintBaselineReporter,ktlintReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-stdlib:2.2.0=ktlint,ktlintBaselineReporter,ktlintReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlin:kotlin-stdlib:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.20=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-tooling-core:2.4.20=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import java.io.File
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
@@ -10,6 +11,8 @@ android {
|
|||||||
ndkVersion = libs.versions.ndk.get()
|
ndkVersion = libs.versions.ndk.get()
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = libs.versions.minSdk.get().toInt()
|
minSdk = libs.versions.minSdk.get().toInt()
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64") }
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
@@ -28,5 +31,134 @@ kotlin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation("${libs.jna.get().module}:${libs.versions.jna.get()}@aar")
|
||||||
|
implementation(libs.annotation)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
|
androidTestImplementation(libs.android.test.runner)
|
||||||
|
}
|
||||||
|
|
||||||
|
val workspace = rootProject.layout.projectDirectory.dir("..").asFile
|
||||||
|
val cargoExecutable = providers.environmentVariable("CARGO").orElse(
|
||||||
|
providers.environmentVariable("PATH").map { path ->
|
||||||
|
path.split(File.pathSeparatorChar).map { File(it, "cargo") }
|
||||||
|
.firstOrNull { it.isFile && it.canExecute() }?.absolutePath
|
||||||
|
?: error("Cargo must be installed and in PATH")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val rustVersion = libs.versions.rust.get()
|
||||||
|
val ndkDirectory = androidComponents.sdkComponents.ndkDirectory
|
||||||
|
val sdkDirectory = androidComponents.sdkComponents.sdkDirectory
|
||||||
|
val rustInputs = files(
|
||||||
|
workspace.resolve("Cargo.toml"),
|
||||||
|
workspace.resolve("Cargo.lock"),
|
||||||
|
rootProject.file("rust-toolchain.toml"),
|
||||||
|
fileTree(workspace.resolve("crates")) { include("**/*.rs", "**/Cargo.toml", "**/uniffi.toml") }
|
||||||
|
)
|
||||||
|
val checkRustToolchain = tasks.register<Exec>("checkRustToolchain") {
|
||||||
|
workingDir = workspace
|
||||||
|
commandLine(
|
||||||
|
cargoExecutable.get(), "+$rustVersion", "run", "--locked",
|
||||||
|
"--package", "ironstorage-android-build", "--", "check-toolchain",
|
||||||
|
cargoExecutable.get(), rustVersion, ndkDirectory.get().asFile.absolutePath,
|
||||||
|
libs.versions.ndk.get(), libs.versions.cargoNdk.get()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
androidComponents.onVariants { variant ->
|
||||||
|
val name = variant.name
|
||||||
|
val title = name.replaceFirstChar { it.uppercaseChar() }
|
||||||
|
val rawNative = layout.buildDirectory.dir("generated/native-raw/$name/jniLibs")
|
||||||
|
val nativeOutput = layout.buildDirectory.dir("generated/native/$name/jniLibs")
|
||||||
|
val rawBindings = layout.buildDirectory.dir("generated/bindings-raw/$name")
|
||||||
|
val bindings = layout.buildDirectory.dir("generated/bindings/$name")
|
||||||
|
val native = tasks.register<Exec>("build${title}Rust") {
|
||||||
|
dependsOn(checkRustToolchain)
|
||||||
|
workingDir = workspace
|
||||||
|
inputs.files(rustInputs)
|
||||||
|
inputs.property("rustVersion", rustVersion)
|
||||||
|
inputs.property("cargoNdk", libs.versions.cargoNdk.get())
|
||||||
|
inputs.property("ndkVersion", libs.versions.ndk.get())
|
||||||
|
inputs.property("minSdk", libs.versions.minSdk.get())
|
||||||
|
outputs.dir(rawNative)
|
||||||
|
environment("ANDROID_NDK_HOME", ndkDirectory.get().asFile.absolutePath)
|
||||||
|
environment("ANDROID_HOME", sdkDirectory.get().asFile.absolutePath)
|
||||||
|
environment(
|
||||||
|
"RUSTFLAGS",
|
||||||
|
"-D warnings -C link-arg=-Wl,-z,max-page-size=16384 -C link-arg=-Wl,-z,common-page-size=16384"
|
||||||
|
)
|
||||||
|
environment("CARGO_PROFILE_RELEASE_DEBUG", "2")
|
||||||
|
commandLine(
|
||||||
|
listOf(
|
||||||
|
cargoExecutable.get(), "+$rustVersion", "ndk",
|
||||||
|
"--target", "arm64-v8a",
|
||||||
|
"--target", "armeabi-v7a",
|
||||||
|
"--target", "x86_64",
|
||||||
|
"--platform", libs.versions.minSdk.get(),
|
||||||
|
"--output-dir", rawNative.get().asFile.absolutePath,
|
||||||
|
"build", "--locked", "--package", "ironstorage-android", "--lib"
|
||||||
|
) +
|
||||||
|
if (variant.buildType == "release") listOf("--release") else emptyList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val audit = tasks.register<Exec>("package${title}Rust") {
|
||||||
|
dependsOn(native)
|
||||||
|
workingDir = workspace
|
||||||
|
inputs.dir(rawNative)
|
||||||
|
inputs.files(
|
||||||
|
fileTree(workspace.resolve("tools/android-build")) {
|
||||||
|
include("**/*.rs", "Cargo.toml")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
outputs.dir(nativeOutput)
|
||||||
|
commandLine(
|
||||||
|
cargoExecutable.get(), "+$rustVersion", "run", "--locked",
|
||||||
|
"--package", "ironstorage-android-build", "--", "package-native",
|
||||||
|
rawNative.get().asFile.absolutePath, nativeOutput.get().asFile.absolutePath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val generate = tasks.register<Exec>("generate${title}RustBindings") {
|
||||||
|
dependsOn(audit)
|
||||||
|
workingDir = workspace
|
||||||
|
inputs.dir(nativeOutput)
|
||||||
|
inputs.file(rootProject.file("uniffi.toml"))
|
||||||
|
inputs.files(
|
||||||
|
fileTree(workspace.resolve("tools/android-build")) {
|
||||||
|
include("**/*.rs", "Cargo.toml")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
outputs.dir(rawBindings)
|
||||||
|
commandLine(
|
||||||
|
cargoExecutable.get(), "+$rustVersion", "run", "--locked",
|
||||||
|
"--package", "ironstorage-android-build", "--bin", "ironstorage-uniffi-bindgen",
|
||||||
|
"--", "generate", "--library",
|
||||||
|
nativeOutput.get().file(
|
||||||
|
"arm64-v8a/libironstorage_android.so"
|
||||||
|
).asFile.absolutePath,
|
||||||
|
"--language", "kotlin", "--config",
|
||||||
|
rootProject.file(
|
||||||
|
"uniffi.toml"
|
||||||
|
).absolutePath,
|
||||||
|
"--out-dir", rawBindings.get().asFile.absolutePath, "--no-format"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val prepare = tasks.register<Exec>("prepare${title}RustBindings") {
|
||||||
|
dependsOn(generate)
|
||||||
|
workingDir = workspace
|
||||||
|
inputs.dir(rawBindings)
|
||||||
|
inputs.files(
|
||||||
|
fileTree(workspace.resolve("tools/android-build")) {
|
||||||
|
include("**/*.rs", "Cargo.toml")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
outputs.dir(bindings)
|
||||||
|
commandLine(
|
||||||
|
cargoExecutable.get(), "+$rustVersion", "run", "--locked",
|
||||||
|
"--package", "ironstorage-android-build", "--", "prepare-bindings",
|
||||||
|
rawBindings.get().asFile.absolutePath, bindings.get().asFile.absolutePath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
variant.sources.kotlin!!.addStaticSourceDirectory(bindings.get().asFile.absolutePath)
|
||||||
|
variant.sources.jniLibs!!.addStaticSourceDirectory(nativeOutput.get().asFile.absolutePath)
|
||||||
|
tasks.matching {
|
||||||
|
it.name == "pre${title}Build" || it.name == "compile${title}Kotlin"
|
||||||
|
}.configureEach { dependsOn(prepare) }
|
||||||
}
|
}
|
||||||
@@ -1 +1,7 @@
|
|||||||
# Native/generated keep rules are added with the UniFFI packaging in #92.
|
-keep class com.sun.jna.** { *; }
|
||||||
|
-keep class de.rfc1437.ironstorage.bridge.generated.** { *; }
|
||||||
|
# JNA includes optional desktop AWT helpers that Android never invokes.
|
||||||
|
-dontwarn java.awt.Component
|
||||||
|
-dontwarn java.awt.GraphicsEnvironment
|
||||||
|
-dontwarn java.awt.HeadlessException
|
||||||
|
-dontwarn java.awt.Window
|
||||||
@@ -2,6 +2,12 @@
|
|||||||
# Manual edits can break the build and are not advised.
|
# Manual edits can break the build and are not advised.
|
||||||
# This file is expected to be part of source control.
|
# This file is expected to be part of source control.
|
||||||
# To regenerate this file, run: ./gradlew :rust-bridge:dependencies --write-locks
|
# To regenerate this file, run: ./gradlew :rust-bridge:dependencies --write-locks
|
||||||
|
androidx.annotation:annotation-jvm:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation:1.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.test.services:storage:1.6.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test:monitor:1.8.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test:runner:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.tracing:tracing:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
ch.qos.logback:logback-classic:1.3.15=ktlint
|
ch.qos.logback:logback-classic:1.3.15=ktlint
|
||||||
ch.qos.logback:logback-core:1.3.15=ktlint
|
ch.qos.logback:logback-core:1.3.15=ktlint
|
||||||
com.android.tools.analytics-library:protos:32.4.1=androidLintTool
|
com.android.tools.analytics-library:protos:32.4.1=androidLintTool
|
||||||
@@ -73,8 +79,9 @@ io.github.oshai:kotlin-logging:5.1.0=ktlint,ktlintBaselineReporter,ktlintReporte
|
|||||||
jakarta.activation:jakarta.activation-api:1.2.1=androidLintTool
|
jakarta.activation:jakarta.activation-api:1.2.1=androidLintTool
|
||||||
jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool
|
jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool
|
||||||
javax.inject:javax.inject:1=androidLintTool
|
javax.inject:javax.inject:1=androidLintTool
|
||||||
junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
junit:junit:4.13.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
||||||
|
net.java.dev.jna:jna:5.19.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
net.java.dev.jna:jna:5.6.0=androidLintTool
|
net.java.dev.jna:jna:5.6.0=androidLintTool
|
||||||
net.sf.kxml:kxml2:2.3.0=androidLintTool
|
net.sf.kxml:kxml2:2.3.0=androidLintTool
|
||||||
org.apache.commons:commons-compress:1.27.1=androidLintTool
|
org.apache.commons:commons-compress:1.27.1=androidLintTool
|
||||||
@@ -91,29 +98,29 @@ org.checkerframework:checker-qual:3.43.0=androidLintTool
|
|||||||
org.ec4j.core:ec4j-core:1.1.1=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.ec4j.core:ec4j-core:1.1.1=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
||||||
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
||||||
org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.20=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-cri-impl:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-impl:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-compiler-embeddable:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-client:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-daemon-client:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-client:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-daemon-client:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-daemon-embeddable:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool
|
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-script-runtime:2.2.0=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-script-runtime:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-script-runtime:2.4.20=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-script-runtime:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0=ktlintReporter
|
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.0=ktlintReporter
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=ktlintReporter
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=ktlintReporter
|
||||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
@@ -122,8 +129,8 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.10=androidLintTool,unified-test-plat
|
|||||||
org.jetbrains.kotlin:kotlin-stdlib:2.2.0=ktlint,ktlintBaselineReporter,ktlintReporter,ktlintRuleset
|
org.jetbrains.kotlin:kotlin-stdlib:2.2.0=ktlint,ktlintBaselineReporter,ktlintReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlin:kotlin-stdlib:2.2.10=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.20=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-tooling-core:2.4.20=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
|
|||||||
+128
@@ -0,0 +1,128 @@
|
|||||||
|
package de.rfc1437.ironstorage.bridge
|
||||||
|
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.FfiConverterString
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.IntegrityCheckingUniffiLib
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.InternalException
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAuthenticationErrorKind
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAuthenticationFfiException
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileEntryCopy
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileShellState
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileTab
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.UniffiRustCallStatus
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.uniffiTraitInterfaceCall
|
||||||
|
import java.io.File
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertThrows
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class NativeRuntimeTest {
|
||||||
|
private val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun generatedBindingsCallEveryRustFixtureAndRedactDiagnostics() {
|
||||||
|
val runtime = NativeRuntime(context)
|
||||||
|
MobileShellState.entries.forEach { state ->
|
||||||
|
val shell = runtime.fixture(state)
|
||||||
|
assertEquals(MobileTab.entries, shell.pages.map { it.tab })
|
||||||
|
assertEquals(setOf(state), shell.pages.map { it.state }.toSet())
|
||||||
|
}
|
||||||
|
val secret = "NativeFixtureSecretMustNeverAppearInDiagnostics"
|
||||||
|
val copy = MobileEntryCopy(secret, 60uL)
|
||||||
|
assertEquals(secret, copy.value)
|
||||||
|
assertFalse(copy.toString().contains(secret))
|
||||||
|
val error = MobileAuthenticationFfiException.Failed(
|
||||||
|
MobileAuthenticationErrorKind.entries.first(),
|
||||||
|
secret,
|
||||||
|
secret
|
||||||
|
)
|
||||||
|
assertFalse(error.toString().contains(secret))
|
||||||
|
assertFalse(error.message.contains(secret))
|
||||||
|
assertFalse(InternalException(secret).toString().contains(secret))
|
||||||
|
val status = UniffiRustCallStatus()
|
||||||
|
uniffiTraitInterfaceCall<Unit>(status, { throw IllegalStateException(secret) }, {})
|
||||||
|
assertEquals(
|
||||||
|
"Native callback failed ([REDACTED])",
|
||||||
|
FfiConverterString.lift(status.error_buf)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wrongNativeContractAndChecksumFailWithTypedRedactedErrors() {
|
||||||
|
NativeRuntime(context).fixture(MobileShellState.EMPTY)
|
||||||
|
val version = IntegrityCheckingUniffiLib
|
||||||
|
.ffi_ironstorage_apple_uniffi_contract_version().toLong()
|
||||||
|
val checksum = IntegrityCheckingUniffiLib
|
||||||
|
.uniffi_ironstorage_apple_checksum_func_mobile_shell_fixture().toLong() and 0xffffL
|
||||||
|
NativeBindingChecks.requireMatch(-27278, 38258, NativeFailureKind.ChecksumMismatch)
|
||||||
|
for ((actual, kind) in listOf(
|
||||||
|
version to NativeFailureKind.ContractMismatch,
|
||||||
|
checksum to NativeFailureKind.ChecksumMismatch
|
||||||
|
)) {
|
||||||
|
val failure = assertThrows(NativeBindingMismatchException::class.java) {
|
||||||
|
NativeBindingChecks.requireMatch(actual, actual + 1, kind)
|
||||||
|
}
|
||||||
|
assertEquals(kind, failure.kind)
|
||||||
|
assertEquals("Rust bindings do not match the packaged native library", failure.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun mainThreadAndUnreadablePackagesFailWithTypedErrors() {
|
||||||
|
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||||
|
val failure = assertThrows(NativeBridgeException::class.java) {
|
||||||
|
NativeRuntime(context).fixture(MobileShellState.EMPTY)
|
||||||
|
}
|
||||||
|
assertEquals(NativeFailureKind.MainThreadCall, failure.kind)
|
||||||
|
}
|
||||||
|
val packageFile = File.createTempFile("native-corrupt-package", ".apk", context.cacheDir)
|
||||||
|
try {
|
||||||
|
val info = ApplicationInfo(context.applicationInfo).apply {
|
||||||
|
sourceDir = packageFile.absolutePath
|
||||||
|
splitSourceDirs = null
|
||||||
|
nativeLibraryDir = File(context.cacheDir, "missing-native-fixture").absolutePath
|
||||||
|
}
|
||||||
|
val invalid = object : ContextWrapper(context) {
|
||||||
|
override fun getApplicationContext() = this
|
||||||
|
override fun getApplicationInfo() = info
|
||||||
|
}
|
||||||
|
val failure = assertThrows(NativeBridgeException::class.java) {
|
||||||
|
NativeRuntime(invalid).fixture(MobileShellState.EMPTY)
|
||||||
|
}
|
||||||
|
assertEquals(NativeFailureKind.LoadFailure, failure.kind)
|
||||||
|
} finally {
|
||||||
|
packageFile.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun missingLibraryAndUnsupportedAbiFailBeforeEnteringRust() {
|
||||||
|
val abiFailure = assertThrows(NativeBridgeException::class.java) {
|
||||||
|
NativeRuntime.supportedAbi(listOf("unsupported-fixture-abi"))
|
||||||
|
}
|
||||||
|
assertEquals(NativeFailureKind.UnsupportedAbi, abiFailure.kind)
|
||||||
|
val packageFile = File.createTempFile("native-empty-package", ".apk", context.cacheDir)
|
||||||
|
try {
|
||||||
|
ZipOutputStream(packageFile.outputStream()).close()
|
||||||
|
val info = ApplicationInfo(context.applicationInfo).apply {
|
||||||
|
sourceDir = packageFile.absolutePath
|
||||||
|
splitSourceDirs = null
|
||||||
|
nativeLibraryDir = File(context.cacheDir, "missing-native-fixture").absolutePath
|
||||||
|
}
|
||||||
|
val missing = object : ContextWrapper(context) {
|
||||||
|
override fun getApplicationContext() = this
|
||||||
|
override fun getApplicationInfo() = info
|
||||||
|
}
|
||||||
|
val failure = assertThrows(NativeBridgeException::class.java) {
|
||||||
|
NativeRuntime(missing).fixture(MobileShellState.EMPTY)
|
||||||
|
}
|
||||||
|
assertEquals(NativeFailureKind.MissingLibrary, failure.kind)
|
||||||
|
} finally {
|
||||||
|
packageFile.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package de.rfc1437.ironstorage.bridge
|
||||||
|
|
||||||
|
internal object NativeBindingChecks {
|
||||||
|
fun requireMatch(actual: Long, expected: Long, kind: NativeFailureKind) {
|
||||||
|
// UniFFI checksums are u16; JNA's Int return can include unspecified upper bits.
|
||||||
|
val value = if (kind == NativeFailureKind.ChecksumMismatch) actual and 0xffffL else actual
|
||||||
|
if (value != expected) throw NativeBindingMismatchException(kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package de.rfc1437.ironstorage.bridge
|
||||||
|
|
||||||
|
enum class NativeFailureKind {
|
||||||
|
UnsupportedAbi,
|
||||||
|
MissingLibrary,
|
||||||
|
ContractMismatch,
|
||||||
|
ChecksumMismatch,
|
||||||
|
LoadFailure,
|
||||||
|
RustFailure,
|
||||||
|
MainThreadCall
|
||||||
|
}
|
||||||
|
|
||||||
|
class NativeBindingMismatchException(val kind: NativeFailureKind) :
|
||||||
|
LinkageError("Rust bindings do not match the packaged native library")
|
||||||
|
|
||||||
|
class NativeBridgeException(val kind: NativeFailureKind) :
|
||||||
|
Exception("Native Rust runtime unavailable: $kind")
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package de.rfc1437.ironstorage.bridge
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Looper
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileShell
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileShellState
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.mobileShellFixture
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.uniffiEnsureInitialized
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.concurrent.CancellationException
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
|
||||||
|
/** OS library loading only. Callers schedule all native calls off the main thread. */
|
||||||
|
class NativeRuntime(context: Context) {
|
||||||
|
private val applicationInfo = context.applicationContext.applicationInfo
|
||||||
|
private val lock = Any()
|
||||||
|
private var initialized = false
|
||||||
|
private var initializationFailure: NativeFailureKind? = null
|
||||||
|
|
||||||
|
fun fixture(state: MobileShellState): MobileShell = call {
|
||||||
|
initialize()
|
||||||
|
mobileShellFixture(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initialize() = synchronized(lock) {
|
||||||
|
initializationFailure?.let { throw NativeBridgeException(it) }
|
||||||
|
if (!initialized) {
|
||||||
|
val abi = supportedAbi(Build.SUPPORTED_ABIS.toList())
|
||||||
|
val extracted = File(applicationInfo.nativeLibraryDir, LIBRARY_FILE).isFile
|
||||||
|
val packages =
|
||||||
|
listOf(applicationInfo.sourceDir) + applicationInfo.splitSourceDirs.orEmpty()
|
||||||
|
val packaged = extracted || packages.any { path ->
|
||||||
|
ZipFile(path).use { it.getEntry("lib/$abi/$LIBRARY_FILE") != null }
|
||||||
|
}
|
||||||
|
if (!packaged) throw NativeBridgeException(NativeFailureKind.MissingLibrary)
|
||||||
|
System.loadLibrary(LIBRARY)
|
||||||
|
uniffiEnsureInitialized()
|
||||||
|
initialized = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> call(operation: () -> T): T {
|
||||||
|
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||||
|
throw NativeBridgeException(NativeFailureKind.MainThreadCall)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return operation()
|
||||||
|
} catch (error: NativeBridgeException) {
|
||||||
|
fail(error.kind)
|
||||||
|
} catch (error: CancellationException) {
|
||||||
|
throw error
|
||||||
|
} catch (error: NativeBindingMismatchException) {
|
||||||
|
fail(error.kind)
|
||||||
|
} catch (_: IOException) {
|
||||||
|
fail(NativeFailureKind.LoadFailure)
|
||||||
|
} catch (_: LinkageError) {
|
||||||
|
fail(NativeFailureKind.LoadFailure)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
fail(NativeFailureKind.RustFailure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fail(kind: NativeFailureKind): Nothing {
|
||||||
|
synchronized(lock) {
|
||||||
|
if (!initialized) initializationFailure = kind
|
||||||
|
}
|
||||||
|
throw NativeBridgeException(kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val LIBRARY = "ironstorage_android"
|
||||||
|
private const val LIBRARY_FILE = "libironstorage_android.so"
|
||||||
|
|
||||||
|
internal fun supportedAbi(deviceAbis: List<String>): String =
|
||||||
|
deviceAbis.firstOrNull { it in setOf("arm64-v8a", "armeabi-v7a", "x86_64") }
|
||||||
|
?: throw NativeBridgeException(NativeFailureKind.UnsupportedAbi)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "1.97.1"
|
||||||
|
profile = "minimal"
|
||||||
|
targets = ["aarch64-linux-android", "armv7-linux-androideabi", "x86_64-linux-android"]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[defaults.bindings.kotlin]
|
||||||
|
package_name = "de.rfc1437.ironstorage.bridge.generated"
|
||||||
|
cdylib_name = "ironstorage_android"
|
||||||
|
android = true
|
||||||
|
generate_immutable_records = true
|
||||||
|
omit_checksums = false
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "ironstorage-android"
|
||||||
|
description = "Android native library reusing the shared mobile UniFFI exports"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "ironstorage_android"
|
||||||
|
crate-type = ["lib", "cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ironstorage-apple = { path = "../apple" }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
//! Android packaging of the existing mobile UniFFI component.
|
||||||
|
//! The shared component owns every conversion; no interface is copied here.
|
||||||
|
|
||||||
|
ironstorage_apple::uniffi_reexport_scaffolding!();
|
||||||
@@ -6,6 +6,12 @@
|
|||||||
//! Credential Manager, and Secret Service boundaries. Operations are serialized
|
//! Credential Manager, and Secret Service boundaries. Operations are serialized
|
||||||
//! by the parent `SecretStore`, as required by the Windows adapter contract.
|
//! by the parent `SecretStore`, as required by the Windows adapter contract.
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "ios",
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "macos",
|
||||||
|
target_os = "windows"
|
||||||
|
))]
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||||
@@ -29,7 +35,14 @@ use security_framework::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use keyring_core::{CredentialStore, Entry};
|
#[cfg(any(
|
||||||
|
target_os = "ios",
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "macos",
|
||||||
|
target_os = "windows"
|
||||||
|
))]
|
||||||
|
use keyring_core::CredentialStore;
|
||||||
|
use keyring_core::Entry;
|
||||||
|
|
||||||
use super::{SecretLocator, SecretProtection, SecretStoreBackend, SecretStoreError};
|
use super::{SecretLocator, SecretProtection, SecretStoreBackend, SecretStoreError};
|
||||||
use crate::repository::SecretBytes;
|
use crate::repository::SecretBytes;
|
||||||
|
|||||||
@@ -205,11 +205,13 @@ Every issue runs the AGENTS.md Rust gates before commit. Android changes also
|
|||||||
run build/lint/unit/instrumented checks appropriate to the issue and computer-use
|
run build/lint/unit/instrumented checks appropriate to the issue and computer-use
|
||||||
validation on the existing emulator. Update by installation over the existing
|
validation on the existing emulator. Update by installation over the existing
|
||||||
app, never uninstall/reset. If unlocking needs an unavailable user, label the
|
app, never uninstall/reset. If unlocking needs an unavailable user, label the
|
||||||
issue untested and document exactly what could not be checked. Emulator evidence
|
issue untested and document exactly what could not be checked. The user clarified on 2026-10-08 that validation for every milestone issue is
|
||||||
cannot satisfy physical biometric/camera/Keystore/autofill or Play acceptance.
|
emulator-only; no physical devices are included in testing. Record emulator/API
|
||||||
|
limitations explicitly and use untested for an unavailable required emulator
|
||||||
|
check. This does not change production security behavior or claim Play approval.
|
||||||
Apple changes require XcodeGen and affected simulator builds and UI checks;
|
Apple changes require XcodeGen and affected simulator builds and UI checks;
|
||||||
never re-enroll an already enrolled iPhone simulator in ordinary validation.
|
never re-enroll an already enrolled iPhone simulator in ordinary validation.
|
||||||
|
|
||||||
#94 owns reproducible CI and test boundaries, #105 accessibility/performance,
|
#94 owns reproducible CI and test boundaries, #105 accessibility/performance,
|
||||||
#111 the complete architecture/security/parity audit, and #112 physical production
|
#111 the complete architecture/security/parity audit, and #112 emulator
|
||||||
install/update/Play release evidence. No release approval is implied by this ADR.
|
install/update evidence and Play release preparation. No release approval is implied by this ADR.
|
||||||
@@ -81,8 +81,8 @@ milestone. This list gives ownership, not permission to skip acceptance criteria
|
|||||||
| [#108 Move/copy/delete](https://git.rfc1437.de/hugo/IronStorage/issues/108) | storage mobile_mutation/mutation plus Compose features | Rust plans/tokens/overwrite/reencryption, destination and confirmation UI |
|
| [#108 Move/copy/delete](https://git.rfc1437.de/hugo/IronStorage/issues/108) | storage mobile_mutation/mutation plus Compose features | Rust plans/tokens/overwrite/reencryption, destination and confirmation UI |
|
||||||
| [#109 Credential Manager/Autofill](https://git.rfc1437.de/hugo/IronStorage/issues/109) | storage identity/permission/credential contract plus OS services | AndroidX provider and framework AutofillService, explicit selection/lease before secrets |
|
| [#109 Credential Manager/Autofill](https://git.rfc1437.de/hugo/IronStorage/issues/109) | storage identity/permission/credential contract plus OS services | AndroidX provider and framework AutofillService, explicit selection/lease before secrets |
|
||||||
| [#110 TOTP catalog/discovery/search](https://git.rfc1437.de/hugo/IronStorage/issues/110) | storage mobile_totp plus Compose features | Existing hash/path/is_totp catalog, Rust progress/checkpoints/filter, no Watch |
|
| [#110 TOTP catalog/discovery/search](https://git.rfc1437.de/hugo/IronStorage/issues/110) | storage mobile_totp plus Compose features | Existing hash/path/is_totp catalog, Rust progress/checkpoints/filter, no Watch |
|
||||||
| [#111 Parity/security/reliability audit](https://git.rfc1437.de/hugo/IronStorage/issues/111) | All above plus independent acceptance review | Completed matrix evidence, Rust/Android release gates and physical-device threat tests |
|
| [#111 Parity/security/reliability audit](https://git.rfc1437.de/hugo/IronStorage/issues/111) | All above plus independent acceptance review | Completed matrix evidence, Rust/Android release gates and emulator threat tests |
|
||||||
| [#112 Google Play distribution](https://git.rfc1437.de/hugo/IronStorage/issues/112) | Release tooling/listing and production app | Protected signing/Play AAB, audited manifest/licenses, physical clean install and update-preservation tests |
|
| [#112 Google Play distribution](https://git.rfc1437.de/hugo/IronStorage/issues/112) | Release tooling/listing and production app | Protected signing/Play AAB, audited manifest/licenses, emulator install and update-preservation tests |
|
||||||
|
|
||||||
#87 is the closed umbrella issue, not an open implementation candidate. Verify
|
#87 is the closed umbrella issue, not an open implementation candidate. Verify
|
||||||
live issues after each closure; newly created bug/critical issues may change the
|
live issues after each closure; newly created bug/critical issues may change the
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ironstorage-android-build"
|
name = "ironstorage-android-build"
|
||||||
description = "Android fixture generation and architecture boundary checks"
|
description = "Android native packaging, binding generation and architecture gates"
|
||||||
|
default-run = "ironstorage-android-build"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
@@ -11,3 +12,10 @@ publish = false
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
ironstorage.workspace = true
|
ironstorage.workspace = true
|
||||||
regex.workspace = true
|
regex.workspace = true
|
||||||
|
uniffi = { workspace = true, features = ["cli"] }
|
||||||
|
object = { version = "0.36.7", default-features = false, features = ["read", "elf"] }
|
||||||
|
zip = { version = "2.4.2", default-features = false, features = ["deflate"] }
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "ironstorage-uniffi-bindgen"
|
||||||
|
path = "src/bindgen.rs"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
uniffi::uniffi_bindgen_main();
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
//! Narrow, version-checked hardening of UniFFI 0.32's Kotlin diagnostics.
|
||||||
|
//! Records remain immutable data classes with unchanged wire layouts/checksums.
|
||||||
|
|
||||||
|
use std::{error::Error, fs, path::Path};
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
pub fn prepare(input: &Path, output: &Path) -> Result<(), Box<dyn Error>> {
|
||||||
|
if !input.is_dir() || input.is_symlink() || output.is_symlink() {
|
||||||
|
return Err("binding input and output must be distinct directories".into());
|
||||||
|
}
|
||||||
|
let input = input.canonicalize()?;
|
||||||
|
let destination = if output.exists() {
|
||||||
|
output.canonicalize()?
|
||||||
|
} else {
|
||||||
|
output
|
||||||
|
.parent()
|
||||||
|
.ok_or("output needs a parent")?
|
||||||
|
.canonicalize()?
|
||||||
|
.join(output.file_name().ok_or("output needs a name")?)
|
||||||
|
};
|
||||||
|
if input.starts_with(&destination) || destination.starts_with(&input) {
|
||||||
|
return Err("binding input/output directories must not overlap".into());
|
||||||
|
}
|
||||||
|
if output.exists() {
|
||||||
|
fs::remove_dir_all(output)?;
|
||||||
|
}
|
||||||
|
copy(&input, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy(input: &Path, output: &Path) -> Result<(), Box<dyn Error>> {
|
||||||
|
fs::create_dir_all(output)?;
|
||||||
|
let mut found = false;
|
||||||
|
for entry in fs::read_dir(input)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let destination = output.join(entry.file_name());
|
||||||
|
if entry.file_type()?.is_dir() {
|
||||||
|
copy(&entry.path(), &destination)?;
|
||||||
|
found = true;
|
||||||
|
} else if entry.file_type()?.is_file()
|
||||||
|
&& entry.path().extension().is_some_and(|ext| ext == "kt")
|
||||||
|
{
|
||||||
|
let source = fs::read_to_string(entry.path())?;
|
||||||
|
fs::write(destination, harden_source(&source)?)?;
|
||||||
|
found = true;
|
||||||
|
} else {
|
||||||
|
return Err("unexpected file in generated Kotlin bindings".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return Err("UniFFI produced no Kotlin bindings".into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn harden_source(source: &str) -> Result<String, Box<dyn Error>> {
|
||||||
|
let internal = "class InternalException(message: String) : kotlin.Exception(message)";
|
||||||
|
let callback = "val err = try { e.stackTraceToString() } catch(_: Throwable) { \"\" }";
|
||||||
|
if !source.contains(internal) || source.matches(callback).count() != 2 {
|
||||||
|
return Err("UniFFI unexpected-error template changed; review secret redaction".into());
|
||||||
|
}
|
||||||
|
let source = source.replace(internal, "class InternalException(@Suppress(\"UNUSED_PARAMETER\") message: String) : kotlin.Exception(\"Native Rust failure ([REDACTED])\")")
|
||||||
|
.replace(callback, "val err = \"Native callback failed ([REDACTED])\"");
|
||||||
|
let records = Regex::new(r"(?ms)^data class (\w+) \((.*?)\n\)([^\{]*)\{\n")?;
|
||||||
|
if !records.is_match(&source) {
|
||||||
|
return Err("UniFFI record template changed; review diagnostic hardening".into());
|
||||||
|
}
|
||||||
|
let source = records.replace_all(&source, |captures: ®ex::Captures<'_>| {
|
||||||
|
format!(
|
||||||
|
"{} override fun toString(): String = \"{}([REDACTED])\"\n",
|
||||||
|
&captures[0], &captures[1]
|
||||||
|
)
|
||||||
|
});
|
||||||
|
let errors = Regex::new(r#"(?m)(override val message\n\s*)get\(\) = ".*"$"#)?;
|
||||||
|
// Kotlin Exception.message is reserved; keep the Rust field/wire checksum unchanged.
|
||||||
|
let source = source
|
||||||
|
.replace(
|
||||||
|
"val `message`: kotlin.String",
|
||||||
|
"val `rustMessage`: kotlin.String",
|
||||||
|
)
|
||||||
|
.replace("value.`message`", "value.`rustMessage`");
|
||||||
|
let source = errors.replace_all(
|
||||||
|
&source,
|
||||||
|
"${1}get() = \"Rust operation failed ([REDACTED])\"",
|
||||||
|
);
|
||||||
|
let contract = "throw RuntimeException(\"UniFFI contract version mismatch: try cleaning and rebuilding your project\")";
|
||||||
|
let checksum = "throw RuntimeException(\"UniFFI API checksum mismatch: try cleaning and rebuilding your project\")";
|
||||||
|
if !source.contains(contract) || !source.contains(checksum) {
|
||||||
|
return Err(
|
||||||
|
"UniFFI integrity template changed; checksum checks must remain enabled".into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let checksum_guard = Regex::new(
|
||||||
|
r#"if \(lib\.(\w+)\(\) != (-?\d+)\) \{\s*throw RuntimeException\("UniFFI API checksum mismatch: try cleaning and rebuilding your project"\)\s*\}"#,
|
||||||
|
)?;
|
||||||
|
let contract_guard = Regex::new(
|
||||||
|
r#"if \(bindings_contract_version != scaffolding_contract_version\) \{\s*throw RuntimeException\("UniFFI contract version mismatch: try cleaning and rebuilding your project"\)\s*\}"#,
|
||||||
|
)?;
|
||||||
|
if !checksum_guard.is_match(&source) || !contract_guard.is_match(&source) {
|
||||||
|
return Err(
|
||||||
|
"UniFFI integrity guard changed; refusing to generate unchecked bindings".into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let output = checksum_guard.replace_all(&source, "de.rfc1437.ironstorage.bridge.NativeBindingChecks.requireMatch(lib.${1}().toLong(), ${2}.toLong(), de.rfc1437.ironstorage.bridge.NativeFailureKind.ChecksumMismatch)");
|
||||||
|
let output = contract_guard.replace_all(&output, "de.rfc1437.ironstorage.bridge.NativeBindingChecks.requireMatch(scaffolding_contract_version.toLong(), bindings_contract_version.toLong(), de.rfc1437.ironstorage.bridge.NativeFailureKind.ContractMismatch)").into_owned();
|
||||||
|
if output.contains(contract) || output.contains(checksum) {
|
||||||
|
return Err("UniFFI integrity guard was not translated completely".into());
|
||||||
|
}
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SOURCE: &str = "data class Secret (\n val value: String\n)\n{\n companion object\n}\nclass Failure {\n override val message\n get() = \"value=${value}\"\n}\nif (bindings_contract_version != scaffolding_contract_version) { throw RuntimeException(\"UniFFI contract version mismatch: try cleaning and rebuilding your project\") }\nif (lib.checksum() != 1234) { throw RuntimeException(\"UniFFI API checksum mismatch: try cleaning and rebuilding your project\") }\nclass InternalException(message: String) : kotlin.Exception(message)\nval err = try { e.stackTraceToString() } catch(_: Throwable) { \"\" }\nval err = try { e.stackTraceToString() } catch(_: Throwable) { \"\" }\n";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn redacts_record_and_error_diagnostics_without_changing_fields_or_checksums() {
|
||||||
|
let hardened = harden_source(SOURCE).unwrap();
|
||||||
|
assert!(hardened.contains("val value: String"));
|
||||||
|
assert!(hardened.contains("Secret([REDACTED])"));
|
||||||
|
assert!(!hardened.contains("get() = \"value="));
|
||||||
|
assert!(hardened.contains("requireMatch(lib.checksum().toLong(), 1234.toLong()"));
|
||||||
|
assert!(hardened.contains("NativeFailureKind.ChecksumMismatch"));
|
||||||
|
assert!(hardened.contains("NativeFailureKind.ContractMismatch"));
|
||||||
|
assert!(!hardened.contains("stackTraceToString"));
|
||||||
|
assert!(!hardened.contains("kotlin.Exception(message)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fails_closed_if_upstream_templates_or_integrity_checks_change() {
|
||||||
|
assert!(harden_source("data class Secret(val value: String)").is_err());
|
||||||
|
assert!(harden_source(&SOURCE.replace("UniFFI API checksum mismatch", "changed")).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preserves_rust_message_fields_without_colliding_with_kotlin_exception_message() {
|
||||||
|
let source = SOURCE.replace("val value: String", "val `message`: kotlin.String")
|
||||||
|
+ "FfiConverterString.write(value.`message`, buf)";
|
||||||
|
let hardened = harden_source(&source).unwrap();
|
||||||
|
assert!(hardened.contains("val `rustMessage`: kotlin.String"));
|
||||||
|
assert!(hardened.contains("FfiConverterString.write(value.`rustMessage`, buf)"));
|
||||||
|
assert!(hardened.contains("override val message"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,10 @@
|
|||||||
use ironstorage::mobile::{MobileShell, MobileShellState};
|
use ironstorage::mobile::{MobileShell, MobileShellState};
|
||||||
use std::{env, error::Error, fs, path::Path};
|
use std::{env, error::Error, fs, path::Path};
|
||||||
|
|
||||||
|
mod bindings;
|
||||||
|
mod native;
|
||||||
|
mod toolchain;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let args: Vec<_> = env::args_os().collect();
|
let args: Vec<_> = env::args_os().collect();
|
||||||
match args.as_slice() {
|
match args.as_slice() {
|
||||||
@@ -12,9 +16,38 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
fs::write(path, fixtures())?;
|
fs::write(path, fixtures())?;
|
||||||
}
|
}
|
||||||
[_, command, path] if command == "check" => check(Path::new(path))?,
|
[_, command, path] if command == "check" => check(Path::new(path))?,
|
||||||
|
[_, command, input, output] if command == "prepare-bindings" => {
|
||||||
|
bindings::prepare(Path::new(input), Path::new(output))?;
|
||||||
|
}
|
||||||
|
[_, command, input, output] if command == "package-native" => {
|
||||||
|
native::package_directory(Path::new(input), Path::new(output))?;
|
||||||
|
}
|
||||||
|
[_, command, path, abi] if command == "audit-elf" => {
|
||||||
|
native::audit_elf(&fs::read(path)?, abi.to_str().ok_or("invalid ABI")?)?;
|
||||||
|
}
|
||||||
|
[_, command, path, abi] if command == "audit-apk-split" => {
|
||||||
|
native::audit_split(Path::new(path), abi.to_str().ok_or("invalid ABI")?)?;
|
||||||
|
}
|
||||||
|
[_, command, paths @ ..] if command == "audit-package" && !paths.is_empty() => {
|
||||||
|
for path in paths {
|
||||||
|
native::audit_package(Path::new(path))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[_, command, directory] if command == "audit-native" => {
|
||||||
|
native::audit_directory(Path::new(directory))?
|
||||||
|
}
|
||||||
|
[_, command, cargo, rust, ndk, ndk_version, cargo_ndk] if command == "check-toolchain" => {
|
||||||
|
toolchain::check(
|
||||||
|
Path::new(cargo),
|
||||||
|
rust.to_str().ok_or("invalid Rust version")?,
|
||||||
|
Path::new(ndk),
|
||||||
|
ndk_version.to_str().ok_or("invalid NDK version")?,
|
||||||
|
cargo_ndk.to_str().ok_or("invalid cargo-ndk version")?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(
|
return Err(
|
||||||
"usage: ironstorage-android-build <fixtures output.kt | check android-dir>".into(),
|
"usage: ironstorage-android-build <fixtures output.kt | check android-dir | prepare-bindings input output | package-native input output | audit-elf path abi | audit-native jniLibs | audit-apk-split apk abi | audit-package apk-or-aab | check-toolchain cargo rust ndk ndk-version cargo-ndk-version>".into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
//! Verify every packaged native library, including JNA, against the ABI/page contract.
|
||||||
|
|
||||||
|
use std::{collections::BTreeMap, error::Error, fs::File, io::Read, path::Path};
|
||||||
|
|
||||||
|
use object::{Architecture, BinaryFormat, Object, ObjectSection, ObjectSegment, ObjectSymbol};
|
||||||
|
|
||||||
|
const PAGE_SIZE: u64 = 16_384;
|
||||||
|
const ABIS: [&str; 3] = ["arm64-v8a", "armeabi-v7a", "x86_64"];
|
||||||
|
|
||||||
|
pub fn package_directory(input: &Path, output: &Path) -> Result<(), Box<dyn Error>> {
|
||||||
|
audit_directory(input)?;
|
||||||
|
let input = input.canonicalize()?;
|
||||||
|
let output = if output.exists() {
|
||||||
|
if output.is_symlink() {
|
||||||
|
return Err("native output must not be a symlink".into());
|
||||||
|
}
|
||||||
|
output.canonicalize()?
|
||||||
|
} else {
|
||||||
|
output
|
||||||
|
.parent()
|
||||||
|
.ok_or("output needs a parent")?
|
||||||
|
.canonicalize()?
|
||||||
|
.join(output.file_name().ok_or("output needs a name")?)
|
||||||
|
};
|
||||||
|
if input.starts_with(&output) || output.starts_with(&input) {
|
||||||
|
return Err("native input/output must not overlap".into());
|
||||||
|
}
|
||||||
|
if output.exists() {
|
||||||
|
std::fs::remove_dir_all(&output)?;
|
||||||
|
}
|
||||||
|
for abi in ABIS {
|
||||||
|
std::fs::create_dir_all(output.join(abi))?;
|
||||||
|
// cargo-ndk also emits dependency cdylibs; ship only the Android boundary.
|
||||||
|
std::fs::copy(
|
||||||
|
input.join(abi).join("libironstorage_android.so"),
|
||||||
|
output.join(abi).join("libironstorage_android.so"),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn audit_directory(directory: &Path) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut expected = None;
|
||||||
|
for abi in ABIS {
|
||||||
|
let bytes = std::fs::read(directory.join(abi).join("libironstorage_android.so"))?;
|
||||||
|
audit_elf(&bytes, abi)?;
|
||||||
|
let library = object::File::parse(bytes.as_slice())?;
|
||||||
|
let mut metadata = BTreeMap::new();
|
||||||
|
for symbol in library.symbols() {
|
||||||
|
let name = symbol.name()?;
|
||||||
|
if name.starts_with("UNIFFI_META_") {
|
||||||
|
let section = library.section_by_index(
|
||||||
|
symbol
|
||||||
|
.section_index()
|
||||||
|
.ok_or("UniFFI metadata has no section")?,
|
||||||
|
)?;
|
||||||
|
let value = section
|
||||||
|
.data_range(symbol.address(), symbol.size())?
|
||||||
|
.ok_or("UniFFI metadata is outside its section")?;
|
||||||
|
metadata.insert(name.to_owned(), value.to_vec());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if metadata.is_empty() {
|
||||||
|
return Err("native library has no UniFFI metadata".into());
|
||||||
|
}
|
||||||
|
if let Some(expected) = &expected {
|
||||||
|
if expected != &metadata {
|
||||||
|
return Err("UniFFI metadata differs across Android ABIs".into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expected = Some(metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Verified three native ABIs, 16 KB ELF alignment and identical UniFFI metadata");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn audit_elf(bytes: &[u8], abi: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
let expected = match abi {
|
||||||
|
"arm64-v8a" => Architecture::Aarch64,
|
||||||
|
"armeabi-v7a" => Architecture::Arm,
|
||||||
|
"x86_64" => Architecture::X86_64,
|
||||||
|
_ => return Err("unapproved native ABI".into()),
|
||||||
|
};
|
||||||
|
let library = object::File::parse(bytes)?;
|
||||||
|
if library.format() != BinaryFormat::Elf || library.architecture() != expected {
|
||||||
|
return Err("native library architecture does not match its ABI directory".into());
|
||||||
|
}
|
||||||
|
let mut segments = 0;
|
||||||
|
for segment in library.segments() {
|
||||||
|
let (offset, _) = segment.file_range();
|
||||||
|
if segment.align() < PAGE_SIZE || segment.address() % PAGE_SIZE != offset % PAGE_SIZE {
|
||||||
|
return Err("native ELF LOAD segment is not compatible with 16 KB pages".into());
|
||||||
|
}
|
||||||
|
segments += 1;
|
||||||
|
}
|
||||||
|
if segments == 0 {
|
||||||
|
return Err("native ELF has no loadable segments".into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn audit_package(path: &Path) -> Result<(), Box<dyn Error>> {
|
||||||
|
audit_package_abis(path, &ABIS)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn audit_split(path: &Path, abi: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
if !ABIS.contains(&abi) || !path.extension().is_some_and(|ext| ext == "apk") {
|
||||||
|
return Err("expected an APK split for an approved ABI".into());
|
||||||
|
}
|
||||||
|
audit_package_abis(path, &[abi])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn audit_package_abis(path: &Path, abis: &[&str]) -> Result<(), Box<dyn Error>> {
|
||||||
|
let apk = path.extension().is_some_and(|ext| ext == "apk");
|
||||||
|
if !apk && !path.extension().is_some_and(|ext| ext == "aab") {
|
||||||
|
return Err("expected an APK or AAB".into());
|
||||||
|
}
|
||||||
|
let mut archive = zip::ZipArchive::new(File::open(path)?)?;
|
||||||
|
let mut libraries = BTreeMap::<String, Vec<String>>::new();
|
||||||
|
for index in 0..archive.len() {
|
||||||
|
let mut file = archive.by_index(index)?;
|
||||||
|
let name = file.name().to_owned();
|
||||||
|
let native = name.strip_prefix(if apk { "lib/" } else { "base/lib/" });
|
||||||
|
let Some((abi, library)) = native.and_then(|name| name.split_once('/')) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if !library.ends_with(".so") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if library == "libironstorage_apple.so" {
|
||||||
|
return Err("Android package includes the redundant Apple boundary library".into());
|
||||||
|
}
|
||||||
|
if !abis.contains(&abi) || library.contains('/') {
|
||||||
|
return Err("package contains an unapproved native library path".into());
|
||||||
|
}
|
||||||
|
if apk
|
||||||
|
&& (file.compression() != zip::CompressionMethod::Stored
|
||||||
|
|| file.data_start() % PAGE_SIZE != 0)
|
||||||
|
{
|
||||||
|
return Err(format!("{name}: APK native entry is not stored/aligned to 16 KB").into());
|
||||||
|
}
|
||||||
|
if file.size() > 512 * 1024 * 1024 {
|
||||||
|
return Err("native library exceeds the package audit bound".into());
|
||||||
|
}
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
file.read_to_end(&mut bytes)?;
|
||||||
|
audit_elf(&bytes, abi).map_err(|error| format!("{name}: {error}"))?;
|
||||||
|
libraries
|
||||||
|
.entry(abi.to_owned())
|
||||||
|
.or_default()
|
||||||
|
.push(library.to_owned());
|
||||||
|
}
|
||||||
|
for abi in abis {
|
||||||
|
let found = libraries
|
||||||
|
.get(*abi)
|
||||||
|
.ok_or("package is missing a supported ABI")?;
|
||||||
|
for required in ["libironstorage_android.so", "libjnidispatch.so"] {
|
||||||
|
if !found.iter().any(|name| name == required) {
|
||||||
|
return Err(format!("{abi}: missing {required}").into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"Verified all packaged native libraries for {abis:?} in {}",
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn elf(alignment: u64, address: u64) -> Vec<u8> {
|
||||||
|
let mut bytes = vec![0; 120];
|
||||||
|
bytes[..7].copy_from_slice(b"\x7fELF\x02\x01\x01");
|
||||||
|
bytes[16..18].copy_from_slice(&3_u16.to_le_bytes());
|
||||||
|
bytes[18..20].copy_from_slice(&183_u16.to_le_bytes());
|
||||||
|
bytes[20..24].copy_from_slice(&1_u32.to_le_bytes());
|
||||||
|
bytes[32..40].copy_from_slice(&64_u64.to_le_bytes());
|
||||||
|
bytes[52..54].copy_from_slice(&64_u16.to_le_bytes());
|
||||||
|
bytes[54..56].copy_from_slice(&56_u16.to_le_bytes());
|
||||||
|
bytes[56..58].copy_from_slice(&1_u16.to_le_bytes());
|
||||||
|
bytes[64..68].copy_from_slice(&1_u32.to_le_bytes());
|
||||||
|
bytes[68..72].copy_from_slice(&4_u32.to_le_bytes());
|
||||||
|
bytes[80..88].copy_from_slice(&address.to_le_bytes());
|
||||||
|
bytes[96..104].copy_from_slice(&120_u64.to_le_bytes());
|
||||||
|
bytes[104..112].copy_from_slice(&120_u64.to_le_bytes());
|
||||||
|
bytes[112..120].copy_from_slice(&alignment.to_le_bytes());
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn checks_real_load_alignment_congruence_and_directory_abi() {
|
||||||
|
assert!(audit_elf(&elf(PAGE_SIZE, 0), "arm64-v8a").is_ok());
|
||||||
|
assert!(audit_elf(&elf(4096, 0), "arm64-v8a").is_err());
|
||||||
|
assert!(audit_elf(&elf(PAGE_SIZE, 4), "arm64-v8a").is_err());
|
||||||
|
assert!(audit_elf(&elf(PAGE_SIZE, 0), "x86_64").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_non_elf_unapproved_abi_and_truncated_headers() {
|
||||||
|
assert!(audit_elf(b"not an ELF", "arm64-v8a").is_err());
|
||||||
|
assert!(audit_elf(b"\x7fELF", "x86_64").is_err());
|
||||||
|
assert!(audit_elf(&[], "mips").is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
//! Build-time tools only; application crates never launch these processes.
|
||||||
|
#![allow(
|
||||||
|
clippy::disallowed_types,
|
||||||
|
reason = "build-only verification of Cargo/cargo-ndk, never linked into the application"
|
||||||
|
)]
|
||||||
|
use std::{error::Error, fs, path::Path, process::Command};
|
||||||
|
|
||||||
|
pub fn check(
|
||||||
|
cargo: &Path,
|
||||||
|
rust: &str,
|
||||||
|
ndk: &Path,
|
||||||
|
ndk_version: &str,
|
||||||
|
cargo_ndk: &str,
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
version(
|
||||||
|
cargo,
|
||||||
|
&[&format!("+{rust}"), "--version"],
|
||||||
|
&format!("cargo {rust}"),
|
||||||
|
)?;
|
||||||
|
version(
|
||||||
|
cargo,
|
||||||
|
&[&format!("+{rust}"), "ndk", "--version"],
|
||||||
|
&format!("cargo-ndk {cargo_ndk}"),
|
||||||
|
)?;
|
||||||
|
let properties = fs::read_to_string(ndk.join("source.properties"))?;
|
||||||
|
if !properties
|
||||||
|
.lines()
|
||||||
|
.any(|line| line.trim() == format!("Pkg.Revision = {ndk_version}"))
|
||||||
|
{
|
||||||
|
return Err("Android NDK revision does not match the version catalog".into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(command: &Path, args: &[&str], expected: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
let result = Command::new(command).args(args).output()?;
|
||||||
|
let value = std::str::from_utf8(&result.stdout)?;
|
||||||
|
if !result.status.success() || !matches_version(value, expected) {
|
||||||
|
return Err(format!("build tool must report {expected}").into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_version(value: &str, expected: &str) -> bool {
|
||||||
|
value
|
||||||
|
.trim()
|
||||||
|
.strip_prefix(expected)
|
||||||
|
.is_some_and(|suffix| suffix.is_empty() || suffix.starts_with(' '))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn rejects_nearby_and_failed_version_output() {
|
||||||
|
assert!(matches_version("cargo 1.97.1 (abc)\n", "cargo 1.97.1"));
|
||||||
|
assert!(matches_version("cargo-ndk 4.1.2\n", "cargo-ndk 4.1.2"));
|
||||||
|
assert!(!matches_version("cargo-ndk 4.1.20", "cargo-ndk 4.1.2"));
|
||||||
|
assert!(!matches_version("", "cargo-ndk 4.1.2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user