Translate

Tuesday, 22 January 2019

Develop an Android App with React Native & Publish on Google Play

Long-scroll mobile illustration

This article was originally published on the Okta developer blog. Thank you for supporting the partners who make SitePoint possible.

As mobile app usage is expected to continue to grow, now is as good a time as any to get into the market. Android is by far the most popular OS worldwide and the dominant way to get Android apps to phone users is the Google Play Store. In this tutorial, you’ll build a React Native app and I’ll walk you through everything from how to pick a design, as well as setting up your React Native environment, tips for getting the most out of your editor, and publishing it on Google Play.

This is what the eventual app will look like:

Final Result

For this tutorial, I checked out Karan Goel’s Mega Project List for project inspiration. You’ll be building the Prime Factorization problem which takes a number and returns its prime factors.

Determine Interface Theming for Your React Native App

Outside of application logic, UI and theming decisions are some of the most important that you’ll make for your app This includes the controls like dropdowns and buttons, as well as the layout on the screen. Since we are using a React-based technology, we’re going to use Styled Components which is a popular, light-weight approach to theming React applications (and it also works great on React Native). There’s an entire page listing components and component-systems based on Styled Components. In this tutorial, you’ll be using Styled Components to build up components yourself.

Set Up Your Android Production Environment

In order to build the eventual APK (the format of the app you’ll upload to the store), you need to install Android Studio. Once done make sure you have SDK version 27 as this is what React Native uses.

Install the JDK

You also need to make sure you have a recent Java Development Kit installed (like version 8). The installation differs depending on your platform. You can use Oracle’s Java SDK or use SDKMAN to install other options, like OpenJDK.

Add the React Native CLI and Initialize the Skeleton

Next, you should install the React Native Command Line Interface. For this, you should make sure you have Node installed which varies depending on your operating system. (I am using version 8.12.0).

npm install -g react-native-cli@2.0.1

You should have a command react-native available to you, which includes the init option.

react-native init prime_components

This will create the prime_components directory and put a React Native project inside, with a runnable skeleton. Change to the directory, connect your Android phone or run an emulator (after having installed Android Studio), and run the project.

NOTE: If Android Studio prompts you to open a project before you can create an emulator, you can point to the prime_components/android directory.

cd prime_components
react-native run-android

Welcome to React Native

To see the output you’ll upload to the Play Store, go to android/app/build/outputs/apk/debug. You should see an app-debug.apk that is around 8MB in size.

Reduce the Output Size of Your Android App

You want to make sure your users have the smallest download possible. It’s already quite small (around 8MB) because you’re using the command line (something like Expo produces 25MB for even basic apps) but we can reduce it further. Go to android/app/build.gradle and change the following variables to be true:

def enableSeparateBuildPerCPUArchitecture = true
def enableProguardInReleaseBuilds = true

You’ll also have to remove the ndk section of defaultConfig to removing the conflicting configuration in ndk abiFilters error:

ndk {
    abiFilters "armeabi-v7a", "x86"
}

Now after re-running react-native run-android you should see two (much smaller - between 4MB and 5MB) APKs in the output directory.

Add Linting to Your React Native App

Writing any JavaScript (like React) requires tools to ensure you haven’t made any obvious mistakes which can be a big help for beginners. The most common of these is ESLint which can be plugged right into your project and editor.

First, add the linter using NPM:

npm install -D eslint@5.9.0 babel-eslint@10.0.1

One common set of plugins is Airbnb’s configuration so add those too:

npm install -D eslint-config-airbnb@17.1.0 eslint-plugin-jsx-a11y@6.1.2 eslint-plugin-react@7.11.1 eslint-plugin-import@2.14.0

Now put the following into .eslintrc.js (you’ll need to create this file):

module.exports = {
  'extends': 'airbnb',
  'parser': 'babel-eslint',
  'env': {
    'jest': true,
  },
  'rules': {
    'no-use-before-define': 'off',
    'react/jsx-filename-extension': 'off',
    'react/prop-types': 'off',
    'comma-dangle': 'off'
  },
  'globals': {
    "fetch": false
  }
}

Now you just need to add the plugins to your editor. For Sublime there’s ESLint which gives you an output of errors (or issues) with CTRL + ALT + e (Cmd + Option + e on Mac). There also one for VSCode.

ESLint

A lot of these errors can be fixed automatically using the eslint --fix command which you can run from your editor with the ESLint Fix package.

Add Styled Components for React Native

React and React Native build interfaces using web technologies, i.e. HTML, CSS, and JavaScript. One very popular library to use with React (and React Native) is Styled Components which clean up how one adds CSS to your components.

For example, take a look at the following code, taken from the React Native sample app (which is what you get with react-init):

export default class App extends Component<Props> {
  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>
      <Text style={styles.instructions}>{instructions}</Text>
    </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,
  },
});

You declare your DOM elements (View, Text), linking them to styles, and then create the stylesheet later.

With Styled Components you would do the following:

const Container = styled.View`
  flex: 1;
  justify-content: center;
  align-items: center;
  background-color: #F5FCFF;
`;

const Welcome = styled.Text`
  fontSize: 20;
  text-align: center;
  margin: 10;
`;

const Instructions = styled.Text`
  text-align: center;
  color: #333333;
  margin-bottom: 5;
`;

export default class App extends Component<Props> {
  render() {
    return (
      <Container>
        <Welcome>Welcome to React Native!</Welcome>
        <Instructions>To get started, edit App.js</Instructions>
      </Container>
  );
  }
}

It’s both cleaner and more portable (CSS names don’t clash, etc.).

To install it, run npm install styled-components@4.1.1 from the root directory.

Add Custom Fonts to Your React Native App

To get a custom font like Racing Sans One into your application you first need to download the ttf and put it into assets/fonts (you will need to create this directory). Then add the following to your package.json:

"rnpm": {
  "assets": [
    "./assets/fonts/"
  ]
}

Finally run react-native link from the command line. You should now see your font inside of android/app/src/main/assets/fonts. You should be able to use it now. Create a components folder and put the following inside of components/Header.js:

import styled from 'styled-components/native';

export default styled.Text`
  color: black;
  font-family: RacingSansOne-Regular;
  font-size: 32px;
  margin-top: 120px;
  background-color: transparent;
  text-align: center;
`;

Then, import this into your App.js and add <Heading>Welcome</Heading> above the Text nodes:

import Header from './components/Header';
...
export default class App extends Component<Props> {
  render() {
    return (
      <View style={styles.container}>
        <Header>Welcome</Header>
        <Text style={styles.welcome}>Welcome to React Native!</Text>
        <Text style={styles.instructions}>To get started, edit App.js</Text>
        <Text style={styles.instructions}>{instructions}</Text>
      </View>
    );
  }
}

And you should get a nicely formatted header:

Custom fonts

Adjust Your App to be Fullscreen on Android

To get your app to not show the title bar, go to android/app/src/main/res/values/styled.xml and add the following inside the <styles> element:

<item name="android:windowFullscreen">true</item>

Now when you re-run you should see the navigation bar is gone.

Create the Android App Components

It can take a long time to decide on a final design, with layout, colors, and fonts. This is often an iterative process. Here you’ll go through how to build up the final result you saw at the start - which was inspired by related online tutorials and styling examples - but remember that it takes time to get to something you like.

Change App.js to the following:

import React from 'react';
import { Container, Header, Input, Keypad, ButtonRow } from './components';

const App = () => (
  <Container>
    <Header>Prime Components</Header>
    <Input>123456</Input>
    <Keypad>
      <ButtonRow keys={['1','2','3']} />
      <ButtonRow keys={['4','5','6']} />
      <ButtonRow keys={['7','8','9']} />
      <ButtonRow keys={['0','Clear','Go']} />
    </Keypad>
  </Container>
);

export default App;

You can see here how clean things are with Styled Components. We have a header, an input and a keypad (all names you choose) all surrounded by a container. No superfluous information. The styling happens in the components.

Create the components directory. Inside components/index.js put the following:

export { default as Input } from './Input';
export { default as Container } from './Container';
export { default as Header } from './Header';
export { default as Keypad } from './Keypad';
export { default as Button } from './Button';
export { default as ButtonRow } from './ButtonRow';

This is just a convenience module that allows for the importing as in App.js, i.e. ` import { Container, Header, Input, Keypad, ButtonRow } from ‘./components’;`. Otherwise, you’d have to import each component on a separate line.

Put this into components/Container.js: (Note: you must use capital letters for your components in React Native!)

import styled from 'styled-components/native';

export default Container = styled.View`
  flex: 1;
`;

Very simple: you are extending a View component and assigning a flex value of one (which in this context means “take up everything”).

components/Header.js:

import styled from 'styled-components/native';

export default Header = styled.Text`
  flex: 1.5;
  font-size: 80px;
  font-family: Chathura-ExtraBold;
  background-color: rgb(29, 31, 33);
  color: gold;
  text-align: center;
`;

Also, a styled text component, with large, centered fonts, a gold color, and grey background. Make sure you install the Chathura font from Google Fonts as before!

components/Input.js:

import styled from 'styled-components/native';

export default Input = styled.Text`
  flex: 2;
  text-align: right;
  font-family: Audiowide-Regular;
  text-align-vertical: center;
  font-size: 70;
  color: firebrick;
  background-color: gold;
`;

Similar to before except now with the Audiowide-Regular font (also available from Google Fonts).

components/Keypad.js:

import styled from 'styled-components/native';

export default Keypad = styled.View`
  flex: 6;
  background-color: rgb(29, 31, 33);
  padding-top: 10px;
  padding-bottom: 10px;
`;

Also just a styled view (essentially a container like a <div> in HTML).

components/ButtonRow.js:

import React from 'react';
import styled from 'styled-components/native';
import { Button } from '.';

const RowBox = styled.View`
  flex: 1;
  flex-direction: row;
`;

export default ButtonRow = ({keys}) => (
  <RowBox>
    { /* https://stackoverflow.com/a/32157488 */ }
    {keys.map(key => (
      <Button text={key} key={key} />
    ))}
  </RowBox>
);

Here, things get complicated. You are importing a Button from the current directory (which you’ll create in a second), creating a component called RowBox which is not exported, and then ButtonRow is defined having a React property called keys.

Then you are mapping each key to a button component. This is a clean way of looping through an array as with for each and using the value to set both the text and key attributes (you must set a key attribute to make the DOM object unique!). You’ll be using the text to render the button.

components/Button.js:

import React from 'react';
import styled from 'styled-components/native';

/* https://kylewbanks.com/blog/react-native-tutorial-part-2-designing-a-calculator */

/* https://github.com/styled-components/styled-components/issues/149 */
const ButtonBox = styled.TouchableHighlight.attrs({
  underlayColor: '#193441',
})`
  flex: 1;
  align-items: center;
  justify-content: center;
  background-color: rgb(39, 41, 43);
  border-radius: 10px;
  margin: 5px;
`;

const ButtonText = styled.Text`
  font-size: 30;
  font-family: Orbitron-Bold;
  color: ${props => props.text=="Go" ? "green" : "orange"};
`;

handleButtonPress = (value) => {

};

export default Button = ({text}) => (
  <ButtonBox onPress={() => handleButtonPress()}>
    <ButtonText text={text}>{text}</ButtonText>
  </ButtonBox>
);

This is the last component. You start by creating a ButtonBox which just acts as a container over the whole button. It is using TouchableHighlight which is a React Native component that will change color when touched. The styling is normal except for the underlay color (the color you see when touching) since this needs to be hacked to work in Styled Components.

The post Develop an Android App with React Native & Publish on Google Play appeared first on SitePoint.



No comments:

Post a Comment