Código Específico da Plataforma
Platform.OS, Platform.select, e extensões de arquivo .ios/.android.
Busque em todas as páginas da documentação
Platform.OS, Platform.select, e extensões de arquivo .ios/.android.
Cartão de receita de referência rápida - pronto para copiar e colar.
import { Platform, StyleSheet, Text, View } from "react-native";
const HEADER_HEIGHT = Platform.select({ ios: 44, android: 56, default: 48 });
export function ScreenHeader({ title }: { title: string }) {
return (
<View style={styles.header}>
<Text style={styles.title}>{title}</Text>
</View>
);
}
const styles = StyleSheet.create({
header: {
height: HEADER_HEIGHT,
paddingTop: Platform.OS === "ios" ? 4 : 0,
backgroundColor: Platform.select({ ios: "#f8f8f8", android: "#6200ee" }),
justifyContent: "center",
paddingHorizontal: 16,
},
title: {
fontSize: 17,
fontWeight: Platform.select({ ios: "600", android: "500" }),
color: Platform.OS === "android" ? "#fff" : "#000",
},
});Quando usar isso: Pequenas diferenças de estilo ou constantes entre iOS e Android em um único arquivo de componente compartilhado.
// AppButton.tsx - entrada compartilhada; o Metro resolve arquivos de plataforma automaticamente
import { AppButton } from "./components/AppButton";
export default function CheckoutScreen() {
return (
<AppButton
label="Pagar agora"
onPress={() => console.log("checkout")}
/>
);
}// components/AppButton.tsx - API compartilhada, reexporta implementação da plataforma
export { AppButton } from "./AppButton.native";
export type { AppButtonProps } from "./AppButton.types";// components/AppButton.types.ts
export interface AppButtonProps {
label: string;
onPress: () => void;
disabled?: boolean;
}// components/AppButton.native.tsx - fallback para plataformas não divididas
import { Platform } from "react-native";
import { AppButtonIos } from "./AppButton.ios";
import { AppButtonAndroid } from "./AppButton.android";
export function AppButton(props: import("./AppButton.types").AppButtonProps) {
return Platform.OS === "android" ? (
<AppButtonAndroid {...props} />
) : (
<AppButtonIos {...props} />
);
}// components/AppButton.ios.tsx
import { Pressable, StyleSheet, Text } from "react-native";
import type { AppButtonProps } from "./AppButton.types";
export function AppButtonIos({ label, onPress, disabled }: AppButtonProps) {
return (
<Pressable
onPress={onPress}
disabled={disabled}
style={({ pressed }) => [
styles.button,
pressed && styles.pressed,
disabled && styles.disabled,
]}
>
<Text style={styles.label}>{label}</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
button: {
backgroundColor: "#007aff",
borderRadius: 10,
minHeight: 44,
alignItems: "center",
justifyContent: "center",
paddingHorizontal: 20,
},
pressed: { opacity: 0.7 },
disabled: { opacity: 0.4 },
label: { color: "#fff", fontSize: 17, fontWeight: "600" },
});// components/AppButton.android.tsx
import { Pressable, StyleSheet, Text } from "react-native";
import type { AppButtonProps } from "./AppButton.types";
export function AppButtonAndroid({ label, onPress, disabled }: AppButtonProps) {
return (
<Pressable
onPress={onPress}
disabled={disabled}
android_ripple={{ color: "rgba(255,255,255,0.3)" }}
style={[styles.button, disabled && styles.disabled]}
>
<Text style={styles.label}>{label}</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
button: {
backgroundColor: "#6750a4",
borderRadius: 4,
minHeight: 48,
alignItems: "center",
justifyContent: "center",
paddingHorizontal: 24,
elevation: 2,
},
disabled: { opacity: 0.4 },
label: { color: "#fff", fontSize: 15, fontWeight: "500", textTransform: "uppercase" },
});// utils/share.ts - módulo compartilhado com Platform.select para comportamento
import { Platform, Share } from "react-native";
export async function shareUrl(url: string, message: string) {
if (Platform.OS === "web") {
if (navigator.share) {
await navigator.share({ title: message, url });
return;
}
await navigator.clipboard.writeText(url);
return;
}
await Share.share(
Platform.select({
ios: { url, message },
android: { message: `${message}\n${url}` },
default: { message: `${message} ${url}` },
})!
);
}O que isso demonstra:
Platform.select para diferenças de constantes e de payload do Share.share em um arquivo.ios.tsx / .android.tsx para cromos de botão materialmente diferentesAppButton.types.ts compartilhado mantendo um único contrato de props público.ios.js / .android.js / .native.js / .jsPlatform.OS === "web" para targets web do Expo sem um arquivo web separado.ios.tsx → .native.tsx → .tsx (no simulador/dispositivo iOS).Platform.OS é uma string em tempo de execução lida na thread JS - seguro dentro de renderizações e manipuladores.Platform.select retorna a chave de plataforma correspondente ou default - pode retornar objetos, números ou funções..ios.tsx.Platform.Version com detecção de recursos.| Importação | Bundle iOS carrega | Bundle Android carrega |
|---|---|---|
./Foo | Foo.ios.tsx → Foo.native.tsx → Foo.tsx | Foo.android.tsx → Foo.native.tsx → Foo.tsx |
./Foo.ios | Arquivo iOS explícito apenas | N/A a menos que importado |
.native.tsx executa em iOS e Android, mas não em web quando um irmão .web.tsx existe..web.tsx é escolhido para exports web do Expo.// Forma de objeto - escolher um valor
const font = Platform.select({ ios: "System", android: "Roboto", default: "sans-serif" });
// Forma de função - preguiçoso por plataforma
const createStyles = Platform.select({
ios: () => StyleSheet.create({ card: { shadowOpacity: 0.2 } }),
android: () => StyleSheet.create({ card: { elevation: 4 } }),
});
// Ternário inline - bom para props de uso único
paddingTop: Platform.OS === "ios" ? 8 : 0,| Abordagem | Melhor para | Evitar quando |
|---|---|---|
Platform.select em StyleSheet | Cores, alturas, pesos de fonte | Componentes inteiros diferem |
Platform.OS if/else | Lógica condicional, retornos antecipados | Muitos blocos JSX duplicados |
Arquivos .ios / .android | Grandes UIs ou wrappers de módulos nativos | Ajuste de cor de uma linha |
*.web.tsx | APIs DOM específicas da web do Expo | Apps apenas para celular sem target web |
import { Platform } from "react-native";
const iosVersion =
Platform.OS === "ios" ? parseInt(String(Platform.Version), 10) : 0;
const androidApi =
Platform.OS === "android" ? Platform.Version : 0;
const supportsBlur = iosVersion >= 13 || androidApi >= 31;Platform.Version no iOS é uma string como "17.0" - analise antes da comparação numérica.34).import { Platform, type PlatformOSType } from "react-native";
type MobileOS = Extract<PlatformOSType, "ios" | "android">;
function isMobile(os: PlatformOSType): os is MobileOS {
return os === "ios" || os === "android";
}
// O retorno de Platform.select pode ser undefined - forneça um padrão
const height = Platform.select({ ios: 44, android: 56 }) ?? 48;
// Compartilhe módulos específicos da plataforma com exports idênticos
export type { AppButtonProps } from "./AppButton.types";PlatformOSType inclui "web" no Expo - estreite antes de usar APIs apenas para mobile.Platform.select sem default pode retornar undefined - use fallback ??..types.ts neutro importado por todas as variantes de plataforma.Dividir arquivos muito cedo - Três diferenças de cor de uma linha não precisam de arquivos .ios e .android. Correção: Use Platform.select até que o JSX divirja materialmente.
Importar arquivos .ios diretamente - import X from "./Foo.ios" quebra bundles Android ou envia o módulo errado. Correção: Importe ./Foo e deixe o Metro resolver.
Esquecer default em Platform.select - Targets web ou macos recebem undefined. Correção: Sempre adicione default para apps multi-plataforma do Expo.
Verificações de plataforma em estilos compartilhados fora de create - Chamar Platform.select uma vez no escopo do módulo é bom; valores dinâmicos por tema pertencem a hooks.
Lógica de negócios duplicada entre arquivos de plataforma - Copiar e colar se desvia com o tempo. Correção: Compartilhe lógica em utils/*.ts; divida apenas a fronteira de visualização/nativa.
Assumir Android === Material, iOS === Human Interface - Usuários esperam consistência de marca. Correção: Unifique espaçamento e semântica; varie o cromo apenas onde as convenções do SO exigem.
Comparar Platform.Version como string no iOS - "17" < "9" lexicograficamente falha. Correção: parseInt(String(Platform.Version), 10) antes da comparação numérica.
| Alternativa | Usar quando | Não usar quando |
|---|---|---|
Platform.select | Pequenas deltas de estilo/constante | Componentes inteiros diferem |
Arquivos .ios / .android | Grandes UIs ou imports nativos por SO | Ajuste de cor ou altura único |
expo-device / Constants | Modelo do dispositivo, isTablet, runtimeVersion | Enum simples de SO é suficiente |
| Módulos nativos condicionais | Recurso requer TurboModule apenas em um SO | Diferença de estilo apenas em JS |
| Design universal | Mandatos de marca exigem paridade de pixels | O HIG do SO afeta materialmente a UX (folhas de compartilhamento) |
Breakpoints do react-native-unistyles | Tokens de tema por plataforma em um sistema de design | Altura de cabeçalho de uso único |
"ios" e "android"."web", e o RN suporta "macos" e "windows" em alguns templates.Platform.OS === "ios" em vez de assumir apenas duas plataformas.Foo.ios.tsx primeiro, depois Foo.native.tsx, depois Foo.tsx.Foo.android.tsx substitui a etapa .ios.Platform.select para valores de estilo, constantes numéricas e pequenos objetos de configuração.*.web.tsx completamente diferente..ios) vence .native vence .tsx genérico.default, plataformas não correspondentes recebem undefined.default ou uma chave web explícita.Platform.select({...}) ?? fallback.app/, mas os componentes podem ser divididos normalmente..ios, a menos que você pretenda telas específicas do SO.const spacing = Platform.select({
ios: 8,
android: 12,
default: 10,
}); // number | undefined sem default - use a chave default"18.0") - analise para a versão principal inteira para comparações.34) - compare numericamente.{Platform.OS === "ios" && <BlurView />}) são aceitáveis.*.web.tsx quando presentes..web, a web pode voltar para .tsx ou .native.tsx dependendo da configuração do resolvedor.*.web.tsx explícito quando o código mobile importar módulos apenas nativos../Button sempre - deixe o bundler escolher o arquivo certo.Component.types.ts com interfaces de props.Component.ios.tsx / Component.android.tsx importa os mesmos tipos.Component.tsx (barrel) que reexporta a implementação resolvida.Platform.OS via jest.spyOn(Platform, "OS", "get").Platform.OS é "web".ios - defina explicitamente por suíte.expo-constants expõe executionEnvironment, sessionId, sutilezas de platform, e metadados EAS.Platform para ramificações rápidas de SO em componentes de UI..ios.ts / .android.ts com assinaturas TypeScript correspondentes.index.ts para que o código do app permaneça agnóstico à plataforma.Versões do Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0, e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026