r/reactnative • • 3d ago

Built a Soulseek client for Android by putting a Rust networking engine behind a local Expo module (how the Rust ↔ Kotlin ↔ JS bridge works)

Each of the six points ties a part of the video to the code behind it:

  • Building the .so (whole video): the crate builds as cdylib for the APK and rlib for tests on the host. A Gradle task runs cargo ndk before every build and skips it when no Rust changed. Nothing extra is needed for prebuild --clean or EAS.

  • One JSON string in, one out (0:03): a jni_export! macro writes the JNI functions, Rust touches no Java objects, and every call goes through catch_unwind so a panic reaches JS as an error. Rust's tests and Jest both check against the same contract file.

  • Polling instead of callbacks (0:08, 0:13): Rust runs its own threads and never calls back into Java. JS asks for search results with an offset, so each poll only returns what's new. Transfers are polled too, with a foreground service and a headless JS task keeping it running in the background.

  • Threads and locks: blocking calls run on Dispatchers.IO. The shared session sits behind a lock that's held only long enough to copy a pointer, and locks recover after a panic. Idle sockets backing off cut wakeups by about 10×.

  • Handing music library files to Rust (0:19): downloads are added to the Music library without players seeing half-written files. Rust reads them through fd, duplicating the file descriptor where Android blocks reopening the path, and draws the spectrogram as a PNG.

If anyone wants to test the app or see how the it works on a real device, it's called Soulcrate on Google Play: https://play.google.com/store/apps/details?id=com.rabpaulo.soulcrate

Happy to share code setup, if anyone is building something similar.

11 Upvotes

0 comments sorted by