Skip to content

Commit ece26d6

Browse files
react-native: add README to native modules sample
1 parent 476d260 commit ece26d6

File tree

2 files changed

+199
-0
lines changed

2 files changed

+199
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ It contains the following samples:
88
* iOS: [Native Xcode Sample](ios/native-xcode)
99
* iOS: [Native Xcode Sample using a Node Project folder](ios/native-xcode-node-folder)
1010
* React-Native: [Suspend Resume Sample](react-native/SuspendResume)
11+
* React-Native: [Use Native Modules](react-native/UseNativeModules)
1112
* Cordova : [Cordova App With AngularJS](cordova-angularjs)
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# React Native Use Native Modules Sample
2+
3+
A React Native project that uses the [Node.js for Mobile Apps React Native plugin]( https://github.com/janeasystems/nodejs-mobile-react-native) plugin to showcase building and running native modules.
4+
5+
In this sample, the Node.js engine runs in a background thread inside the app, executing sample code from the [sha3](https://www.npmjs.com/package/sha3) and [sqlite3](https://www.npmjs.com/package/sqlite3) native modules. The results are shown in the app UI.
6+
7+
**Disclaimer: Building native modules is only available on macOS and Linux at the time of writing this sample.**
8+
9+
## Prerequisites
10+
11+
Install the build prerequisites mentioned in [nodejs-mobile](https://github.com/janeasystems/nodejs-mobile) for [Android](https://github.com/janeasystems/nodejs-mobile#prerequisites-to-build-the-android-library-on-linux-ubuntudebian) and [iOS](https://github.com/janeasystems/nodejs-mobile#prerequisites-to-build-the-ios-framework-library-on-macos).
12+
13+
Setup your system as described in the "Building Projects with Native Code" section of React Native's [Getting Started page](https://facebook.github.io/react-native/docs/getting-started.html).
14+
For Android, besides the environment variables mentioned, setting the environment variable ANDROID_NDK_HOME is also needed, as in this example:
15+
```sh
16+
export ANDROID_NDK_HOME=/Users/username/Library/Android/sdk/ndk-bundle
17+
```
18+
19+
## How to run
20+
- Clone this project.
21+
- Run the required npm and react-native commands to install the required node modules in the project root (`react-native/UseNativeModules/`):
22+
- `$ npm install`
23+
- `$ react-native link`
24+
25+
### iOS
26+
27+
If you want to run the app on a physical device, you'll also have to sign the project.
28+
29+
- Open the `ios/UseNativeModules.xcodeproj` project file in Xcode.
30+
- Select one of the physical iOS devices as the run target.
31+
- In the project settings (click on the project main node), in the `Signing` portion of the `General` tab, select a valid Team and let Xcode handle the provisioning profile creation/update. If you get an error that the bundle identifier cannot be used, you can simply change the bundle identifier to a unique string by appending a few characters to it.
32+
- Run the app. If the build process doesn't start the app right away, you might have to go to `Settings>General` in the device and enter `Device Management` or `Profiles & Device Management` to manually accept the profile.
33+
34+
35+
### Android
36+
37+
You may need to open your app's `/android` folder in `Android Studio`, so that it detects, downloads and cofigures requirements that might be missing, like the `NDK` and `CMake` to build the native code part of the project.
38+
39+
- Run `react-native run-android` in the project root (`react-native/UseNativeModules/`).
40+
41+
#### Troubleshooting
42+
On Android applications, the `react-native` build process is sometimes unable to rebuild assets.
43+
If you are getting errors while building the application using `react-native run-android`, the following commands can help you do a clean rebuild of the project, when run in the project root (`react-native/UseNativeModules/`).
44+
45+
On Linux/macOS:
46+
```sh
47+
cd android
48+
./gradlew clean
49+
cd ..
50+
react-native run-android
51+
```
52+
53+
## Project structure
54+
55+
### Node.js Part
56+
57+
In `nodejs-assets/nodejs-project/main.js` you can find the Node.js backend code, that calls the native modules as it receives messages from the React Native part of the project:
58+
59+
```js
60+
var rn_bridge = require('rn-bridge');
61+
62+
// sha3 module sample code adapted from its README.
63+
function sha3SampleCode() {
64+
var SHA3 = require('sha3');
65+
var result = '';
66+
// Generate 512-bit digest.
67+
var d = new SHA3.SHA3Hash();
68+
d.update('foo');
69+
result += "Digest 1: " + d.digest('hex') + "\n"; // => "1597842a..."
70+
// Generate 224-bit digest.
71+
d = new SHA3.SHA3Hash(224);
72+
d.update('foo');
73+
result += "Digest 2: " + d.digest('hex') +"\n"; // => "daa94da7..."
74+
return result;
75+
}
76+
77+
// sqlite3 module sample code adapted from its README.
78+
function sqlite3SampleCode( resultsCallback ) {
79+
var sqlite3 = require('sqlite3').verbose();
80+
var db = new sqlite3.Database(':memory:');
81+
82+
db.serialize(function() {
83+
db.run("CREATE TABLE lorem (info TEXT)");
84+
85+
var stmt = db.prepare("INSERT INTO lorem VALUES (?)");
86+
for (var i = 0; i < 10; i++) {
87+
stmt.run("Ipsum " + i);
88+
}
89+
stmt.finalize();
90+
91+
db.all("SELECT rowid AS id, info FROM lorem", function(err, rows) {
92+
var result = '';
93+
rows.forEach((row) =>
94+
result += row.id + ": " + row.info + "\n"
95+
);
96+
resultsCallback(result);
97+
});
98+
99+
});
100+
101+
db.close();
102+
}
103+
104+
rn_bridge.channel.on('message', (msg) => {
105+
try {
106+
switch(msg) {
107+
case 'versions':
108+
rn_bridge.channel.send(
109+
"Versions: " +
110+
JSON.stringify(process.versions)
111+
);
112+
break;
113+
case 'sha3':
114+
rn_bridge.channel.send(
115+
"sha3 output:\n" +
116+
sha3SampleCode()
117+
);
118+
break;
119+
case 'sqlite3':
120+
sqlite3SampleCode( (result) =>
121+
rn_bridge.channel.send(
122+
"sqlite3 output:\n" +
123+
result
124+
)
125+
);
126+
break;
127+
default:
128+
rn_bridge.channel.send(
129+
"unknown request:\n" +
130+
msg
131+
);
132+
break;
133+
}
134+
} catch (err)
135+
{
136+
rn_bridge.channel.send("Error: " + JSON.stringify(err) + " => " + err.stack );
137+
}
138+
});
139+
140+
// Inform react-native node is initialized.
141+
rn_bridge.channel.send("Node was initialized. Versions: " + JSON.stringify(process.versions));
142+
```
143+
144+
### React Native part
145+
146+
The React Native interface takes care of querying Node.js for each module by the means of distinct UI buttons and showing the results in the UI.
147+
148+
App.js contents:
149+
```js
150+
...
151+
import nodejs from 'nodejs-mobile-react-native';
152+
153+
type Props = {};
154+
export default class App extends Component<Props> {
155+
constructor(props){
156+
super(props);
157+
this.state = { lastNodeMessage: "No message yet." };
158+
this.listenerRef = null;
159+
}
160+
componentWillMount()
161+
{
162+
nodejs.start('main.js');
163+
this.listenerRef = ((msg) => {
164+
this.setState({lastNodeMessage: msg});
165+
});
166+
nodejs.channel.addListener(
167+
"message",
168+
this.listenerRef,
169+
this
170+
);
171+
}
172+
componentWillUnmount()
173+
{
174+
if (this.listenerRef) {
175+
nodejs.channel.removeListener("message", this.listenerRef);
176+
}
177+
}
178+
render() {
179+
return (
180+
<View style={styles.container}>
181+
<Button title="Get Versions"
182+
onPress={() => nodejs.channel.send('versions')}
183+
/>
184+
<Button title="Run sha3"
185+
onPress={() => nodejs.channel.send('sha3')}
186+
/>
187+
<Button title="Run sqlite3"
188+
onPress={() => nodejs.channel.send('sqlite3')}
189+
/>
190+
<Text style={styles.instructions}>
191+
{this.state.lastNodeMessage}
192+
</Text>
193+
</View>
194+
);
195+
}
196+
}
197+
...
198+
```

0 commit comments

Comments
 (0)