This project aims to bridge Rust, WebAssembly (WASM) and React Native together. It allows you to compile Rust code into WASM and then integrate it into a React Native application.
Before getting started, make sure you have the following installed:
- Node.js (>=18.0.0)
- Yarn
- Rust (>=1.50.0) with
wasm32-unknown-unknown
target installed - React Native CLI
-
Clone the project repository:
git clone https://github.com/your-username/rust2wasm2react-native.git
-
Navigate to the project directory:
cd rust2wasm2react-native
-
Install project dependencies using Yarn:
yarn install
-
Build the Rust code and copy the generated WASM file:
sh build.sh
-
Create a new React Native project using the following command:
npx react-native init <YourProjectName>
-
Navigate to the project directory:
cd <YourProjectName>
-
Install the required dependencies using Yarn:
yarn add axios react-native-fs react-native-webassembly base-64 @types/base-64
-
If you want to go full manual, inside the project directory, you can add new directory
-
Create a new file
lib.rs
inside the and add your Rust code to it. -
Add a
Cargo.toml
file like the following:[package] description = "rust2wasm2react-native bridge among Rust, WebAssembly and React-Native" edition = "2021" license = "MIT" name = "rust2wasm2react-native" repository = "<https://github.com/xonoxitron/rust2wasm2react-native>" version = "0.1.0" [lib] crate-type = ["cdylib"]
-
You can use the embedded
build.sh
located the project root directory -
Make the
build.sh
script executable by running the following command:chmod +x build.sh
-
Build the Rust code and copy the Wasm file to the React Native project by executing the
build.sh
script:./build.sh
This script cleans the wasm
directory, compiles the Rust code to Wasm using the rustc
command, and copies the resulting Wasm file to the React Native project's assets
directory.
To ensure that Metro, the JavaScript bundler used by React Native, recognizes the Wasm file as an asset, you need to extend the metro.config.js
file. Follow these steps:
-
Open the
metro.config.js
file in the root directory of your project. -
Locate the
getDefaultConfig
import at the top of the file:const { getDefaultConfig } = require('metro-config');
-
Add the following code inside the
module.exports
function:resolver: { assetExts: [...assetExts, 'wasm'], // Extend assetExts with 'wasm' },
The
assetExts
property contains an array of file extensions that Metro considers as assets. By adding'wasm'
to this array, Metro will recognize Wasm files as assets.
To include a static file in your React Native project and read it from the script in iOS, you can follow these steps:
-
Create a new directory called
assets
in the root of your React Native project. This directory will hold your static files. -
Place the file you want to read in the
assets
directory. For example, let's say you have a file namedYourFile.wasm
. -
In Xcode, open your project workspace by navigating to the
ios
directory of your React Native project and double-clicking the.xcworkspace
file. -
In Xcode, right-click on your project's root folder in the project navigator, and select "Add Files to [Your Project Name]".
-
Navigate to the
assets
directory in your React Native project and select theYourFile.wasm
file. Make sure to check the "Copy items if needed" option and select the target you want to add the file to. -
In your React Native script, you can use the
react-native-fs
library to read the file from the assets directory. Update your script to the following:
const App = () => {
const loadFile = async () => {
try {
const filePath = RNFS.MainBundlePath + '/YourFile.wasm';
const fileExists = await RNFS.exists(filePath);
if (!fileExists) {
console.log('File does not exist');
return;
}
...
To include a static file in your React Native project and read it from the script, you can follow these steps:
-
Create a new directory called
assets
in the root of your React Native project. This directory will hold your static files. -
Place the file you want to read in the
assets
directory. For example, let's say you have a file namedYourFile.wasm
. -
In your
android/app
directory, create a new directory calledsrc/main/assets
. This is where the files in your React Nativeassets
directory will be bundled when building the Android app. -
Copy or move the
assets
directory from the root of your project intoandroid/app/src/main
. You should now haveandroid/app/src/main/assets
. -
In your
android/app/build.gradle
file, add the following lines inside theandroid
block:
android {
// ...
// Add this block
sourceSets {
main {
assets.srcDirs += 'src/main/assets'
}
}
}
- In your React Native script, you can use the
react-native-fs
library to read the file from the assets directory. Update your script to the following:
const App = () => {
const loadFile = async () => {
try {
const filePath = 'file:///android_asset/YourFile.wasm';
const fileExists = await RNFS.existsAssets(filePath);
if (!fileExists) {
console.log('File does not exist');
return;
}
...
In this example, the YourFile.wasm
file is placed in the assets
directory. We then read the file using the RNFS.readFileAssets
method, passing the file path as file:///android_asset/YourFile.wasm
. The RNFS.existsAssets
method is used to check if the file exists.
By following these steps, you can include a static file in your React Native project and read it from the script.
The main entry point of your React Native application is the App.tsx
file. In this file, you can use the react-native-webassembly
and react-native-fs
libraries to load and interact with the Wasm module.
-
Open the
App.tsx
file located in theReactNativeWasmBridgeApp
directory. -
Import the required modules and libraries at the top of the file:
import axios from 'axios'; import RNFS from 'react-native-fs'; import { decode as atob } from 'base-64'; import * as WebAssembly from 'react-native-webassembly';
-
Update the
App
component to include the following code:
const App: React.FC = () => {
const isDarkMode = useColorScheme() === 'dark';
useEffect(() => {
// Utility function to convert base64 string to ArrayBuffer
const base64ToArrayBuffer = (base64: string) => {
const binaryString = atob(base64);
const length = binaryString.length;
const arrayBuffer = new ArrayBuffer(length);
const uintArray = new Uint8Array(arrayBuffer);
for (let i = 0; i < length; i++) {
uintArray[i] = binaryString.charCodeAt(i);
}
return arrayBuffer;
};
// Load the WebAssembly module remotely from a URL
const loadWasmRemotely = async () => {
const { data: bufferSource } = await axios({
url:
'https://github.com/xonoxitron/rust2wasm2react-native/blob/main/wasm/rust_lib.wasm',
method: 'get',
responseType: 'arraybuffer',
});
const module = await WebAssembly.instantiate<{
add: (a: number, b: number) => number;
}>(bufferSource);
console.log(module.instance.exports.add(1, 2));
};
loadWasmRemotely();
// Load the WebAssembly module locally from the bundled file
const loadWasmLocally = async () => {
try {
const filePath = `${RNFS.MainBundlePath}/rust_lib.wasm`;
const fileExists = await RNFS.exists(filePath);
if (!fileExists) {
console.log('File does not exist');
return;
}
const content = await RNFS.readFile(filePath, 'base64');
const bufferSource = base64ToArrayBuffer(content);
const module = await WebAssembly.instantiate<{
add: (a: number, b: number) => number;
}>(bufferSource);
console.log(module.instance.exports.add(3, 4));
} catch (error) {
console.log('Error:', error);
}
};
loadWasmLocally();
}, []);
-
Customize the UI sections inside the
return
statement according to your application's requirements. You can add, remove, or modify the sections as needed. -
Save the file.
To run the React Native application and test the integration with the Rust Wasm module, follow these steps:
-
Make sure you have a device or emulator connected to your development machine.
-
In the project directory, run the following command to start the Metro bundler:
npx react-native start
-
Open a new terminal window and run the following command to launch the application on your device or emulator:
npx react-native run-android # For Android npx react-native run-ios # For iOS
This will build the React Native application and deploy it to the connected device or emulator.
-
Once the application is running, you should see the screen with the sections you defined in the
App.tsx
file. -
Check the console logs for the output of the Wasm module's functions. You should see the results of calling the
add
function from both the remotely loaded and locally loaded Wasm modules.Remote Wasm Result: 3 Local Wasm Result: 7
This confirms that the Rust Wasm module has been successfully integrated into your React Native application.
Congratulations! You have successfully set up and integrated the Rust Wasm module into your React Native application using rust2wasm2react-native
. You can now leverage the power of Rust and WebAssembly to enhance the functionality of your mobile application.
Feel free to explore and expand upon this project to suit your specific needs. Happy coding!
Please note that this documentation assumes you have basic knowledge of Rust, WebAssembly, and React Native development. If you are new to any of these technologies, it is recommended to familiarize yourself with them before proceeding with this project.
If you encounter any issues or have further questions, please refer to the project repository for additional documentation and support.