Claude Code y React Native: guia practica de Expo, nativo y release
Usa Claude Code con React Native: Expo vs bare, permisos, errores de Metro, emuladores, accesibilidad y release.
Define el limite movil antes de pedir codigo
Claude Code aporta valor en React Native porque no solo genera una pantalla. Puede leer el proyecto, editar TypeScript, ejecutar comandos de verificacion, explicar si hace falta reconstruir la parte nativa y entregar una nota final con lo que se comprobo. Eso importa porque el desarrollo movil cruza mas fronteras que un componente web: permisos de iOS, package de Android, resolucion de Metro, development builds, emuladores, accesibilidad y controles de release.
La peticion debil es “crea una app React Native”. La peticion util dice si el proyecto usa Expo, si necesita un Expo development build, o si es un proyecto bare React Native donde el equipo mantiene ios/ y android/. Tambien fija los archivos editables, los comandos que requieren confirmacion y la plataforma que se debe probar.
Como base oficial uso Claude Code overview, Claude Code permissions, Expo documentation, Expo development builds, React Native environment setup, React Native Native Modules, Metro troubleshooting y React Native accessibility. Si tu equipo aun esta empezando, revisa antes la guia de inicio de Claude Code y despues la guia de permisos.
Empieza con un project map
Un project map es una breve guia operativa para el agente. El harness, o andamiaje del agente, le dice a Claude Code donde puede moverse, como se valida el resultado y que acciones no debe ejecutar automaticamente. Sin esto, puede producir codigo que compila, pero pasar por alto una reconstruccion nativa, una diferencia iOS/Android o una restriccion de release.
flowchart LR
A["Project map"] --> B["Claude Code task"]
B --> C["JS/TS implementation"]
B --> D["Native config"]
C --> E["Metro and unit tests"]
D --> F["Dev build / emulator"]
E --> G["Accessibility check"]
F --> G
G --> H["Release checklist"]
Antes de implementar, deja un archivo pequeno como este:
# React Native task map
App type: Expo app using TypeScript and Expo Router.
Native runtime: Expo Go for pure JS changes, development build for native libraries.
Targets: Android emulator first, iOS simulator on macOS before release.
Allowed files: app/, components/, hooks/, app.config.ts, metro.config.js, __tests__/.
Do not change: package manager, app slug, bundle identifiers, signing files, .env files.
Verification: npm run lint, npm test, npx expo-doctor, Android emulator smoke test.
Handoff: list changed files, commands run, platform not tested, and any native rebuild needed.
Las plantillas actuales de Expo pueden incluir contexto para agentes de codigo, pero las apps existentes suelen mezclar README viejos, supuestos de SDK antiguos y ajustes nativos sin documentar. Haz que Claude Code lea el repositorio real antes de cambiarlo.
Elige Expo o bare React Native con intencion
La documentacion de React Native separa el desarrollo con framework del flujo donde configuras Android Studio y Xcode directamente. En la practica, Expo suele ser el camino mas rapido para apps nuevas. Bare React Native sigue siendo necesario cuando ya existen SDK nativos, Gradle complejo, Pods personalizados o requisitos de un proveedor.
| Decision | Expo encaja mejor | Bare React Native encaja mejor |
|---|---|---|
| Velocidad inicial | MVP, herramientas internas, aprendizaje, funciones cubiertas por Expo SDK | Hay que conservar codigo iOS/Android existente |
| Funciones nativas | Camera, SecureStore, notificaciones y ajustes soportados por config plugins | SDK propio, terminales de pago, Bluetooth especial, build muy personalizado |
| Alcance para Claude Code | app/, components/, app.config.ts, tests | ios/, android/, Codegen, Pods, Gradle, artefactos generados |
| Verificacion | Expo Go o development build, npx expo-doctor | npm run android, pod install, Xcode y Android Studio |
No trates Expo Go como prueba de release. Expo lo describe como un entorno rapido con un conjunto fijo de librerias nativas. Si agregas una libreria con codigo nativo, usa un development build y pide a Claude Code que informe si hace falta un binario nuevo.
Para un proyecto Expo limpio:
npx create-expo-app@latest rn-claude-lab
cd rn-claude-lab
npx expo install expo-camera expo-secure-store @react-native-community/netinfo
npm install --save-dev @testing-library/react-native jest-expo @types/jest
npx expo start
Pulsa a para Android Emulator o i para iOS Simulator en macOS. Si la red local bloquea el dispositivo, npx expo start --tunnel puede ayudar, aunque sera mas lento.
Ajusta permisos de Claude Code para trabajo movil
En React Native, un solo comando puede crear un cambio enorme. expo prebuild, pod install, gradlew clean y eas build son validos en la tarea correcta, pero no deberian ejecutarse en silencio durante un cambio pequeno de UI.
Claude Code permite separar reglas allow, ask y deny. Un .claude/settings.json compartido puede permitir verificaciones seguras, pedir confirmacion antes de regenerar nativo o lanzar builds, y bloquear secretos o comandos de publicacion.
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(npm test)",
"Bash(npm run lint)",
"Bash(npx expo-doctor)",
"Bash(adb devices)"
],
"ask": [
"Edit",
"Bash(npx expo prebuild*)",
"Bash(eas build*)",
"Bash(cd ios && bundle exec pod install)"
],
"deny": [
"Read(.env)",
"Read(.env.local)",
"Bash(git push*)",
"Bash(rm -rf*)"
]
}
}
Esto no es desconfianza. Es una forma de mantener los efectos secundarios moviles dentro de una revision clara. Si la tarea necesita reconstruccion nativa, Claude Code debe decirlo antes de ampliar el diff.
Implementa una pantalla con permiso de camara
El primer caso practico es un lector QR para check-in, inventario o herramientas internas. Expo Camera expone CameraView y useCameraPermissions. Pide a Claude Code que modele tres estados: permiso cargando, permiso no concedido y camara lista. Exige tambien etiquetas accesibles y proteccion contra lecturas duplicadas.
// components/CameraQrCheck.tsx
import { CameraView, useCameraPermissions } from 'expo-camera';
import { useState } from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';
type ScanResult = {
data: string;
type: string;
} | null;
export function CameraQrCheck() {
const [permission, requestPermission] = useCameraPermissions();
const [scan, setScan] = useState<ScanResult>(null);
if (!permission) {
return (
<View style={styles.center}>
<Text>Checking camera permission...</Text>
</View>
);
}
if (!permission.granted) {
return (
<View style={styles.center}>
<Text style={styles.title}>Camera access is required</Text>
<Text style={styles.body}>
Allow camera access to scan QR codes on this device.
</Text>
<Pressable
accessibilityRole="button"
accessibilityLabel="Allow camera access"
disabled={!permission.canAskAgain}
onPress={requestPermission}
style={({ pressed }) => [
styles.button,
pressed && styles.buttonPressed,
!permission.canAskAgain && styles.buttonDisabled,
]}
>
<Text style={styles.buttonText}>Allow camera</Text>
</Pressable>
</View>
);
}
return (
<View style={styles.container}>
<CameraView
style={styles.camera}
barcodeScannerSettings={{ barcodeTypes: ['qr'] }}
onBarcodeScanned={
scan
? undefined
: ({ data, type }) => {
setScan({ data, type });
}
}
/>
<View style={styles.result}>
<Text accessibilityLiveRegion="polite" style={styles.title}>
{scan ? `Scanned ${scan.type}` : 'Point the camera at a QR code'}
</Text>
{scan ? <Text selectable>{scan.data}</Text> : null}
{scan ? (
<Pressable
accessibilityRole="button"
accessibilityLabel="Scan another QR code"
onPress={() => setScan(null)}
style={styles.button}
>
<Text style={styles.buttonText}>Scan again</Text>
</Pressable>
) : null}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#111827' },
center: { flex: 1, justifyContent: 'center', gap: 12, padding: 24 },
camera: { flex: 1 },
result: { gap: 12, padding: 16, backgroundColor: '#f9fafb' },
title: { fontSize: 18, fontWeight: '700', color: '#111827' },
body: { fontSize: 15, lineHeight: 22, color: '#374151' },
button: {
alignItems: 'center',
borderRadius: 8,
backgroundColor: '#2563eb',
paddingHorizontal: 16,
paddingVertical: 12,
},
buttonPressed: { opacity: 0.75 },
buttonDisabled: { backgroundColor: '#9ca3af' },
buttonText: { color: '#ffffff', fontWeight: '700' },
});
El componente se puede copiar en un proyecto Expo despues de instalar expo-camera. El texto de permisos y la configuracion nativa deben vivir en app config, porque algunos cambios requieren reconstruir la app nativa.
// app.config.ts
import type { ConfigContext, ExpoConfig } from 'expo/config';
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
name: config.name ?? 'rn-claude-lab',
slug: config.slug ?? 'rn-claude-lab',
ios: {
...config.ios,
bundleIdentifier: 'com.example.rnclaudelab',
infoPlist: {
...config.ios?.infoPlist,
NSCameraUsageDescription: 'Scan QR codes for check-in.',
},
},
android: {
...config.android,
package: 'com.example.rnclaudelab',
permissions: ['CAMERA'],
},
plugins: ['expo-camera'],
});
Los config plugins de Expo aplican configuracion nativa durante prebuild y builds nativos. La instruccion clave para Claude Code es: “si editas app.config.ts, reporta si hace falta un development build”.
Trata errores de Metro como evidencia
El segundo caso es Unable to resolve module, especialmente en monorepos. La guia oficial de Metro incluye reset de cache, pero eso no sustituye un diagnostico.
Entrega a Claude Code el error completo, comando ejecutado, package manager, layout del workspace y ultimo archivo movido. En una app Expo dentro de un workspace puede hacer falta:
// metro.config.js
const path = require('path');
const { getDefaultConfig } = require('expo/metro-config');
const projectRoot = __dirname;
const workspaceRoot = path.resolve(projectRoot, '..');
const config = getDefaultConfig(projectRoot);
config.watchFolders = [workspaceRoot];
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, 'node_modules'),
path.resolve(workspaceRoot, 'node_modules'),
];
module.exports = config;
No lo agregues a ciegas. Una app Expo normal de un solo paquete normalmente no lo necesita. Pide a Claude Code que explique por que watchFolders es necesario y que lo evite si el problema real es mayusculas/minusculas, dependencia faltante, Babel obsoleto o import incorrecto.
Planifica modulos nativos antes de editar nativo
El tercer caso es conectar un SDK de proveedor o una API del sistema. La guia actual de Native Modules se centra en Turbo Native Modules y Codegen. Por eso conviene fijar primero la superficie TypeScript y despues pasar a Android e iOS.
Si Camera, SecureStore o NetInfo de Expo cubren el caso, no escribas un modulo nativo propio. Si tienes un terminal de pago, Bluetooth especial o SDK interno de autenticacion, pide primero un plan.
Implement a native bridge plan, not the full code yet.
Goal: expose a device serial reader to TypeScript.
First output:
1. TypeScript interface and error model.
2. Android/iOS files that would need edits.
3. Build commands for each platform.
4. Risks: permissions, threading, simulator limitations, release signing.
Do not edit ios/ or android/ until the plan is reviewed.
Esto parece mas lento al principio, pero reduce mucho el coste de revision. Kotlin, Swift, Pods y Gradle deben cambiarse con una frontera clara.
Incluye tests y accesibilidad en la misma tarea
Las APIs de accesibilidad de React Native alimentan tecnologias como VoiceOver y TalkBack. Si una vista debe ser accesible, label y role son parte de la implementacion.
Empieza fijando el estado sin permiso:
// __tests__/CameraQrCheck.test.tsx
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react-native';
import { CameraQrCheck } from '../components/CameraQrCheck';
const mockRequestPermission = jest.fn();
jest.mock('expo-camera', () => ({
CameraView: 'CameraView',
useCameraPermissions: () => [
{ granted: false, canAskAgain: true },
mockRequestPermission,
],
}));
describe('CameraQrCheck', () => {
beforeEach(() => {
mockRequestPermission.mockClear();
});
it('requests camera permission from the empty state', () => {
render(<CameraQrCheck />);
fireEvent.press(screen.getByText('Allow camera'));
expect(mockRequestPermission).toHaveBeenCalledTimes(1);
});
});
Luego prueba en dispositivo o emulador: dialogo de permiso, ruta de rechazo, rotacion, lectura con poca luz y etiquetas de lector de pantalla. El handoff debe decir que plataforma se probo. “Android emulator passed, iOS not tested” sirve; “looks good” no.
Convierte el release check en comandos
Dev Menu y LogBox son herramientas de desarrollo; los builds de release se comportan distinto. Claude Code debe devolver evidencia de comandos.
npm run lint
npm test -- --runInBand
npx expo-doctor
npx expo start -c
adb devices
adb shell input keyevent 82
npx expo run:android
# macOS only:
npx expo run:ios
Con EAS Build, separa development, preview y production. No dejes que Claude Code cambie bundle identifiers, Android package, signing files o perfiles production si la tarea no lo pide.
Casos de uso y fallos reales
El primer caso es un MVP nuevo en Expo: login, QR, almacenamiento seguro, API simple y una pantalla interna. Divide el trabajo en screens, hooks, tests y config. Si hay monetizacion, incluye analytics y CTA en la definicion de terminado.
El segundo es corregir una app bare existente. Errores de Metro, crashes solo en Android, texto de permisos en iOS y upgrades de SDK nativo funcionan bien con Claude Code si exiges clasificacion del error, diff minimo y nota de reconstruccion nativa.
El tercero es investigar antes de integrar un SDK nativo. Pagos, salud, Bluetooth y autenticacion empresarial merecen una tabla con versiones de OS, permisos, riesgo de store review, limites de simulador y dispositivos de prueba. Combinalo con el review workflow checklist y la guia TDD.
Los fallos se repiten: Expo Go no prueba release, resetear cache no es analisis de causa raiz, la verificacion iOS/Android no puede esperar al final, la accesibilidad no se agrega despues, y los comandos nativos necesitan una razon.
CTA: convierte el flujo en plantilla
En React Native, lo que mas rinde es reutilizar project map, permisos, comandos de verificacion y checklist de review. Si trabajas solo, empieza con la chuleta gratuita. Para prompts y material de setup reutilizable, revisa ClaudeCodeLab products. Si tu equipo necesita reglas Expo/bare React Native, CI, release gates y formacion en un repo real, usa Claude Code training and consultation.
Tambien puedes comparar con la guia de React con Claude Code y la guia Flutter/Dart.
Tras probar este flujo, Masa encontro tres habitos que redujeron mas retrabajo: decidir Expo vs bare antes de implementar, pedir una nota de development build cuando cambia app.config.ts, y verificar permisos y Metro primero en Android Emulator. En funciones nativas como Camera y SecureStore, la frontera de verificacion importa mas que la velocidad de generacion.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Workflow de Obsidian a CLAUDE.md con Claude Code
Convierte notas de trabajo de Obsidian en notas operativas de CLAUDE.md para no repetir contexto.
Claude Code Revenue CTA Routing: de artículos a PDF, Gumroad y consulta
Un flujo con Claude Code para dirigir lectores a PDF gratis, Gumroad o consulta según intención.
Reglas de handoff para equipos con Claude Code: evidencia, permisos, rollback e ingresos
Formato práctico para entregar trabajo de Claude Code con pruebas, permisos, rollback, PDF gratis, Gumroad y consulta.