Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ffi: add Kotlin Multiplatform package #724

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bindings/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# rust-nostr bindings

* [nostr-sdk-ffi](./nostr-sdk-ffi): UniFFI (Python, Kotlin, Swift) bindings
* [nostr-sdk-ffi](./nostr-sdk-ffi): UniFFI (Python, Kotlin, Kotlin Multiplatform, Swift) bindings
* [nostr-sdk-js](./nostr-sdk-js): JavaScript bindings
* [nostr-sdk-flutter](https://github.com/rust-nostr/nostr-sdk-flutter): Flutter bindings
Empty file.
18 changes: 17 additions & 1 deletion bindings/nostr-sdk-ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ If you want to compile from source or need more options, read on.
just python
```

### Kotlin
### Kotlin (android)

For most users, we recommend using our official Kotlin package: [org.rust-nostr:nostr-sdk](https://central.sonatype.com/artifact/org.rust-nostr/nostr-sdk/).

Expand All @@ -39,6 +39,22 @@ just aar

See [Add your AAR or JAR as a dependency](https://developer.android.com/studio/projects/android-library#psd-add-aar-jar-dependency) in Android's docs for more information on how to integrate such an archive into your project.

### Kotlin Multiplatform

For most users, we recommend using our official Kotlin package: [org.rust-nostr:nostr-sdk-kmp](https://central.sonatype.com/artifact/org.rust-nostr/nostr-sdk-kmp/).

If you want to compile from source or need more options, read on.

#### Build

```bash
just build
```

```bash
just kmp
```

### Swift

For most users, we recommend using our official Swift package: [rust-nostr/nostr-sdk-swift](https://github.com/rust-nostr/nostr-sdk-swift).
Expand Down
52 changes: 2 additions & 50 deletions bindings/nostr-sdk-ffi/android/build-aar.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

set -exuo pipefail

CDYLIB="libnostr_sdk_ffi.so"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TARGET_DIR="${SCRIPT_DIR}/../../../target"
ANDROID_MAIN_DIR="${SCRIPT_DIR}/lib/src/main"
ANDROID_MAIN_KOTLIN_DIR="${ANDROID_MAIN_DIR}/kotlin"
ANDROID_MAIN_JNI_LIBS_DIR="${ANDROID_MAIN_DIR}/jniLibs"
Expand All @@ -13,58 +11,12 @@ FFI_KOTLIN_DIR="${FFI_DIR}/kotlin"
FFI_JNI_LIBS_DIR="${FFI_KOTLIN_DIR}/jniLibs"
FFI_ANDROID_DIR="${FFI_DIR}/android"

# Check if ANDROID_NDK_HOME env is set
if [ ! -d "${ANDROID_NDK_HOME}" ] ; then \
echo "Error: Please, set the ANDROID_NDK_HOME env variable to point to your NDK folder" ; \
exit 1 ; \
fi

# Check if ANDROID_SDK_ROOT env is set
if [ ! -d "${ANDROID_SDK_ROOT}" ] ; then \
echo "Error: Please, set the ANDROID_SDK_ROOT env variable to point to your SDK folder" ; \
exit 1 ; \
fi

# Install deps
cargo ndk --version || cargo install cargo-ndk

# Clean
rm -rf "${FFI_KOTLIN_DIR}"
rm -rf "${FFI_ANDROID_DIR}"
rm -rf "${ANDROID_MAIN_KOTLIN_DIR}"
rm -rf "${ANDROID_MAIN_JNI_LIBS_DIR}"

# Install targets
rustup target add aarch64-linux-android # ARM64 (Most modern devices - ~60-75%)
rustup target add armv7-linux-androideabi # ARM32 (Older devices - ~20-30%)
rustup target add x86_64-linux-android # x86_64 (Rare, used mostly in emulators - ~1-2%)
rustup target add i686-linux-android # x86 (Legacy and rare devices - <1%)

# Build targets
cargo ndk -t aarch64-linux-android -t armv7-linux-androideabi -t x86_64-linux-android -t i686-linux-android -o "${FFI_JNI_LIBS_DIR}" build -p nostr-sdk-ffi --lib --release

# Generate Kotlin bindings
cargo run -p nostr-sdk-ffi --features uniffi-cli --bin uniffi-bindgen generate --library "${TARGET_DIR}/aarch64-linux-android/release/${CDYLIB}" --language kotlin --no-format -o "${FFI_KOTLIN_DIR}"

# Compress libraries (only ARM and x86_64 libraries)
#
# NOTE: `--lzma` caused issues on x86/x86_64 architectures: https://github.com/rust-nostr/nostr/issues/703
#
# The UPX compression is known to cause issues on `x86` devices for certain Android API levels (e.g., API 30).
# Since `x86` devices constitute a very small percentage of the Android market (<1%, see links below),
# apps are unlikely to be shipped for this architecture and are typically used only for testing purposes.
# Therefore, compress only the ARM (`arm64-v8a` and `armeabi-v7a`) and `x86_64` libraries.
#
# Issues:
# * https://github.com/rust-nostr/nostr/issues/703
# * https://github.com/upx/upx/issues/700
# * https://github.com/upx/upx/issues/710
#
# Market stats:
# * https://android.stackexchange.com/questions/186334/what-percentage-of-android-devices-runs-on-x86-architecture
# * https://web.archive.org/web/20170808222202/http://hwstats.unity3d.com:80/mobile/cpu-android.html
#
upx --best --android-shlib "${FFI_JNI_LIBS_DIR}/arm64-v8a/${CDYLIB}" "${FFI_JNI_LIBS_DIR}/armeabi-v7a/${CDYLIB}" "${FFI_JNI_LIBS_DIR}/x86_64/${CDYLIB}"
# Build android binaries and generate foreign language
"${SCRIPT_DIR}/../scripts/android.sh"

# Assemble AAR
mkdir -p "${ANDROID_MAIN_KOTLIN_DIR}"
Expand Down
17 changes: 17 additions & 0 deletions bindings/nostr-sdk-ffi/justfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]

[private]
default:
@just --list

bloat:
cargo bloat --release -n 1000

# Build all binaries
build:
@cd scripts && bash build-all.sh

# Compile and build Android Archive (AAR)
aar:
@cd android && bash build-aar.sh

# Assemble the Kotlin Multiplatform package
kmp:
@cd kmp && bash assemble.sh

# Publish android bindings
[confirm]
publish-android: aar
cd android && ./gradlew publishAndReleaseToMavenCentral --no-configuration-cache

# Publish KMP bindings
[confirm]
publish-kmp: aar
cd kmp && ./gradlew publishAndReleaseToMavenCentral --no-configuration-cache

# Compile and build Swift Package
swift:
@cd swift && bash build-xcframework.sh
Expand Down
54 changes: 54 additions & 0 deletions bindings/nostr-sdk-ffi/kmp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Created by https://www.toptal.com/developers/gitignore/api/android
# Edit at https://www.toptal.com/developers/gitignore?templates=android

### Android ###
# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Log/OS Files
*.log

# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json

# IntelliJ
*.iml
.idea/
misc.xml
deploymentTargetDropDown.xml
render.experimental.xml

# Keystore files
*.jks
*.keystore

# Google Services (e.g. APIs or Firebase)
google-services.json

# Android Profiling
*.hprof

### Android Patch ###
gen-external-apklibs

# Replacement of .externalNativeBuild directories introduced
# with Android Studio 3.5.

# End of https://www.toptal.com/developers/gitignore/api/android

.kotlin/

nostr-sdk-kmp/src/androidMain/
nostr-sdk-kmp/src/commonMain/
nostr-sdk-kmp/src/jvmMain/
nostr-sdk-kmp/src/libs/
nostr-sdk-kmp/src/nativeInterop/cinterop/headers/
nostr-sdk-kmp/src/nativeMain/
53 changes: 53 additions & 0 deletions bindings/nostr-sdk-ffi/kmp/assemble.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/bin/bash

set -exuo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
KMP_SRC="${SCRIPT_DIR}/nostr-sdk-kmp/src"
FFI_DIR="${SCRIPT_DIR}/../ffi"
TARGET_DIR="${SCRIPT_DIR}/../../../target"

# Clean
rm -rf "${FFI_DIR}/kmp"
rm -rf "${KMP_SRC}/androidMain/"
rm -rf "${KMP_SRC}/commonMain/"
rm -rf "${KMP_SRC}/jvmMain/"
rm -rf "${KMP_SRC}/libs/"
rm -rf "${KMP_SRC}/nativeInterop/cinterop/headers/"
rm -rf "${KMP_SRC}/nativeMain/"

# Install deps
cargo install --git https://gitlab.com/trixnity/uniffi-kotlin-multiplatform-bindings --rev 593453540e2d52c922cdbdc58d3db14f7b5961a9

# Generate foreign languages
uniffi-bindgen-kotlin-multiplatform --library "${TARGET_DIR}/aarch64-linux-android/release/libnostr_sdk_ffi.so" -o "${FFI_DIR}/kmp" --config "${SCRIPT_DIR}/../uniffi-kmp.toml"

# Copy android libraries
mkdir -p "${KMP_SRC}/androidMain/"
cp -r "${FFI_DIR}/kotlin/jniLibs" "${KMP_SRC}/androidMain/jniLibs"

# Copy Kotlin Multiplatform stuff
cp -r "${FFI_DIR}/kmp/commonMain" "${KMP_SRC}"
cp -r "${FFI_DIR}/kmp/jvmMain" "${KMP_SRC}"
cp -r "${FFI_DIR}/kmp/nativeInterop" "${KMP_SRC}"
cp -r "${FFI_DIR}/kmp/nativeMain" "${KMP_SRC}"

cp -r "${KMP_SRC}/jvmMain/kotlin" "${KMP_SRC}/androidMain/"

# Copy apple binaries
mkdir -p "${KMP_SRC}/libs/macos-x64/"
mkdir -p "${KMP_SRC}/libs/macos-arm64/"
cp "${FFI_DIR}/apple/macos/x86_64/libnostr_sdk_ffi.dylib" "${KMP_SRC}/libs/macos-x64/"
cp "${FFI_DIR}/apple/macos/aarch64/libnostr_sdk_ffi.dylib" "${KMP_SRC}/libs/macos-arm64/"

# Copy linux binaries
mkdir -p "${KMP_SRC}/libs/linux-x64/"
mkdir -p "${KMP_SRC}/libs/linux-arm64/"
cp "${FFI_DIR}/linux/x86_64/libnostr_sdk_ffi.so" "${KMP_SRC}/libs/linux-x64/"
cp "${FFI_DIR}/linux/aarch64/libnostr_sdk_ffi.so" "${KMP_SRC}/libs/linux-arm64/"

# Copy windows binaries
mkdir -p "${KMP_SRC}/libs/mingw-x64/"
cp "${FFI_DIR}/win/x86_64/nostr_sdk_ffi.dll" "${KMP_SRC}/libs/mingw-x64/"

"${SCRIPT_DIR}/gradlew" :nostr-sdk-kmp:assemble
11 changes: 11 additions & 0 deletions bindings/nostr-sdk-ffi/kmp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath(libs.gradle)
classpath(libs.kotlin.gradle.plugin)
classpath(libs.atomicfu.gradle.plugin)
}
}
22 changes: 22 additions & 0 deletions bindings/nostr-sdk-ffi/kmp/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#Gradle
org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"

#Kotlin
kotlin.code.style=official

#Android
android.useAndroidX=true
android.nonTransitiveRClass=true

#Atomicfu
# for JVM IR transformation
kotlinx.atomicfu.enableJvmIrTransformation=true
# for Native IR transformation
kotlinx.atomicfu.enableNativeIrTransformation=true

#MPP
kotlin.mpp.enableCInteropCommonization=true
kotlin.mpp.androidSourceSetLayoutVersion=2

# For apple targets cross compialtion
kotlin.native.enableKlibsCrossCompilation=true
17 changes: 17 additions & 0 deletions bindings/nostr-sdk-ffi/kmp/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[versions]
atomicfu = "0.24.0"
gradle = "8.4.2"
jna = "5.14.0"
kotlin = "1.9.24"
kotlinx-coroutines-core = "1.7.3"
kotlinx-datetime = "0.4.1"
okio = "3.9.0"

[libraries]
atomicfu-gradle-plugin = { module = "org.jetbrains.kotlinx:atomicfu-gradle-plugin", version.ref = "atomicfu" }
gradle = { module = "com.android.tools.build:gradle", version.ref = "gradle" }
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
okio = { module = "com.squareup.okio:okio", version.ref = "okio" }
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#Thu Jul 13 02:13:42 EEST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading
Loading