DEV Community

Cover image for Building WASM, Android and iOS app with single/common RUST core code
Hasan Yousef
Hasan Yousef

Posted on

18 1

Building WASM, Android and iOS app with single/common RUST core code

I'll write below, the file required to write simple hello world code using RUST, that can be called by WASM/Android/iOS app, compiling and calling will follow in later article.. follow me to be notified..

I tested both WASMand Android and they are fine.

src folder tree:

Hasans-Air:src h_ajsf$ tree .
.
├── lib.rs
├── android
│   └── mod.rs
├── ios
│   └── mod.rs
└── wasm
    └── mod.rs

3 directories, 4 files
Enter fullscreen mode Exit fullscreen mode

And the files now are:

Main:

// lib.rs
pub mod wasm;
pub mod ios;
pub mod android;

#[cfg(not(target_arch = "wasm32"))]
use std::os::raw::{c_char};

#[cfg(not(target_arch = "wasm32"))]
use std::ffi::{CStr};

pub fn rust_greetings(to: &str) -> String {
    format!("Hello {}", to)
}

#[cfg(not(target_arch = "wasm32"))]
fn char_str(pattern: *const c_char) -> &'static str {

    let c_str = unsafe { CStr::from_ptr(pattern) };
    let string_ptr = match c_str.to_str() {
        Err(_) => "there",
        Ok(string) => string,
    };
    string_ptr
}
Enter fullscreen mode Exit fullscreen mode

WASM

// src/wasm/mod.rs
#[cfg(target_arch = "wasm32")]
pub mod wasm {
    use crate::rust_greetings;
    use wasm_bindgen::prelude::*;

    #[wasm_bindgen]
    pub fn wasm_greetings(to: &str) -> String {
        rust_greetings(to)
    }
}
Enter fullscreen mode Exit fullscreen mode

Android

// src/android/mod.rs
#[cfg(target_os="android")]
#[allow(non_snake_case)]
pub mod android {
    use crate::rust_greetings;
    use crate::char_str;
    extern crate jni;

    use self::jni::JNIEnv;
    use self::jni::objects::{JClass, JString};
    use self::jni::sys::{jstring};

    #[no_mangle]
    pub unsafe extern fn Java_com_hasan_RustGreetings_greetings(env: JNIEnv, _: JClass, java_pattern: JString) -> jstring {

        let jvm_input = env.get_string(java_pattern)
                                        .expect("invalid pattern string").as_ptr();

        let input = rust_greetings(char_str(jvm_input));

        let output = env.new_string(input)
                                        .expect("Couldn't create java string!");
        output.into_inner()
    }
}
Enter fullscreen mode Exit fullscreen mode

iOS

// src/ios/mod.rs
#[cfg(target_os="ios")]
#[no_mangle]
pub mod ios {
    use crate::char_str;

    use std::ffi::{CString, CStr};
    use std::os::raw::{c_char};
    use crate::rust_greetings;

    #[no_mangle]
    pub extern fn ios_greetings(to: *const c_char) -> *mut c_char {

        let input = rust_greetings(char_str(to));

        CString::new(input).unwrap().into_raw()
    }

    pub extern fn iso_greeting_free(s: *mut c_char) {
        unsafe {
            if s.is_null() { return }
            CString::from_raw(s)
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

TOML

# Cargo.toml
[package]
name = "greetings"
version = "0.1.0"
authors = ["Hasan Yousef"]
edition = "2018"

[dependencies]

[target.'cfg(target_arch="wasm32")'.dependencies]
wasm-bindgen = "0.2.29"

[target.'cfg(target_os="android")'.dependencies]
jni = { version = "0.5", default-features = false }

[lib]
name = "rust_greetings"
crate-type = ["cdylib", "dylib", "staticlib"] 
# Android: dylib
# iOS: cdylib [armv7s-apple-ios] and staticlib [Others]
# WASM: cdylib
Enter fullscreen mode Exit fullscreen mode

Below is to manage the linker for compiling Android targets

Cargo config:

# .cargo/config
[target.aarch64-linux-android]
ar = "NDK/arm64/bin/aarch64-linux-android-ar"
linker = "NDK/arm64/bin/aarch64-linux-android-clang"

[target.armv7-linux-androideabi]
ar = "NDK/arm/bin/arm-linux-androideabi-ar"
linker = "NDK/arm/bin/arm-linux-androideabi-clang"

[target.i686-linux-android]
ar = "NDK/x86/bin/i686-linux-android-ar"
linker = "NDK/x86/bin/i686-linux-android-clang"

[target.x86_64-linux-android]
ar = "NDK/x86/bin/x86_64-linux-android-ar"
linker = "NDK/x86_64/bin/x86_64-linux-android-clang"
Enter fullscreen mode Exit fullscreen mode

Below are for running the WASM, which is already explained (here) [https://dev.to/h_ajsf/rust--wasm-using-bindgen-49b4]

webpack.config.js

// webpack.config.js
const path = require("path");

module.exports = {
  entry: "./index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "index.js",
  },
  mode: "development"
};
Enter fullscreen mode Exit fullscreen mode

package.json

// package.json
{
  "name": "utils2",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.27.1",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.10"
  }
}
Enter fullscreen mode Exit fullscreen mode

index.js

import("./pkg/greetings").then(wasmModule => {
  let gr = wasmModule.wasm_greetings("Karam sweet")
  console.log(gr);
});
Enter fullscreen mode Exit fullscreen mode

index.html

<!DOCTYPE html>
<html>
<head>
    <script src="./index.js"></script>
    <head>
<body></body>
<html>
Enter fullscreen mode Exit fullscreen mode

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (1)

Collapse
 
claudio1985 profile image
Claudio Noguera

git repo?

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay