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-unknowntarget 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.rsinside the and add your Rust code to it. -
Add a
Cargo.tomlfile 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.shlocated the project root directory -
Make the
build.shscript 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.shscript:./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.jsfile in the root directory of your project. -
Locate the
getDefaultConfigimport at the top of the file:const { getDefaultConfig } = require('metro-config');
-
Add the following code inside the
module.exportsfunction:resolver: { assetExts: [...assetExts, 'wasm'], // Extend assetExts with 'wasm' },
The
assetExtsproperty 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
assetsin the root of your React Native project. This directory will hold your static files. -
Place the file you want to read in the
assetsdirectory. For example, let's say you have a file namedYourFile.wasm. -
In Xcode, open your project workspace by navigating to the
iosdirectory of your React Native project and double-clicking the.xcworkspacefile. -
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
assetsdirectory in your React Native project and select theYourFile.wasmfile. 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-fslibrary 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
assetsin the root of your React Native project. This directory will hold your static files. -
Place the file you want to read in the
assetsdirectory. For example, let's say you have a file namedYourFile.wasm. -
In your
android/appdirectory, create a new directory calledsrc/main/assets. This is where the files in your React Nativeassetsdirectory will be bundled when building the Android app. -
Copy or move the
assetsdirectory from the root of your project intoandroid/app/src/main. You should now haveandroid/app/src/main/assets. -
In your
android/app/build.gradlefile, add the following lines inside theandroidblock:
android {
// ...
// Add this block
sourceSets {
main {
assets.srcDirs += 'src/main/assets'
}
}
}- In your React Native script, you can use the
react-native-fslibrary 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.tsxfile located in theReactNativeWasmBridgeAppdirectory. -
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
Appcomponent 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
returnstatement 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.tsxfile. -
Check the console logs for the output of the Wasm module's functions. You should see the results of calling the
addfunction 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.