GoNetwork Tutorial — Welcome to the first of a series of technical blog posts from GoNetwork.

GoNetwork
Keeping Stock
Published in
6 min readOct 20, 2017
GoNetwork with other winners and founders at EthWaterloo

First a little background on how we got here.

ETHWaterloo represented the largest global Ethereum hackathon with participants coming from 32 countries. The 32 hour hack was judged by such notable names in the blockchain community including; Vitalik Buterin, Jeff Coleman, Brian Bondy, Joseph Lubin, Dmitry Buterin to name a few. Our submission Pocket won! We managed to produce a mobile-first bluetooth based tap and pay system using the Ethereum blockchain. We were the only native mobile product amongst the 400 participants.

Pocket by GoNetwork, named after pocket change, aims to solve a problem with financial literacy by implementing gamification, parental controls and transparency for youth leveraging the Ethereum blockchain. The offering allows parents to create assignable digital debit cards and claimable rewards for good behaviour such as decreased spending month to month and controlled spending across different categories (food,entertainment, etc.).

You can check out our entry at: https://devpost.com/software/pocket-t1fmg5.

Our belief is in order for blockchain to reach consumer markets, mobile developers need to start adopting the technology. The goal of this and proceeding tutorials draws on our experience and should get mobile devs to a point of prototyping. As GoNetwork grows we will continue to contribute tools and tutorials to the developer community.

This tutorial is based on a hackathon entry i.e. no code audits; as such this is not production quality code. That being said, lets get started.

You’ll need the following tools installed, I list my version numbers alongside:

  • node v7.9.0 & npm 4.2.0
  • bower 1.8.2
  • react-native 0.49.3 and react-native-cli 2.0.1
  • xcode 8.2.1
  • testprc v4.1.3

TLDR; Of course you can just grab the code and skip all the details if you wish. The source can be found at: https://github.com/gonetwork-project/mobile-dev-tutorials.

We won’t be running an Ethereum node on our mobile device, if you’re looking details for that, check out : https://github.com/ethereum/go-ethereum/wiki/Mobile:-Introduction.

Instead we will opt for methods inspired by status-im team and the work of https://github.com/alinz/react-native-webview-bridge.

Our goal for this tutorial will be creating a simple react-native iOS app that connects to a local test Ethereum node and returns a set of Accounts. Here’s a crude picture of our iOS code architecture:

iOS code architecture, kitten not included

My personal experience with create-react-native-app results in issues: https://github.com/facebook/react-native/issues/14246 , so I opt to use react-native init tutorial_1

react-native run-ios //confirm we can build

Now that you confirmed your app runs and builds lets get a simple webpage that loads web3.js and connects to local ethereum test node going. From the root directory run

bower install web3

This creates a folder which packages web3.js and all its dependencies:

./bower_components

create a directory ./html and a file called ./html/web3.html and copy and paste the code below:

<html>
<head>
<title>
Here are the accounts from test rpc
</title>
</head>
<body>
<div>
<h1>Accounts from TestRPC</h1>
<ul id="accounts">
</ul>
</div>
<script type="text/javascript" src="../bower_components/web3/dist/web3.min.js"></script>
<script type="text/javascript">
/**
* Sample Web3html
* https://github.com/facebook/react-native
* @flow
* Author: Amit Shah
*/
var provider = new Web3.providers.HttpProvider("http://localhost:8545");if (!('toJSON' in Error.prototype))
Object.defineProperty(Error.prototype, 'toJSON', {
value: function () {
var alt = {};
Object.getOwnPropertyNames(this).forEach(function (key) {
alt[key] = this[key];
}, this);
alt['ERROR'] = 1;
return alt;
},
configurable: true,
writable: true
});
CallbackHandler = function(data){
alert(JSON.stringify(data));
}
// var web3 = new Web3(new Web3.providers.HttpProvider("http://192.168.0.16:8545"));
var web3 = new Web3(provider);
function GetAccounts(){
if(web3){
try
{
var accounts = web3.eth.accounts;
return accounts;
}catch(e){
CallbackHandler(e);
}
}else{
CallbackHandler("ERROR, NO WEB3.JS CONTEXT");
}
return [];
}
var accounts = GetAccounts();
for(var i=0; i < accounts.length; i++){
var node = document.createElement("LI");
var textnode = document.createTextNode(accounts[i]);
node.appendChild(textnode);
document.getElementById("accounts").appendChild(node);
}</script></body></html>

Lets test web3.html. Move to the command line and start testrpc. This starts a test Ethereum node with rpc enabled at http://localhost:8545. Now open chrome and navigate to web3.html. When the page loads you should see something like this:

i took up a lot of room to show your test accounts

Great, you have a very simple webpage that connects to your local Ethereum node. Now lets wire this to iOS. Lets first download and install the webview-bridge.

cd ./node_modulesgit clone https://github.com/gonetwork-project/react-native-webview-bridge.gitcd..react-native linkreact-native run-ios 

If compilation fails you may have to clean and build the project from Xcode

Open Xcode, open $TUTORIAL_ROOT/ios/tutorial_1.xcodeproj

Run clean and build. After successful build, move back over to the command line and retry react-native run-ios. With successful compilation we can move on to updating App.js. Copy and paste the code from below and we will examine the various code blocks:

/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View,
Button
} from 'react-native';
import WebViewBridge from 'react-native-webview-bridge';const injectScript = `
(function () {
//https://stackoverflow.com/questions/18391212/is-it-not-possible-to-stringify-an-error-using-json-stringify
CallbackHandler=function(result){
//marshall the data
if(WebViewBridge){
WebViewBridge.send(JSON.stringify(result));
}
}
if (WebViewBridge) {
WebViewBridge.onMessage = function(message){
try{
if(message === "get_accounts"){
var accounts = GetAccounts();
CallbackHandler({result:accounts});
}
}catch(e){
CallbackHandler(e);
}
}
}
}());`;//we will need this for futre work
var WVB_GLOBAL = null;
export default class App extends Component<{}> {
onBridgeMessage(message) {
try{
if (this.refs['webviewbridge'] !== null) {
var msg = JSON.parse(message);
var accounts = msg.result;
alert("react-native accounts array:"+accounts);
}
}catch(err){
}
}
onButtonPress(){
this.webviewbridge.sendToBridge("get_accounts");
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit App.js
</Text>
<WebViewBridge
ref={(ref) => {this.webviewbridge = ref; WVB_GLOBAL = ref;}}
onBridgeMessage={(m) => this.onBridgeMessage(m)}
javaScriptEnabled={true}
injectedJavaScript={injectScript}
// If you run android, sorry you gotta deal with some local file stuff :()
//source={() =>
// Platform.OS === 'ios' ? require('./html/web3.html') :
// { uri: 'file:///android_asset/path-to/the-linked-file.html' }}
source={require('./html/web3.html')}
style={styles.webview} />
<Button
onPress={() => this.onButtonPress()}
title="Get Accounts"
color="#841584"
accessibilityLabel="Learn more about this purple button"
/>
</View>);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
webview: {
marginTop: 20,
maxHeight: 200,
width: 320,
flex: 1
},
});

Lets go through some interesting parts of this code. Firstly, we add the WebViewBridge into our render function:

<WebViewBridge
ref={(ref) => {this.webviewbridge = ref; WVB_GLOBAL = ref;}}
onBridgeMessage={(m) => this.onBridgeMessage(m)}
javaScriptEnabled={true}
injectedJavaScript={injectScript}
// If you run android, sorry you gotta deal with some local file stuff :()
//source={() =>
// Platform.OS === 'ios' ? require('./html/web3.html') :
// { uri: 'file:///android_asset/path-to/the-linked-file.html' }}
source={require('./html/web3.html')}
style={styles.webview} />

Interesting things to note:

  1. We define a callback onBridgeMessage that will respond to information sent from web3.html
  2. We define a property this.webviewbridge using react-natives ref props
  3. We inject javascript with injectedJavascriptProperty. The javascript code will help us marshal messages between react-native and web3.html
  4. We simply require('./html/web3.html') source. This has only been tested for iOS, android is known to have some issues referencing local files in a webview.

Lets take a look at injectScript

const injectScript = `
(function () {
//https://stackoverflow.com/questions/18391212/is-it-not-possible-to-stringify-an-error-using-json-stringify
CallbackHandler=function(result){
//marshall the data
if(WebViewBridge){
WebViewBridge.send(JSON.stringify(result));
}
}
if (WebViewBridge) {
WebViewBridge.onMessage = function(message){
try{
if(message === "get_accounts"){
var accounts = GetAccounts();
CallbackHandler({result:accounts});
}
}catch(e){
CallbackHandler(e);
}
}
}
}());`;

This script is appended to web3.html and redefines the CallbackHandler in web3.html. The redefined CallbackHandler will callJSON.stringifyon our account data before sending it back to react-native.

When that process happens, onBridgeMessage is invoked as a callback from react-native. If you press the “Get Accounts” button, you should see an alert modal pop up and list the very same accounts that were rendered in the web3.html test view.

And there you have it! You have just completed connecting to a local Ethereum node with react native. This is the very foundation of the next series of tutorials which will cover the following topics:

  • creating and sending off-chain signed transactions
  • Creating and compiling contracts with truffle and interacting with them in react-native
  • building a simple bluetooth tap-and-pay component

Stay Tuned and feel free to leave comments and feedback.

Thanks to @digital_abyss for proofread

--

--

GoNetwork
Keeping Stock

A highly scalable, low cost mobile first network infrastructure for Ethereum. Winning team at #ETHWaterloo, the worlds largest Ethereum hackathon.