create-expo-module
Um guia para criar um módulo nativo local com uma interface TypeScript tipada - o caminho suportado quando os pacotes do Expo SDK e bibliotecas de terceiros não cobrem sua integração.
Busque em todas as páginas da documentação
Um guia para criar um módulo nativo local com uma interface TypeScript tipada - o caminho suportado quando os pacotes do Expo SDK e bibliotecas de terceiros não cobrem sua integração.
Cartão de receita de referência rápida - pronto para copiar e colar.
# Da raiz do seu app Expo
npx create-expo-module@latest modules/attestation
# Responda às perguntas: nome do módulo, descrição, plataformas (ios + android)
cd modules/attestation
npm install
npm run build # compila a interface TypeScript
# Conecte ao app (dependência de workspace ou de arquivo)
cd ../..
npm install ./modules/attestation
# Gere os projetos nativos novamente
npx expo prebuild --clean
npx expo run:ios// Uso do app após a criação
import AttestationModule from "attestation";
const result = await AttestationModule.isDeviceTrustedAsync();Quando usar isso:
packages/attestation.npx create-expo-app@latest AttestationApp --template blank-typescript@sdk-57 --yes
cd AttestationApp
npx create-expo-module@latest modules/device-trustLayout de saída típico:
AttestationApp/
├── app.json
├── package.json
├── App.tsx
└── modules/
└── device-trust/
├── android/
│ └── src/main/java/expo/modules/devicetrust/DeviceTrustModule.kt
├── ios/
│ └── DeviceTrustModule.swift
├── src/
│ ├── DeviceTrustModule.ts
│ └── index.ts
├── expo-module.config.json
└── package.json// modules/device-trust/ios/DeviceTrustModule.swift
import ExpoModulesCore
public class DeviceTrustModule: Module {
public func definition() -> ModuleDefinition {
Name("DeviceTrust")
AsyncFunction("isDeviceTrustedAsync") { () -> Bool in
// Substitua pela integração DeviceCheck / App Attest
#if targetEnvironment(simulator)
return false
#else
return true
#endif
}
}
}// modules/device-trust/android/src/main/java/expo/modules/devicetrust/DeviceTrustModule.kt
package expo.modules.devicetrust
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
class DeviceTrustModule : Module() {
override fun definition() = ModuleDefinition {
Name("DeviceTrust")
AsyncFunction("isDeviceTrustedAsync") {
// Substitua pela API Play Integrity
!Build.FINGERPRINT.contains("generic")
}
}
}// modules/device-trust/src/DeviceTrustModule.ts
import { requireNativeModule } from "expo-modules-core";
type DeviceTrustModuleType = {
isDeviceTrustedAsync: () => Promise<boolean>;
};
export default requireNativeModule<DeviceTrustModuleType>("DeviceTrust");// modules/device-trust/src/index.ts
export { default } from "./DeviceTrustModule";// AttestationApp/package.json (trecho)
{
"dependencies": {
"device-trust": "file:./modules/device-trust",
"expo": "~57.0.4",
"expo-dev-client": "~6.0.0",
"react": "19.2.3",
"react-native": "0.86.0"
}
}// App.tsx
import { useEffect, useState } from "react";
import { Button, StyleSheet, Text, View } from "react-native";
import DeviceTrust from "device-trust";
export default function App() {
const [trusted, setTrusted] = useState<boolean | null>(null);
useEffect(() => {
DeviceTrust.isDeviceTrustedAsync().then(setTrusted);
}, []);
return (
<View style={styles.container}>
<Text style={styles.title}>Módulo Device Trust</Text>
<Text>Confiável: {trusted === null ? "…" : trusted ? "sim" : "não"}</Text>
<Button title="Verificar novamente" onPress={() => DeviceTrust.isDeviceTrustedAsync().then(setTrusted)} />
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: "center", padding: 24, gap: 8 },
title: { fontSize: 20, fontWeight: "700" },
});# Compile o TS do módulo, faça o prebuild, execute
cd modules/device-trust && npm run build && cd ../..
npx expo install expo-dev-client
npx expo prebuild
npx expo run:iosO que isso demonstra:
create-expo-module gera esqueletos correspondentes de Swift/Kotlin/TypeScript com o registro correto de Name("DeviceTrust").requireNativeModule carrega a ligação JSI após a compilação do código nativo por autolinking.file:./modules/... mantém o módulo local - publique mais tarde se for reutilizado entre repositórios.Se o módulo precisar de entitlements, adicione app.plugin.js dentro do pacote do módulo e registre-o em app.config.ts do app. Veja Plugins de Configuração.
{
"platforms": ["ios", "android"],
"ios": {
"modules": ["DeviceTrustModule"]
},
"android": {
"modules": ["expo.modules.devicetrust.DeviceTrustModule"]
}
}O autolinking lê este arquivo durante npx expo prebuild e conecta as entradas do Gradle/Pod - sem vinculação manual em apps CNG.
| Layout | Caminho | Dependência |
|---|---|---|
| App único | modules/device-trust | "file:./modules/device-trust" |
| Pacote Monorepo | packages/device-trust | "workspace:*" em package.json do app |
| npm publicado | registro externo | "device-trust": "^1.0.0" |
Para nuances de autolinking em monorepos, veja Autolinking & expo-modules-core.
Módulo Expo (create-expo-module) | RN TurboModule (Codegen) |
|---|---|
| Autolinking Expo + plugins de configuração | RN-first; configuração manual do Codegen |
DSL ModuleDefinition Swift/Kotlin | C++/Java/ObjC com arquivos de spec |
| Melhor para apps Expo SDK 57 | Melhor para bibliotecas RN-core sem expo |
A maioria das equipes de aplicativos deve começar com a API Expo Modules. Use Escrevendo um TurboModule ao compartilhar C++ entre plataformas ou fazer upstream para a comunidade RN.
De acordo com as Regras de Módulos Nativos, documente:
npm run build no módulo - o app importa a saída build/ desatualizada. Correção: Adicione "prepare": "expo-module build" ou compile em CI antes da compilação do app.Name("DeviceTrust") e requireNativeModule("DeviceTrust") - erro em tempo de execução. Correção: Mantenha os nomes idênticos entre Swift, Kotlin e TS.npx expo prebuild --clean.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Pacote Expo SDK | O recurso existe upstream | API proprietária |
| Biblioteca nativa npm de terceiros | Ponte comunitária mantida | Não mantida ou sem Nova Arquitetura |
| Módulo Expo (esta página) | Ponte personalizada fina em app Expo | Núcleo compartilhado C++ pesado |
| TurboModule + Codegen | Biblioteca do ecossistema RN | Integração padrão de app CNG Expo |
Sim, em apps React Native puros com expo-modules-core instalado via npx install-expo-modules. O Expo prebuild ainda é o caminho de conexão mais fácil.
Sim. Use workspace:* e ative autolinkingModuleResolution - veja a página de autolinking.
Use Events("onTrustChanged") em ModuleDefinition e EventEmitter no lado JS - o mesmo padrão de expo-sensors.
Somente quando o módulo requer permissões, entitlements, dependências Gradle ou metadados de manifesto não cobertos pelos padrões de autolinking.
Complete a criação, adicione README e testes, execute npm publish de modules/device-trust. Os consumidores executam npx expo install device-trust e registram qualquer plugin.
Versões da 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