Skip to content
This repository has been archived by the owner on Aug 15, 2019. It is now read-only.

Add rn integration test app #1874

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tfjs-react-native/.npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ tsconfig.json
tslint.json
yarn-error.log
yarn.lock
integration_rn59
68 changes: 67 additions & 1 deletion tfjs-react-native/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,69 @@
# Platform Adapter for React Native

Status: Early development.
Status: __Early development__. This is still an unpublished experimental package.

## Adapter Docs

TODO

## Setting up a React Native app with tfjs-react-native

These instructions assume that you are generally familiar with [react native](https://facebook.github.io/react-native/) developement. This library has only been tested with React Native 0.58.X & 0.59.X. React Native 0.60 is not supported.

### Step 1. Create your react native app.

You can use the [React Native CLI or Expo](https://facebook.github.io/react-native/docs/getting-started). This library relies on a couple of dependencies from the Expo project so it may be convenient to use expo but is not mandatory. You will also need to use Cocoapods to install these dependencies.

### Step 2: Install expo related libraries

Note if in a _managed_ expo application these libraries should be present and you should be able to skip this step.

Install and configure [react-native-unimodules](https://github.com/unimodules/react-native-unimodules)
Install and configure [expo-gl-cpp](https://github.com/expo/expo/tree/master/packages/expo-gl-cpp) and [expo-gl](https://github.com/expo/expo/tree/master/packages/expo-gl)

> Note that after this point, if you are using XCode to build for ios, you should use a ‘.workspace’ file instead of the ‘.xcodeproj’

### Step 3: Configure Metro

Edit your `metro.config.js` to look like the following. Changes are noted in
the comments below.

```js
// Change 1
const blacklist = require('metro-config/src/defaults/blacklist');

module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
resolver: {
// Change 2 (add 'bin' to assetExts)
assetExts: ['bin', 'txt', 'jpg'],
sourceExts: ['js', 'json', 'ts', 'tsx', 'jsx'],
// Change 3
blacklistRE: blacklist([/platform_node/])
},
};
```


### Step 4: Install TensorFlow.js and tfjs-react-native

- Install @tensorflow/tfjs - `npm install @tensorflow/tfjs`
- Install @tensorflow/tfjs-react-native - coming soon

### Step 5: Test that it is working

TODO: Add some sample code.

For now take a look at `integration_rn59/App.tsx` for an example of what using tfjs-react-native looks like.

### Optional Steps

If you want use the AsyncStorageHandler to save and load models. Add [async-storage](https://github.com/react-native-community/async-storage) to your project.

6 changes: 6 additions & 0 deletions tfjs-react-native/integration_rn59/.buckconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

[android]
target = Google Inc.:Google APIs:23

[maven_repositories]
central = https://repo1.maven.org/maven2
1 change: 1 addition & 0 deletions tfjs-react-native/integration_rn59/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pbxproj -text
63 changes: 63 additions & 0 deletions tfjs-react-native/integration_rn59/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# OSX
#
.DS_Store

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
project.xcworkspace

# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml

# Visual Studio Code
#
.vscode/

# node.js
#
node_modules/
npm-debug.log
yarn-error.log

# BUCK
buck-out/
\.buckd/
*.keystore

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/

*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots

# Bundle artifact
*.jsbundle

# CocoaPods
/ios/Pods/
1 change: 1 addition & 0 deletions tfjs-react-native/integration_rn59/.watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
172 changes: 172 additions & 0 deletions tfjs-react-native/integration_rn59/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/**
* @license
* Copyright 2019 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/

import React, { Fragment } from 'react';
import {
Button,
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
} from 'react-native';

import * as tf from '@tensorflow/tfjs';
import '@tensorflow/tfjs-react-native';

import Diagnostic from './components/Diagnostic';
import MobilenetDemo from './components/MobilenetDemo';

export type Screen = 'main' | 'diag' | 'demo';

interface AppState {
isTfReady: boolean;
currentScreen: Screen;
}

export default class App extends React.Component<any, AppState> {
constructor(props: any) {
super(props);
this.state = {
isTfReady: false,
currentScreen: 'main'
}

this.showDiagnosticScreen = this.showDiagnosticScreen.bind(this);
this.showDemoScreen = this.showDemoScreen.bind(this);
this.showMainScreen = this.showMainScreen.bind(this);
}

async componentDidMount() {
await tf.setBackend('rn-webgl');
await tf.ready();
this.setState({
isTfReady: true,
});
}

showDiagnosticScreen() {
this.setState({ currentScreen: 'diag' });
}

showDemoScreen() {
this.setState({ currentScreen: 'demo' });
}

showMainScreen() {
this.setState({ currentScreen: 'main' });
}

renderMainScreen() {
return <Fragment>
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>Diagnostic</Text>
<Button
onPress={this.showDiagnosticScreen}
title="Show Diagnostic Screen"
/>
</View>
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>Demo</Text>
<Button
onPress={this.showDemoScreen}
title="Show Demo Screen"
/>
</View>
</Fragment>;
}

renderDiagnosticScreen() {
return <Fragment>
<Diagnostic returnToMain={this.showMainScreen} />
</Fragment>
}

renderDemoScreen() {
const image = require('./assets/images/catsmall.jpg');
return <Fragment>
<MobilenetDemo
image={image}
returnToMain={this.showMainScreen} />
</Fragment>
}

renderLoadingTF() {
return <Fragment>
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>Loading TF</Text>
</View>
</Fragment>
}

renderContent() {
const { currentScreen, isTfReady } = this.state;
if (isTfReady) {
switch (currentScreen) {
case 'main':
return this.renderMainScreen();
case 'diag':
return this.renderDiagnosticScreen();
case 'demo':
return this.renderDemoScreen();
default:
return this.renderMainScreen();
}
} else {
return this.renderLoadingTF();
}

}

render() {
return (
<Fragment>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}>

<View style={styles.body}>
{this.renderContent()}
</View>
</ScrollView>
</SafeAreaView>
</Fragment>
);
}
}

const styles = StyleSheet.create({
scrollView: {
backgroundColor: 'white',
},
body: {
backgroundColor: 'white',
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: 'black',
marginBottom: 6,
},
});
3 changes: 3 additions & 0 deletions tfjs-react-native/integration_rn59/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This is an app that serves and an integration testbed for tfjs-react-native.

For more info please see the README in the folder above this one.
14 changes: 14 additions & 0 deletions tfjs-react-native/integration_rn59/__tests__/App-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @format
*/

import 'react-native';
import React from 'react';
import App from '../App';

// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';

it('renders correctly', () => {
renderer.create(<App />);
});
Loading