Neste post estarei compartilhando e documentando minha experiência durante o processo de criação de aplicativos Android e iOS utilizando React Native.
1) Configuração do ambiente
1.2) Quais as ferramentas de desenvolvimento?
- Node.js
- Git
- Visual Studio Code
- Extensões: React Native Tools e Expo Tools
- Android Studio
- Genynobile Scrcpy (Para espelhar o smartphone no computador)
1.3) Criando um app em React Native (com Expo)
Criando o app
npx create-expo-app NomeApp
O comando acima irá criar um o aplicativo utilizando o Expo.
Executando o app
cd NomeApp
npx expo start
Observações:
- Instalar o app Expo Go (Android/iOS*)
- Ler o QR-Code gerado através do aplicativo Expo Go;
- *no iOS basta ler o QR-Code com o aplicativo de câmera;
1.4) Criando um app em React Native (por CLI)
Observações:
- Ambiente: Windows
- Dispositivo: Android
- Conectar o dispositivo Android no computador via cabo USB;
- No aparelho, habilitar o modo de desenvolvedor e permitir a depuração USB;
- Ao conectar o celular no computador, permitir a transferência de arquivos;
Criando o app
npx react-native@latest init NomeApp
O comando acima irá criar todos os arquivos necessários para o app;
Iniciando o app
cd NomeApp
npx react-native run-android
O aplicativo será instalado automaticamente no aparelho Android
Também é possível iniciar com Metro* separadamente com o comando:
npx react-native start
*o Metro é muito parecido com o webpack (React para web) — só que p/ para apps — ele é um empacotador de JavaScript.
Atalhos
Podemos personalizar os atalhos para executar o app em modo de desenvolvimento;
Para isso, basta editar o arquivo package.json.
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"lint": "eslint .",
"start": "react-native start",
"dev": "react-native start --reset-cache",
"test": "jest"
}
No exemplo acima foi adicionado o atalho “dev”
com —reset-cache
.
Assim podemos iniciar o modo de desenvolvimento com:
npm run dev
2) O básico
2.1) O que é o React Native?
React Native é uma estrutura híbrida e de código aberto para criar apps para Android e iOS usando React;
Para aprender React Native é necessário saber os fundamentos de Javascript, HTML e CSS.
2.2) Desenvolvimento Nativo x Híbrido
-
Para criar apps nativos em Android utilizamos a linguagem Java ou Kotlin;
-
Para criar apps nativos para iOS é necessário codificar em Swift ou Objective-C;
-
O React Native é uma estrutura híbrida e utiliza a linguagem Javascript para criar as visualizações correspondentes do Android e iOS em tempo de execução;
2.3) Componentes principais
- O React Native possui muitos componentes principais, como por exemplo:
React Native | Android | iOS | Web (similaridade) |
---|---|---|---|
<View> |
<ViewGroup> |
<UIView> |
<div> |
<Text> |
<TextView> |
<UITextView> |
<p> |
<Image> |
<ImageView> |
<UIImageImage> |
<img> |
<ScrollView> |
<ScrollView> |
<UIScrollView> |
<div> |
<TextInput> |
<EditText> |
<UITextField> |
<input type="text"> |
2.3.1) Amostra das visualizações no Android x iOS
2.4) Fundamentos de React
-
React Native é executado com base no React, por isso, é necessário saber os fundamentos de:
- 2.4.1) componentes
- 2.4.2) JSX
- 2.4.3) props
- 2.4.4) estado
2.4.1) Componentes
-
Um componente é um elemento básico da interface do usuário;
-
Podemos criar componentes de função (hooks com estado) e com classes (forma antiga);
-
O React Native irá renderizar no aparelho do usuário o componente de acordo com o sistema operacional do dispositivo (iOS ou Android);
import React from "react";
import { Text } from "react-native";
const Cat = () => {
return <Text>Hello, I am your cat!</Text>;
};
export default Cat;
2.4.2) JSX
-
JSX é uma extensão da sintaxe do JavaScript que permite escrever HTML dentro do JavaScript;
-
Em JSX podemos misturar JavaScript e HTML (ou XML) em um único arquivo;
-
Como JSX é JavaScript, podemos usar variáveis dentro dele;
-
Qualquer expressão JavaScript funcionará entre chaves no JSX, como por exemplo:
import React from "react";
import { Text } from "react-native";
const getFullName = (
firstName: string,
secondName: string,
thirdName: string
) => {
return firstName + " " + secondName + " " + thirdName;
};
const Cat = () => {
return <Text>Hello, I am {getFullName("Rum", "Tum", "Tugger")}!</Text>;
};
export default Cat;
2.4.3) Props
-
Props é uma abreviação para propriedades;
-
As propriedades permitem personalizar os componentes React, por exemplo:
import React from "react";
import { Text, View } from "react-native";
const Cat = (props) => {
return (
<View>
<Text>Hello, I am {props.name}!</Text>
</View>
);
};
const Cafe = () => {
return (
<View>
<Cat name="Maru" />
<Cat name="Jellylorum" />
<Cat name="Spot" />
</View>
);
};
export default Cafe;
2.4.4) Estado
-
Estado é a forma de armazenar dados de um componente;
-
O estado fornece memória aos componentes;
-
Ele é útil para lidar com dados que mudam com o tempo ou que vêm da interação do usuário;
-
É possível adicionar estado a um componente React usando o hook
useState
; -
useState
é um hook que permite adicionar estado aos componentes da função;
import React, { useState } from "react";
import { Button, Text, View } from "react-native";
const Cat = (props) => {
const [isHungry, setIsHungry] = useState(true);
return (
<View>
<Text>
I am {props.name}, and I am {isHungry ? "hungry" : "full"}!
</Text>
<Button
onPress={() => {
setIsHungry(false);
}}
disabled={!isHungry}
title={isHungry ? "Pour me some milk, please!" : "Thank you!"}
/>
</View>
);
};
const Cafe = () => {
return <Cat name="Munkustrap" />;
};
export default Cafe;
2.4.5) Fragmentos
-
As tags “vazias”
<>
e</>
acima são bits do JSX chamadas de fragmentos. -
Fragmentos permitem envolver todo código sem precisar incluir um elemento extra e desnecessário, como uma
View
, por exemplo.
const Cafe = () => {
return (
<>
<Cat name="Munkustrap" />
<Cat name="Spot" />
</>
);
};
2.5) Código específico Android/iOS
-
Com React Native é possível implementar componentes visuais separados p/ Android e iOS;
-
Há duas maneiras de separar o código por plataforma:
- Usando o *Platform Module;*
- Usando extensões de arquivos específicas;
Platform Module
-
Essa opção é recomendada para pequenas partes de código;
-
É possível usar a lógica de detecção para implementar o código específico da plataforma;
Platform:
import { Platform, StyleSheet } from "react-native";
const styles = StyleSheet.create({
height: Platform.OS === "ios" ? 200 : 100,
});
Platform.select - pode ser: 'ios' | 'android' | 'native' | 'default'
import { Platform, StyleSheet } from "react-native";
const styles = StyleSheet.create({
container: {
flex: 1,
...Platform.select({
ios: {
backgroundColor: "red",
},
android: {
backgroundColor: "green",
},
default: {
// outras plataformas, web por exemplo
backgroundColor: "blue",
},
}),
},
});
Detectar a versão do Android:
import { Platform } from "react-native";
if (Platform.Version === 25) {
console.log("Running on Nougat!");
}
Detectar a versão do iOS:
import { Platform } from "react-native";
const majorVersionIOS = parseInt(Platform.Version, 10);
if (majorVersionIOS <= 9) {
console.log("Work around a change in behavior");
}
Extensões de arquivos específicas
-
Recomendado para códigos específicos da plataforma mais complexos;
-
Com essa opção é possível dividir o código em arquivos separados;
-
Para utilizar esse opção é só criar o componente com o nome de cada plataforma, por exemplo:
BigButton.ios.js;
BigButton.android.js;
Depois, basta importar o componente e o React Native selecionará automaticamente o arquivo correto com base na plataforma em execução:
import BigButton from "./BigButton";
3) Design
3.1) Style
-
Todos os componentes principais aceitam a propriedade
style
-
Os nomes dos estilos e valores correspondem à maneira como o CSS funciona na web;
-
Porém os nomes são escritos no formato camelCase, por exemplo:
-
backgroundColor
ao invés debackground-color
; -
A medida que o componente cresce em complexidade é mais limpo usar
StyleSheet.create
import React from "react";
import { StyleSheet, Text, View } from "react-native";
const styles = StyleSheet.create({
container: {
marginTop: 50,
},
red: {
color: "red",
},
});
const LotsOfStyles = () => {
return (
<View style={styles.container}>
<Text style={styles.red}>just red</Text>
</View>
);
};
export default LotsOfStyles;
3.2) Largura e altura (Width/Height)
-
Todas as dimensões no React Native não precisam de unidade (px, rem, etc)
-
As dimensões representam pixels independentes da densidade.
import React from "react";
import { View } from "react-native";
export function FixedDimensionsBasics() {
return (
<View>
<View
style=
/>
</View>
);
}
-
Também é possível utilizar valores percentuais no estilo do componente
-
As dimensões percentuais também requerem um elemento pai com o tamanho definido;
import React from "react";
import { View } from "react-native";
const PercentageDimensionsBasics = () => {
return (
<View style=>
<View
style=
/>
<View
style=
/>
</View>
);
};
export default PercentageDimensionsBasics;
3.3) Layout com Flexbox
-
Por padrão todos os componentes do React Native são flex e direcionados por coluna;
-
Na web o padrão é por linha (row), um ao lado do outro;
- Já no React Native, o padrão é por coluna (column), um em baixo do outro;
display: flex
flexDirection: column
- Para que um componente seja expandido e reduzido dinamicamente com base no espaço disponível podemos utilizar
flex: 1
;
Um componente só pode expandir para preencher o espaço disponível se seu pai tiver dimensões maiores que 0
.
Exemplo de layout com Flexbox:
import React from "react";
import { View } from "react-native";
const FlexDimensionsBasics = () => {
return (
<View style=>
<View style= />
<View style= />
<View style= />
</View>
);
};
export default FlexDimensionsBasics;
- Todas as outras propriedades do Flexbox estão disponíveis no React Native:
- Flex-Direction:
column
row
columnReverse
rowReverse
- Layout-Direction:
LTR
RTL
- Justify-Content: ****
flexStart
flexEnd
center
spaceBetween
spaceAround
spaceEvenly
- Align-Items:
stretch
flex-start
flex-end
center
baseline
- Align-Self e Align-Content
- Flex-Wrap, Flex-Basis, Grow e Shrink
- Row-Gap, Column-Gap e Gap
- Posição absoluta e relativa:
relative
absolute
- Flex-Direction:
3.4) Imagens
- O React Native fornece uma maneira unificada de gerenciar imagens e outros ativos de mídia em seus aplicativos Android e iOS;
Imagens Estáticas
- Para adicionar uma imagem estática, basta importar o componente
Image
import { Image } from "react-native";
- Depois é só chamar o componente de imagem e inserir o caminho do arquivo:
<Image source={require("./src/assets/imagem.png")} />
Observações:
- Podemos usar os sufixos
@2x
e@3x
para fornecer imagens para diferentes densidades de tela.
└── img
├── check.png
├── check@2x.png
└── check@3x.png
- E chamar a imagem normalmente:
<Image source={require("./img/check.png")} />
Imagens na Rede
- Também podemos exibir imagens que não estão no projeto
- Porém, ao contrário dos recursos estáticos, precisamos especificar as dimensões da imagem;
// CORRETO
<Image source=
style= />
// ERRADO
<Image source= />
Imagens de fundo (Background-Image)
- Para exibir imagens de fundo podemos usar o componente
<ImageBackground>
; - Ele tem as mesmas propriedades que o componente
<Image>
- Exemplo simples:
<ImageBackground source={...} style=>
<Text>Inside</Text>
</ImageBackground>
- Exemplo completo com imagem na rede:
import React from "react";
import { ImageBackground, StyleSheet, Text, View } from "react-native";
const image = { uri: "https://reactjs.org/logo-og.png" };
const App = () => (
<View style={styles.container}>
<ImageBackground source={image} resizeMode="cover" style={styles.image} />
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
},
image: {
flex: 1,
justifyContent: "center",
},
});
export default App;
3.5) Cores
- Os componentes no React Native são estilizados usando Javascript;
- As propriedades de cores geralmente correspondem à forma como o CSS funciona na web;
Cores em Hexadecimal
- É possível inserir cores conforme o padrão da web que é hexadecimal, como por exemplo:
#fafafa
#000000
#000
(abreviado)
Cores em RGB
- React Native tem suporte para cores em
rgb()
ergba()
'#f0f'
(#rgb)'#ff00ff'
(#rrggbb)'#f0ff'
(#rgba)'#ff00ff00'
(#rrggbbaa)'rgb(255, 0, 255)'
'rgb(255 0 255)'
'rgba(255, 0, 255, 1.0)'
'rgba(255 0 255 / 1.0)'
Cores Nomeadas
- No React Native, também podemos usar strings de nomes de cores como valores;
transparent
(Um atalho parargba(0,0,0,0)
)aliceblue, coral, green, blue, etc...
- A lista completa de cores pode ser acessada aqui
Cores em HSL
- Também é possível usar
hsl()
ehsla()
:'hsl(360, 100%, 100%)'
'hsl(360 100% 100%)'
'hsla(360, 100%, 100%, 1.0)'
'hsla(360 100% 100% / 1.0)'
Cores em Matriz (HWB)
- React Native suporta
hwb()
em notação funcional:'hwb(0, 0%, 100%)'
'hwb(360, 100%, 100%)'
'hwb(0 0% 0%)'
'hwb(70 50% 0%)'
4) Gestos e Toques
- Com o React Native é possível lidar com todos os tipos de gestos comuns;
4.1) Botões
- Um botão é um componente básico que é renderizado em todas as plataformas;
Botão simples
- Um exemplo básico é o botão:
<Button
onPress={() => {
console.log("O botão foi pressionado!");
}}
title="Toque aqui"
color="#841584"
/>
Componentes tocáveis (Touchables)
- Os componentes “tocáveis” podem capturar gestos de toque e exibir feedback;
<TouchableHighlight
onPress={() => {
console.log('O botão foi pressionado!');
}}
underlayColor="white">
<View>
<Text>TouchableHighlight</Text>
</View>
</TouchableHighlight>;
4.2) Navegação entre telas
- Aplicativos raramente são compostos de uma única tela.
- No React Native, a forma mais simples de criar a navegação entre telas e guias é usando o React Natigation;
React Navigation
- Primeiramente é preciso instalar a biblioteca:
npm install @react-navigation/native @react-navigation/native-stack
Dependências do React Navigation
- Se for um projeto React Native simples, instale as dependências com
npm
:
npm install react-native-screens react-native-safe-area-context
- Se for um projeto gerenciado pelo Expo, instale as dependências com
expo
:
npx expo install react-native-screens react-native-safe-area-context
Envolvendo a aplicação
- Agora precisamos envolver todo o aplicativo com o
NavigationContainer
. - Isso é feito no arquivo de entrada de nosso projeto, como
index.js
ouApp.js
:
import * as React from "react";
import { NavigationContainer } from "@react-navigation/native";
const App = () => {
return (
<NavigationContainer>{/* Restante da aplicação */}</NavigationContainer>
);
};
export default App;
Criando as telas
- Exemplo completo abaixo com 2 telas:
-
- Tela inicial (HomeScreen)
-
- Tela de perfil (ProfileScreen)
-
import * as React from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
const Stack = createNativeStackNavigator();
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options=
/>
<Stack.Screen
name="Profile"
component={ProfileScreen}
options=
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
Navegando entre as telas
- Cada tela
<Stack.Screen>
tem uma propriedade chamada:component
; - A propriedade
component
é uma referência a um componente React; - Esses componentes recebem uma propriedade chamada
navigation
; - O
navigation
possui vários métodos para vincular a outras telas;
Componente HomeScreen.jsx
const HomeScreen = ({ navigation }) => {
return (
<Button
title="Go to profile screen"
onPress={() => navigation.navigate("Profile", { name: "Jane" })}
/>
);
};
Componente ProfileScreen.jsx
const ProfileScreen = ({ navigation, route }) => {
return <Text>This is {route.params.name}'s profile</Text>;
};
5) Observações Expo
- Fluxos de trabalho no Expo
- Managed Workflow (padrão, sem acesso as pastas Android e iOS)
- Bare Workflow
- Development Builds
- Config Plugins
- Custom Clients
Parar mudar um fluxo Managed Workflow para Bare Workflow basta rodar o comando:
npx expo prebuild
https://docs.expo.dev/workflow/prebuild/
Configurar Build
https://docs.expo.dev/build/setup/
Gerar APK
https://docs.expo.dev/build-reference/apk/