1

Integrating Rust With Android Development

 2 years ago
source link: https://blog.devgenius.io/integrating-rust-with-android-development-ef341c2f9cca
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Integrating Rust With Android Development

Rust is a general-purpose, systems programming language that has been around for quite some time now. Being a systems programming language, it can be used to perform tasks similar to languages such as C and C++ but with much more memory safety. This allows Rust to be used to write programs or scripts on numerous operating systems including Android. You may wonder how this could be possible and if there is a simple way to do so. Well, that’s what this article is about!

Currently, there isn’t much information on how to write Rust code for an android application. There is some information provided by Google here but it’s complicated for a beginner to understand. The goal of this walkthrough is to provide a simple but efficient guide to integrating Rust code with android development and ultimately become the go-to guide. No prior knowledge of C or C++ or JNI is required!

We will use Android Studio. Let’s begin by setting it up.

Pro Tip💡: Are you looking to write more idiomatic and efficient Rust code? Then try this Rust Cookbook or Textbook which has practical recipes that will help you work with the Standard library to boost your productivity as a Rust developer!

Setup 🌱

Rust Plugin ⚙️

First, we need the Rust plugin. Open up Android Studio. A dialog similar to what is displayed below would open up. Select the Plugins tab, search for “Rust” and then install the official Rust plugin by JetBrains. Alternatively, if you have a project already opened, click on File at the top left corner of Android Studio and select Settings. Click on Plugins.

The Rust Plugin requires Rust installed on your system. You can follow this link to install Rust on your system.

1*vIp429xNBAmk56_FdhOZmw.png?q=20
integrating-rust-with-android-development-ef341c2f9cca

Creating An Empty Application 📱

Now let’s create a new empty app. Start by going through the standard new project setup.

1*eMtX0LGhY1ZVlBt7p12CGg.png?q=20
integrating-rust-with-android-development-ef341c2f9cca

Let’s name our project Rust Application and click on finish.

A window similar to the one shown below would appear.

1*75wCKhDm7MfQ0UPu3m8ZSQ.png?q=20
integrating-rust-with-android-development-ef341c2f9cca

Incorporating A Cargo Project 💼

Let’s now add a Cargo project, following the tutorial provided here. To embed a Rust project, simply click on the Terminal in Android Studio and type cargo new rust_lib --lib, then press enter.

C:\Users\USER1\AndroidStudioProjects\RustApplication>cargo new rust_lib --lib

This creates a new library so it can be used from within our application. We named the library rust_lib. Take note of where the folder is created.

To view the folder in Android Studio, navigate to the Project pane and select Project from the dropdown menu instead of Android.

1*T-2-mcR6WYG_qKYLfgj0ZQ.png?q=20
integrating-rust-with-android-development-ef341c2f9cca

You would then see a new folder named rust_lib. This folder contains a new git repository by default, a Cargo.toml file, and an src folder containing lib.rs. Now let’s modify the type of library we just created using the Cargo.toml file. For mobile app development, the library should be a dynamic one.

Add the following to the contents of the Cargo.toml file.

[lib]
name = "rust_lib"
crate-type = ["cdylib"]

View the gist here.

Adding Dependencies 🧶

Let’s add dependencies that would create the necessary files to make linking our rust code to the Android end a smooth process.

Use the “*” to pull the latest version of the dependency.

flapigenis the main build dependency to generate the appropriate code from our rust code to use it in our android app. flapigen works with an interface file but having to modify the interface file every time there’s a code change could get tedious. That’s where rifgencomes it. It makes the creation of the interface file such a breeze.

The extra dependencies are for logging.

Creating A Build File 📄

As mentioned earlier, flapigen and rifgen are build dependencies and interact with the build.rs file. Right-click on rust_lib folder and select New > Rust File.

1*N7IPHePJFtDux9YTVt0JwA.png?q=20
integrating-rust-with-android-development-ef341c2f9cca

Name the file build.rs.

Following the tutorial given by flapigen and rifgen, our build.rs should look similar to the following:

build.rs

You might be wondering what’s happening in the build.rs. flapigen converts what’s in the interface file to a java_glue rust file. So we first specify the source file for the interface file (in_src) and then the out file (java_glue.rs). The directory of the java_glue.rs has to be the same as the OUT_DIR environment variable. After doing that, use rifgen to generate the interface file, specifying our preference depending on the language we’re adding the rust project to. The last parameter of Generator::new specifies the start of the folder containing our rust code and the generate_interface function takes the path of the interface file. i.e. in_scr. The java_folder specifies where the java files created should go to. Calling swig_gen.expand tells flapigen to generate the appropriate files. Note these parameters as we use them in the Gradle build.

Finally, create a file named java_glue.rs in the rust_lib/src folder and put the following contents:

And add:

mod java_glue;
pub use crate::java_glue::*;

To your lib.rs file. Doing this connects your rust code to the one generated.

Add Android Toolchains And Linkers ⛓

To compile Rust for android, we need to add the android toolchains to rustup. To do so, simply run the following in the Terminal:

C:\Users\USER1\AndroidStudioProjects\RustApplication>rustup target add aarch64-linux-android armv7-linux-androideabi

This adds the rust toolchains and standard library for 64-bit and 32-bit android versions respectively. Now, let’s add the compiler linkers. It should be added to rust_lib/.cargo/config.toml file.

Right-click on the rust_lib folder, create a new directory called .cargo then create a new file in the .cargo directory called config.toml.

The appropriate linkers come with Android NDK and should therefore be downloaded before continuing.

Add the following to the config file you created.

Replace ANDROID SDK with the android SDK path (or the folder containing the NDK-bundle). Also, replace the OS VERSION with your OS version. For instance, on my Windows pc, the full path is:

[target.aarch64-linux-android]
linker = "C:\\Users\\taimoor\\AppData\\Local\\Android\\Sdk\\ndk-bundle\\toolchains\\llvm\\prebuilt\\windows-x86_64\\bin\\aarch64-linux-android21-clang++.cmd"

Notice the .cmd at the end for a Windows build.

Using Gradle To Automate Build 🐘

Gradle can be used to automatically run cargo build whenever we want to test out the app. This would cause changes we made at the Rust side to be automatically updated into our application.

build.gradle

Note that this is the app or module level Gradle file and not the Project level Gradle file. Add lines 20 to 27 and line 65 onwards. Line 65 onwards just instructs Gradle to run cargo build whenever we run the app. After running the cargo build command, we then copy the java files and the dynamic library file (.so) created and paste them into the directory which can be read by Android and used in our Kotlin code.

The application now should run 😄. If you’re having difficulty running it, leave a comment below or feel free to mail me at [email protected]!

Bonus Section: Logging 📃

Let’s quickly implement logging to help with debugging our Rust code. In the lib.rs file, add the following content:

We use the android_logger crate for generating logs and then call log_panics::init() to redirect all panics to be logged rather than printed to standard error. Notice the attribute #[generate_interface]. This tells rifgen that we’re going to call this function from Kotlin so it should add that method call to the interface file.

Loading The Library From Kotlin 📲

Now that we have set up the Rust side, let’s move on to the Kotlin side. We will now load the library from a singleton:

MainActivity.kt

Add the various import for the Logs class we created. Note how even though we named the function initialise_logging, we’re able to use it as initialiseLogging. This is because we specified CamelCase when setting up rifgen.

Run the program to see the information from the Rust code being logged.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK