Quando se começa a usar React Native, é fácil ter a sensação de que "funciona, mas sem entender bem por quê". Neste artigo, vamos explicar tudo o que acontece por baixo dos panos — de Metro, JSI, Codegen e como o Expo funciona, até a implementação nativa para áreas que o SDK do Expo não consegue cobrir.
1. A Filosofia Central do React Native
O coração do React Native é traduzir a lógica de UI escrita em JS para componentes UI nativos. Assim como o ReactDOM converte <div> em elementos DOM, o React Native mapeia <View> e <Text> para UIView no iOS e android.view.View no Android.
Isso significa que ele gera UI nativa real — não renderiza HTML em uma WebView. Essa é a diferença fundamental em relação ao Cordova ou Ionic.
2. Evolução da Arquitetura: De Bridge para JSI
O React Native atualmente tem duas arquiteturas coexistentes.
flowchart LR
subgraph OLD["Arquitetura Antiga (Bridge)"]
direction TB
J1["Thread JS<br/>Lógica React"] -->|"Serializar JSON"| BR["Bridge<br/>Fila assíncrona ⚠"]
BR -->|"Desserializar JSON"| N1["Thread Nativo<br/>UIKit / Android View"]
SH["Thread Shadow<br/>Layout Yoga"] --> N1
end
subgraph NEW["Nova Arquitetura (JSI)"]
direction TB
HM["Motor Hermes<br/>Execução bytecode"] -->|"Referência C++ direta"| JSI["JSI<br/>Host Objects"]
JSI --> FAB["Fabric<br/>Renderizador síncrono"]
JSI --> TM["TurboModules<br/>Inicialização lazy"]
FAB --> N2["Camada Nativa"]
TM --> N2
endProblemas da Arquitetura Antiga (Bridge)
O React Native legado fazia os threads JS e nativo se comunicarem através de um único gargalo assíncrono chamado Bridge. Cada troca precisava ser serializada como JSON, enviada e desserializada — tornando operações frequentes como animações e gestos propensas a problemas de desempenho.
Inovações da Nova Arquitetura (JSI + Hermes)
JSI (JavaScript Interface) é uma camada de binding delgada em C++ que permite ao motor JS referenciar objetos nativos diretamente e de forma síncrona. Isso possibilitou:
- Fabric — Um novo renderizador que constrói e atualiza árvores de UI sincronamente
- TurboModules — Inicialização lazy que adia o carregamento de módulos nativos até que sejam necessários
- Hermes — O motor do Facebook que pré-compila JS para bytecode, reduzindo drasticamente o tempo de inicialização
3. Codegen: A Chave para Comunicação Nativa com Segurança de Tipos
Codegen é o mecanismo mais negligenciado na nova arquitetura. Enquanto JSI e TurboModules tornam a comunicação possível, o Codegen garante que ela seja correta em tempo de compilação.
flowchart TD
SPEC["Arquivo JS Spec<br/>Definições de tipos em TypeScript / Flow"]
subgraph BUILD["Tempo de Compilação"]
CG["Codegen<br/>Executa durante pod install / Gradle"]
end
subgraph OUT["Artefatos Gerados"]
CPP["Classes C++ Abstratas<br/>Interfaces base TurboModule"]
DESC["Component Descriptor<br/>Para componentes nativos Fabric"]
JSTYPE["Definições de Tipos JS<br/>Equivalente a .d.ts"]
end
subgraph NATIVE["Implementação Nativa"]
IOS["iOS<br/>Implementado em Swift / Obj-C"]
AND["Android<br/>Implementado em Kotlin / Java"]
end
RUNTIME["Via JSI<br/>Seguro em tipos, chamadas síncronas"]
SPEC --> CG
CG --> CPP & DESC & JSTYPE
CPP --> IOS & AND
DESC --> IOS & AND
IOS --> RUNTIME
AND --> RUNTIMENa arquitetura antiga, a interface entre JS e nativo era essencialmente um "acordo de cavalheiros". Chamar NativeModules.MyModule.doSomething(42) do JS só geraria um erro ao ocorrer um crash em tempo de execução se o lado nativo esperasse uma String.
O Codegen resolve isso em tempo de compilação. Os desenvolvedores escrevem uma Spec (especificação) em TypeScript ou Flow descrevendo quais tipos um módulo nativo aceita. Durante pod install (iOS) ou a compilação Gradle (Android), o Codegen gera automaticamente classes C++ abstratas, andaime nativo para iOS e Android e definições de tipos JS.
4. O Pipeline do Metro Bundler
Metro é o bundler JavaScript dedicado do React Native. Cumpre o mesmo papel que o webpack, mas é otimizado para desenvolvimento móvel.
flowchart LR
SRC[".js / .ts / .tsx<br/>Arquivos fonte"]
RES["Resolução<br/>Resolução de caminhos de import"]
TRA["Transformação<br/>Transforms ES via Babel"]
SER["Serialização<br/>Geração do bundle"]
DEV["Entrega ao dispositivo<br/>HTTP :8081"]
HMR["HMR<br/>Reenviar apenas módulos alterados"]
CACHE["Cache FS<br/>Mais rápido a partir do 2° início"]
SRC --> RES --> TRA --> SER --> DEV
TRA -.->|"Detecção de mudança de arquivo"| HMR
HMR -.->|"Refletir sem perder o state"| DEV
TRA <-.->|"Cachear resultados transformados"| CACHEO pipeline do Metro tem três fases:
- Resolução — Resolução de módulos no estilo Node.js com seleção automática de arquivos específicos por plataforma (
foo.ios.ts/foo.android.ts) - Transformação — Babel converte JSX, TypeScript e ES moderno; resultados são cacheados para inícios mais rápidos
- Serialização — Gera o bundle final e o entrega ao dispositivo via servidor HTTP
Notavelmente, o HMR (Hot Module Replacement) atualiza apenas o grafo dos módulos alterados, refletindo mudanças de código imediatamente enquanto preserva o estado dos componentes React. Builds de produção combinam --minify e a compilação Hermes em bytecode para reduzir tanto o tamanho do arquivo quanto o tempo de inicialização.
5. A Estrutura em Camadas do Expo e as Ferramentas de Desenvolvimento
flowchart TD
APP["Seu App<br/>App.tsx / screens / hooks"]
SDK["Expo SDK<br/>expo-camera / expo-location / expo-router …"]
EMC["expo-modules-core<br/>DSL com segurança de tipos em Swift / Kotlin"]
RN["React Native Core<br/>View / Text / Animated / StyleSheet"]
IOS["iOS<br/>UIKit / AVFoundation / CoreLocation"]
AND["Android<br/>View / Camera2 / LocationManager"]
GO["Expo Go<br/>Iniciar instantaneamente via QR"]
EASB["EAS Build<br/>Gerar .ipa / .apk na nuvem"]
EASU["EAS Update<br/>Entregar apenas JS bundle via OTA"]
STORE["App Store / Google Play"]
APP --> SDK
EMC --> SDK
SDK --> RN
RN --> IOS & AND
GO -->|"Hospedar durante o dev"| APP
EASB --> STORE
EASU -->|"Sem revisão App Store"| APPO SDK do Expo fornece funcionalidades nativas — câmera, localização, notificações, sistema de arquivos — como pacotes versionados. Sem necessidade de escrever código nativo próprio — esse é seu maior valor.
expo-modules-core é um sistema mais novo que permite o desenvolvimento declarativo de módulos nativos com DSLs Swift e Kotlin, integrado ao Codegen. É mais seguro em tipos e menos verboso que o antigo bridge NativeModules, e quase todos os SDKs de terceiros do Expo o utilizam.
EAS (Expo Application Services) é um termo genérico para Build, Update, Submit, Workflows e mais. Este artigo foca em EAS Build e EAS Update. O EAS Build compila binários nativos na nuvem, possibilitando builds iOS sem Mac. O EAS Update entrega bundles JS e assets via OTA, permitindo entrega rápida de mudanças que não tocam código nativo.
6. Áreas que o Expo não Cobre e a Escolha do Workflow
Principais áreas que o SDK do Expo não cobre:
- Bluetooth LE / NFC — Comunicação com periféricos específicos da plataforma
- SDKs personalizados de pagamento/biometria — Integração direta de
.framework/.aarde fornecedores - Processamento de áudio/vídeo em tempo real — WebRTC de baixo nível ou operações com codecs personalizados
- Bibliotecas nativas internas — Assets Swift / Kotlin extraídos de apps existentes
- Views de câmera personalizadas — Renderização personalizada com OpenGL / Metal
flowchart TD
START["Qual funcionalidade nativa você precisa?"]
START --> Q1{"Coberta pelo SDK Expo<br/>ou biblioteca pública?"}
Q1 -->|"Sim"| MANAGED["Managed Workflow<br/>Sem código nativo necessário<br/>Apenas npx expo start"]
Q1 -->|"Não"| Q2{"Apenas mudanças de configuração?<br/>(Adições Info.plist / AndroidManifest)"}
Q2 -->|"Sim"| PLUGIN["Criar Config Plugin<br/>Adicionar ao app.json<br/>Aplicado automaticamente pelo prebuild"]
Q2 -->|"Não"| Q3{"Volume de código nativo personalizado?"}
Q3 -->|"Leve<br/>(wrapper de SDK existente)"| BARE["Bare Workflow<br/>npx expo prebuild<br/>→ Gerenciar ios/ android/ diretamente"]
Q3 -->|"Completo<br/>(módulo / UI personalizado)"| MODULE{"O que está sendo construído?"}
MODULE -->|"Lógica<br/>Bluetooth / pagamento / cripto"| TM["TurboModule<br/>+ Codegen"]
MODULE -->|"Componente UI<br/>View de câmera personalizada, etc."| FAB["Fabric Component<br/>+ Codegen"]
BARE --> TM & FAB
PLUGIN --> BAREMudanças de configuração menores podem ser tratadas com Config Plugins. Mas se for necessário escrever código, gerar os diretórios ios/ e android/ com npx expo prebuild e migrar para o Bare Workflow é o ponto de partida prático.
7. Arquitetura Completa: JSI + Codegen + Implementação Nativa
flowchart TB
subgraph JS["Camada JS (Hermes)"]
APP["Código do App / Componentes React"]
SPEC["JS Spec<br/>(TypeScript + TurboModuleRegistry)"]
end
subgraph CODEGEN["Codegen (Auto-gerado em tempo de compilação)"]
GEN_CPP["Classes C++ Abstratas<br/>TurboModule / ComponentDescriptor"]
GEN_SHADOW["Definições ShadowNode / Props"]
end
subgraph JSI_LAYER["Camada JSI (C++)"]
JSI["JSI Host Object"]
FABRIC["Fabric Renderer"]
end
subgraph NATIVE_IOS["Implementação Nativa iOS"]
SWIFT["Implementação Swift / Obj-C<br/>(Herda classe C++ abstrata)"]
SDK_IOS["SDK Interno / .framework Externo<br/>ex: CoreBluetooth / Stripe"]
UIVIEW["Subclasse UIView<br/>(Componente UI Personalizado)"]
end
subgraph NATIVE_AND["Implementação Nativa Android"]
KOTLIN["Implementação Kotlin / Java<br/>(Herda classe C++ abstrata)"]
SDK_AND["SDK Interno / .aar Externo<br/>ex: BluetoothGatt / Stripe"]
ANDROIDVIEW["Subclasse View<br/>(Componente UI Personalizado)"]
end
SPEC -->|"Leitura das definições de tipos"| CODEGEN
GEN_CPP --> JSI
GEN_SHADOW --> FABRIC
APP -->|"Chamadas síncronas / assíncronas"| JSI
JSI --> SWIFT & KOTLIN
FABRIC --> UIVIEW & ANDROIDVIEW
SWIFT --> SDK_IOS
KOTLIN --> SDK_ANDA chave está na dependência unidirecional: Spec → Codegen → Implementação Nativa. Escreva definições de tipos no lado JS, e o Codegen gera classes C++ abstratas em tempo de compilação. As implementações Swift / Kotlin só precisam heroá-las — a consistência de tipos é garantida pelo compilador, eliminando o "acordo de cavalheiros" como fonte de crashes em tempo de execução.
8. Fluxo de Implementação TurboModule (Exemplo Bluetooth)
Nota: O código a seguir é um exemplo simplificado baseado nos guias oficiais do React Native para TurboModule / Codegen / Custom Events. Não são citações diretas dos exemplos oficiais, mas uma reconstrução usando Bluetooth como exemplo.
① Escrever a JS Spec
// src/specs/NativeBluetoothModule.ts
import type { TurboModule, CodegenTypes } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export type ScanResult = {
id: string;
name: string;
rssi: number;
};
export interface Spec extends TurboModule {
startScan(serviceUUIDs: string[]): void;
stopScan(): void;
connect(deviceId: string): Promise<boolean>;
readonly onDeviceFound: CodegenTypes.EventEmitter<ScanResult>;
}
export default TurboModuleRegistry.getEnforcing<Spec>('NativeBluetoothModule');
② O que o Codegen Gera (Automaticamente)
flowchart LR
SPEC["NativeBluetoothModule.ts<br/>(Escrito pelo desenvolvedor)"]
subgraph AUTO["Código auto-gerado"]
CPP["Código C++ glue<br/>Saída JSI / Codegen"]
IOS_H["Código iOS glue<br/>Saída Obj-C++ / header"]
AND_J["Código Android glue<br/>Saída JNI / classe Spec"]
end
subgraph IMPL["Implementado pelo desenvolvedor"]
SWIFT_IMPL["NativeBluetoothModule.swift<br/>Implementa Spec gerada, chama CoreBluetooth"]
KOTLIN_IMPL["NativeBluetoothModule.kt<br/>Implementa Spec gerada, chama BluetoothGatt"]
end
SPEC --> CPP
SPEC --> IOS_H
SPEC --> AND_J
CPP --> SWIFT_IMPL & KOTLIN_IMPL
IOS_H --> SWIFT_IMPL
AND_J --> KOTLIN_IMPL③ Implementação iOS (Swift)
// ios/NativeBluetoothModule.swift
import CoreBluetooth
@objc(NativeBluetoothModule)
class NativeBluetoothModule: NativeBluetoothModuleSpec, CBCentralManagerDelegate {
private var centralManager: CBCentralManager!
override func startScan(_ serviceUUIDs: [String]) {
let uuids = serviceUUIDs.map { CBUUID(string: $0) }
centralManager.scanForPeripherals(withServices: uuids)
}
func centralManager(_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String: Any], rssi: NSNumber) {
emitOnDeviceFound([
"id": peripheral.identifier.uuidString,
"name": peripheral.name ?? "",
"rssi": rssi
])
}
}
④ Implementação Android (Kotlin)
// android/src/main/java/NativeBluetoothModule.kt
class NativeBluetoothModule(reactContext: ReactApplicationContext)
: NativeBluetoothModuleSpec(reactContext), BluetoothGatt.Callback {
private val adapter = BluetoothAdapter.getDefaultAdapter()
override fun startScan(serviceUUIDs: ReadableArray) {
val filters = serviceUUIDs.toArrayList().map { uuid ->
ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(uuid as String)).build()
}
adapter.bluetoothLeScanner.startScan(filters, ScanSettings.Builder().build(), scanCallback)
}
private val scanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val params = Arguments.createMap().apply {
putString("id", result.device.address)
putString("name", result.device.name ?: "")
putInt("rssi", result.rssi)
}
emitOnDeviceFound(params)
}
}
}
9. Fluxo de Implementação Fabric Component (Exemplo View de Câmera Personalizada)
Se TurboModule lida com a lógica, o Fabric Component serve para incorporar UI nativa no JSX. Necessário para renderização personalizada com OpenGL / Metal, ou reutilização de views nativas existentes.
Nota: O seguinte também é um exemplo mínimo para compreensão. Caminhos de import do Codegen e nomes de tipos variam conforme a versão do React Native, sempre consulte a documentação oficial da sua versão ao implementar.
// src/specs/NativeCameraViewSpec.ts
import type { ViewProps } from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
import type { DirectEventHandler, Float } from 'react-native/Libraries/Types/CodegenTypes';
type FrameCapturedEvent = Readonly<{
uri: string;
}>;
interface NativeProps extends ViewProps {
zoom?: Float; // Codegen mapeia Float → CGFloat / float
torchEnabled?: boolean;
onFrameCaptured?: DirectEventHandler<FrameCapturedEvent>;
}
export default codegenNativeComponent<NativeProps>('CameraView');
O Codegen gera definições C++ para ShadowNode, ComponentDescriptor e Props a partir desta Spec. No iOS, implemente um CameraViewComponentView herdando de RCTViewComponentView; no Android, herdar de ReactViewGroup. Do lado JS, é tão simples quanto <CameraView zoom={2.0} torchEnabled />.
10. Integração de SDKs Internos / .framework e .aar Externos
iOS: Referência Local via CocoaPods
# ios/Podfile
pod 'CompanyPaymentSDK', :path => '../vendor/ios/CompanyPaymentSDK'
# ou para xcframework
pod 'CompanyPaymentSDK', :podspec => '../vendor/ios/CompanyPaymentSDK.podspec'
Após adicionar ao Podfile e executar pod install, pode ser usado como uma classe Swift normal com import CompanyPaymentSDK. Chamar diretamente da implementação TurboModule.
Android: Maven Local / Referência .aar
// android/app/build.gradle
dependencies {
implementation files('../vendor/android/company-payment-sdk.aar')
// ou um repositório Maven interno
implementation 'com.company:payment-sdk:1.4.0'
}
11. O Loop de Desenvolvimento: Do Início à Verificação
flowchart TD
INIT["npx create-expo-app MyApp<br/>--template blank-typescript"]
subgraph START["npx expo start"]
METRO["Metro Bundler inicia<br/>porta 8081"]
QR["QR code + atalhos<br/>i = iOS a = Android w = Web"]
end
subgraph DEVICE["Escolher alvo"]
SIM["iOS Simulator<br/>Incluído com Xcode (apenas Mac)"]
EMU["Android Emulator<br/>Android Studio AVD"]
GO["Dispositivo físico + Expo Go<br/>Via LAN ou Tunnel"]
end
subgraph NATIVE_BUILD["Apenas na primeira vez: Build Nativo"]
POD["pod install<br/>iOS CocoaPods"]
GRADLE["Gradle build<br/>Android"]
CODEGEN_RUN["Codegen executa<br/>Spec → Andaime nativo"]
end
BUNDLE["Transferir JS bundle ao dispositivo<br/>via servidor HTTP do Metro"]
RENDER["Tela é exibida"]
INIT --> START
METRO --> QR
QR --> SIM & EMU & GO
SIM --> NATIVE_BUILD
EMU --> NATIVE_BUILD
NATIVE_BUILD --> BUNDLE
GO --> BUNDLE
BUNDLE --> RENDERExecute npx expo start para iniciar o Metro, e um QR code com atalhos de teclado aparece no terminal.
- Tecla
i→ iOS Simulator (funciona no Mac com Xcode instalado) - Tecla
a→ Android Emulator (dispositivo virtual criado no Android Studio AVD Manager) - Para dispositivos físicos, escanear o QR no Expo Go — conecta quase instantaneamente em LAN
Ao acionar explicitamente um build nativo com npx expo run:ios ou npx expo run:android, pod install (iOS) ou Gradle (Android) é executado pela primeira vez e o Codegen gera o andaime nativo. Execuções posteriores transferem apenas diferenças do JS bundle e são muito mais rápidas.
12. O Loop de Mudanças no Bare Workflow
flowchart TD
subgraph CHANGE["Ramificação por tipo de mudança"]
JS_ONLY["Apenas mudanças JS<br/>Componentes / lógica / estilos"]
NATIVE_CHANGE["Mudanças de código nativo<br/>Swift / Kotlin / Spec / Podfile"]
end
subgraph JS_LOOP["Loop de Mudança JS (Rápido)"]
METRO_HMR["Metro HMR<br/>Transferir bundle diferencial<br/>~Centenas de ms"]
SIM_JS["Visível imediatamente no emulador<br/>Estado do app preservado"]
end
subgraph NATIVE_LOOP["Loop de Mudança Nativo (Lento)"]
CODEGEN_RUN["Re-executar Codegen<br/>pod install (iOS)<br/>Gradle sync (Android)"]
REBUILD["Rebuild nativo<br/>npx expo run:ios<br/>npx expo run:android"]
SIM_NATIVE["Verificar no emulador / dispositivo"]
end
JS_ONLY --> METRO_HMR --> SIM_JS
NATIVE_CHANGE --> CODEGEN_RUN --> REBUILD --> SIM_NATIVE
SIM_JS -->|"Sem problemas"| DONE["Verificação OK"]
SIM_NATIVE -->|"Sem problemas"| DONE
SIM_JS -->|"Bug encontrado"| DEBUG_JS["Hermes Debugger<br/>React DevTools"]
SIM_NATIVE -->|"Crash nativo"| DEBUG_NATIVE["Xcode / Android Studio<br/>Depurador nativo"]
DEBUG_JS --> JS_ONLY
DEBUG_NATIVE --> NATIVE_CHANGEMudanças apenas de JS são tratadas pelo Metro HMR em centenas de milissegundos, preservando o estado.
Mudanças de código nativo exigem um rebuild. O primeiro build iOS leva 2–5 minutos, builds diferenciais cerca de 30 segundos a um minuto. Android com cache Gradle é similar; o primeiro build leva mais tempo.
Essa assimetria é a chave para a eficiência de desenvolvimento no Bare Workflow: fixar cedo o limite nativo (Spec) e empurrar a maior parte da implementação para o lado JS para reduzir a frequência de builds nativos pesados.
13. Depuração: Investigação Através do Limite JS/Nativo
flowchart TD
SYMPTOM["Observar sintomas"]
SYMPTOM --> Q1{"Tipo de crash"}
Q1 -->|"Erro JS<br/>Tela vermelha LogBox"| JS_ERR["Investigar com Hermes Debugger<br/>Breakpoints, stack trace<br/>Números de linha TS via Source Map"]
Q1 -->|"Crash nativo<br/>App congela / crasha"| NAT_ERR["Verificar logs de crash"]
Q1 -->|"Funciona mas<br/>resultado errado"| BORDER["Suspeitar do limite JS↔Nativo"]
NAT_ERR --> IOS_CRASH["iOS: Xcode<br/>Debug Navigator<br/>+ anexar lldb"]
NAT_ERR --> AND_CRASH["Android: Android Studio<br/>Stack trace Logcat<br/>+ Native Debugger"]
BORDER --> LOG_IOS["iOS: NSLog / os_log<br/>npx react-native log-ios"]
BORDER --> LOG_AND["Android: Log.d<br/>npx react-native log-android"]
BORDER --> JS_LOG["Lado JS: console.log<br/>Verificar valores de retorno TurboModule"]
IOS_CRASH --> INSTRUMENTS["Instruments<br/>Time Profiler / Allocations<br/>Identificar vazamentos de memória / CPU"]
AND_CRASH --> PROFILER["Android Studio<br/>Memory / CPU Profiler"]
JS_ERR --> FIXED["Corrigir → Visível via Metro HMR"]
INSTRUMENTS --> FIXED2["Corrigir → Verificar com npx expo run:ios"]
PROFILER --> FIXED3["Corrigir → Verificar com npx expo run:android"]
LOG_IOS & LOG_AND & JS_LOG --> BORDER2["Identificar causa raiz<br/>→ Corrigir Spec / implementação"]Erros JS: Hermes Debugger
Cmd+D → "Open Debugger" abre o Chrome DevTools. O Metro fornece Source Maps, permitindo colocar breakpoints nos números de linha TypeScript originais — não no código bundleado. Exceções em chamadas TurboModule mostram o stack completo de volta ao lado JS.
Crashes Nativos: Anexar Depurador do Xcode / Android Studio
# iOS: Anexar lldb ao simulador em execução
npx expo run:ios --configuration Debug
# → Xcode abre automaticamente e anexa o depurador
# Android
npx expo run:android
# → "Run > Attach Debugger to Android Process"
Para crashes que só se reproduzem em dispositivos físicos (especialmente Bluetooth, câmera, sensores), o depurador pode ser anexado da mesma forma a um dispositivo conectado via USB.
Investigação de Limite: Encapsular com Logs
Quando dados são corrompidos no limite JS↔Nativo, encapsulá-los com logs de ambos os lados é a abordagem mais rápida.
// Lado Swift
os_log("BluetoothModule.connect called: %{public}@", deviceId)
// → Filtrar com npx react-native log-ios
// Lado Kotlin
Log.d("BluetoothModule", "connect called: $deviceId")
// → Filtrar com npx react-native log-android
// Lado JS
const result = await BluetoothModule.connect(deviceId);
console.log('connect result:', result); // Saída no Metro
React DevTools
npx react-devtools
# → Aguarda conexão do dispositivo na porta 8097
Visualize a árvore de componentes e inspecione (e modifique) props e state em tempo real.
14. Simuladores vs. Dispositivos Físicos
| O que está sendo testado | iOS Simulator | Android Emulator | Dispositivo Físico |
|---|---|---|---|
| UI / Layout | Suficiente | Suficiente | Verificação final |
| Lógica JS / API | Suficiente | Suficiente | Não necessário |
| Bluetooth / NFC | Impossível | Impossível | Obrigatório |
| Câmera / Microfone | Parcial | Impossível | Obrigatório |
| Notificações push | Parcial | Parcial | Recomendado |
| Performance | Apenas referência | Apenas referência | Obrigatório |
| Autenticação biométrica | Sim Face ID disponível | Sim impressão digital disponível | Recomendado |
Para desenvolvimento com módulos nativos, uma abordagem em duas etapas funciona bem: consolidar o comportamento JS nos emuladores, verificar funcionalidades nativas em dispositivos físicos. Especialmente para Bluetooth e NFC — já que emuladores não conseguem testá-los — o número de dispositivos e a cobertura de versões de SO impacta diretamente a qualidade.
Resumo
O Stack Tecnológico Completo
| Camada | Tecnologia | Papel |
|---|---|---|
| Bundler | Metro | Transpilação de fontes, HMR, ramificação por plataforma |
| Motor JS | Hermes | Execução bytecode para inicialização rápida |
| Bridge JS↔Nativo | JSI | Binding síncrono via C++ |
| Geração de Código | Codegen | Auto-geração de andaime nativo com segurança de tipos a partir da Spec |
| Renderizador UI | Fabric | Renderização de UI síncrona sobre JSI |
| APIs Nativas | TurboModules | Módulos com inicialização lazy herdando classes geradas pelo Codegen |
| Infraestrutura Dev | Expo / EAS | SDK, builds na nuvem, atualizações OTA |
Fluxo Completo para Implementação Nativa
① Escrever a JS Spec (definições de tipos em TypeScript)
↓
② pod install / gradle build → Codegen auto-gera andaime C++
↓
③ Implementar em Swift / Kotlin (chamar SDK interno / bibliotecas externas)
↓
④ npx expo run:ios / run:android → Build nativo & verificação no emulador
↓
⑤ Escrever código de chamada JS → Iteração rápida via Metro HMR
↓
⑥ Erros JS → Hermes Debugger
Crashes nativos → Depurador Xcode / Android Studio
Discrepâncias no limite → Encapsular com log-ios / log-android + console.log
↓
⑦ Verificar Bluetooth / câmera / sensores em dispositivos físicos
↓
⑧ EAS Build gera binários prontos para as lojas
A transição do React Native de Bridge para JSI + Codegen o transformou de "funciona mas frágil" para "com segurança de tipos e alto desempenho". Sair do Expo traz custos — builds pesados e escrever a mesma lógica em duas linguagens — mas o Codegen torna a Spec a única fonte da verdade, eliminando o maior risco: crashes em tempo de execução por incompatibilidades de tipos, já na fase de design.
URLs de Referência
Nota: Este artigo resume e reconstrói informações das seguintes fontes. Exemplos e explicações foram simplificados para maior clareza e não são citações diretas. Sempre consulte a documentação oficial da versão que está usando ao implementar.
URLs Referenciadas
React Native Oficial
- React Native Nova Arquitetura (Visão Geral): https://reactnative.dev/architecture/landing-page
- Visão Geral JSI & TurboModules: https://reactnative.dev/docs/turbo-native-modules-introduction
- O que é Codegen: https://reactnative.dev/docs/the-new-architecture/what-is-codegen
- Como usar Codegen: https://reactnative.dev/docs/the-new-architecture/using-codegen
- Enviando eventos de TurboModules: https://reactnative.dev/docs/the-new-architecture/native-modules-custom-events
- Apêndice de definições de tipos Codegen: https://reactnative.dev/docs/appendix
- Motor Hermes: https://reactnative.dev/docs/hermes
- Metro (React Native oficial): https://reactnative.dev/docs/metro
Expo Oficial
- Por que Metro (Expo): https://docs.expo.dev/guides/why-metro/
- Usando Hermes (Expo): https://docs.expo.dev/guides/using-hermes/
- Visão Geral EAS: https://docs.expo.dev/eas/
- Visão Geral EAS Build: https://docs.expo.dev/build/introduction/
- Visão Geral EAS Update: https://docs.expo.dev/eas-update/introduction/
