
Testando no Dispositivo
Embora o protocolo MWA principal seja projetado para dispositivos Android físicos e dependa de intents, sockets locais e um app de carteira real, você pode usar o Mock MWA para simular interações MWA em um emulador.
Requisitos
Você precisa de:
Nota sobre Emulador: O Mock MWA requer que o emulador tenha algum tipo de autenticação (PIN/biometria). A conexão com a carteira falha sem autenticação.
Nota sobre iOS: MWA é exclusivo para Android. O protocolo requer Android Intents para iniciar apps de carteira e servidores WebSocket locais para comunicação, nenhum dos quais tem equivalentes no iOS. A especificação oficial observa: "Suporte ao iOS está planejado para uma versão futura." Para usuários iOS, embedded wallets (Curso 3) ou deeplinks do Phantom fornecem alternativas.
Configuração do Dispositivo Android
Habilitar Modo Desenvolvedor
Vá para Configurações → Sobre o Telefone
Encontre Build Number
Toque 7 vezes até ver "Você agora é um desenvolvedor"
Volte para Configurações, encontre Opções do Desenvolvedor
Habilite Depuração USB
Conectar ao Computador
Conecte o cabo USB
No telefone: Permita depuração USB quando solicitado
Marque "Sempre permitir deste computador"
Verifique a conexão:
adb devicesVocê deve ver seu dispositivo listado:
List of devices attached
XXXXXXXXX deviceSe disser unauthorized, verifique seu telefone para o prompt de permissão.
Executando o App
React Native CLI
# Inicie o Metro bundler em um terminal
npx react-native start
# Em outro terminal, construa e execute no dispositivo
npx react-native run-androidExpo Development Build
Como MWA requer código nativo, você precisa de um development build (não Expo Go):
# Criar development build
npx expo run:androidIsso constrói e instala o app no seu dispositivo. Execuções subsequentes usam:
# Iniciar servidor de desenvolvimento
npx expo start --dev-clientEscaneie o código QR com a câmera do seu dispositivo para conectar.
Instalar uma Carteira
Instale um app de carteira que suporta MWA:
Phantom: play.google.com/store/apps/details?id=app.phantom
Solflare: play.google.com/store/apps/details?id=com.solflare.mobile
Após instalar:
Crie ou importe uma carteira
Mude para Devnet (Configurações → Configurações do Desenvolvedor → Devnet)
Obtenha SOL de devnet de uma faucet
Obtendo SOL de Devnet
Financie sua carteira para testes:
Web Faucet: faucet.solana.com
CLI:
solana airdrop 2 YOUR_WALLET_ADDRESS --url devnetProgramaticamente (do seu app):
const connection = new Connection('https://api.devnet.solana.com');
const signature = await connection.requestAirdrop(
walletPublicKey,
2 * LAMPORTS_PER_SOL
);
await connection.confirmTransaction(signature);Testando a Conexão
Crie uma tela de teste mínima:
// TestScreen.tsx
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet, ScrollView } from 'react-native';
import { transact } from '@solana-mobile/mobile-wallet-adapter-protocol-web3js';
import { PublicKey } from '@solana/web3.js';
import { toByteArray } from 'react-native-quick-base64';
const APP_IDENTITY = {
name: 'MWA Test',
uri: 'https://test.app',
icon: 'favicon.ico',
};
export function TestScreen() {
const [logs, setLogs] = useState<string[]>([]);
const log = (message: string) => {
const timestamp = new Date().toLocaleTimeString();
setLogs((prev) => [...prev, `[${timestamp}] ${message}`]);
};
const testConnect = async () => {
log('Iniciando transact...');
try {
await transact(async (wallet) => {
log('Sessão estabelecida');
const result = await wallet.authorize({
identity: APP_IDENTITY,
chain: 'solana:devnet',
});
const address = new PublicKey(
toByteArray(result.accounts[0].address)
);
log(`Autorizado: ${address.toBase58()}`);
log(`Auth token: ${result.auth_token.slice(0, 20)}...`);
log(`Contas: ${result.accounts.length}`);
});
log('Sessão encerrada com sucesso');
} catch (error) {
log(`ERRO: ${error}`);
}
};
const clearLogs = () => setLogs([]);
return (
<View style={styles.container}>
<Text style={styles.title}>Teste de Conexão MWA</Text>
<View style={styles.buttons}>
<Button title="Testar Conexão" onPress={testConnect} />
<Button title="Limpar Logs" onPress={clearLogs} />
</View>
<ScrollView style={styles.logContainer}>
{logs.map((log, index) => (
<Text key={index} style={styles.log}>{log}</Text>
))}
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 16 },
title: { fontSize: 20, fontWeight: 'bold', marginBottom: 16 },
buttons: { flexDirection: 'row', gap: 8, marginBottom: 16 },
logContainer: { flex: 1, backgroundColor: '#1a1a1a', padding: 8, borderRadius: 8 },
log: { color: '#0f0', fontFamily: 'monospace', fontSize: 12, marginBottom: 4 },
});Quando você tocar em "Testar Conexão":
Seu app abre a carteira
A carteira mostra o prompt de autorização
Você aprova
O controle retorna ao seu app
Os logs mostram o resultado
Dicas de Depuração
Ver Logs
Use adb logcat filtrado para React Native:
adb logcat *:S ReactNative:V ReactNativeJS:VOu use Flipper para uma interface mais agradável:
npx react-native-flipperProblemas Comuns
"Nenhuma carteira instalada encontrada"
Verifique se Phantom/Solflare está instalado
Verifique se o app da carteira é a versão correta do MWA
"Timeout da sessão"
A carteira ficou em segundo plano por muito tempo
O Android encerrou o processo da carteira
Tente manter a carteira em primeiro plano
"Autorização falhou" imediatamente
Seu auth token está desatualizado
Limpe o token em cache e tente novamente
Verifique se o URI de identidade corresponde ao seu app
App crasha no transact()
Polyfills ausentes (verifique a ordem do arquivo de entrada)
Metro bundler precisa reiniciar
Execute
npx react-native start --reset-cache
Assinatura de transação falha mas sem erro
Verifique se a carteira está na devnet (se testando com devnet)
Verifique se a transação é válida (simule primeiro)
Verifique se há SOL suficiente para as taxas
Inspecionar Requisições de Rede
Para depuração RPC, registre todas as requisições Solana:
// Patch Connection para logging (apenas desenvolvimento)
if (__DEV__) {
const originalFetch = global.fetch;
global.fetch = async (url, options) => {
if (typeof url === 'string' && url.includes('solana')) {
console.log('[RPC]', options?.body);
}
return originalFetch(url, options);
};
}Hot Reloading
O hot reload do Metro funciona com desenvolvimento MWA:
Faça alterações no código
Salve o arquivo
O app recarrega automaticamente
Teste o fluxo MWA novamente
Para iteração mais rápida, crie uma conexão de carteira de teste no topo da sua tela de teste e mantenha o logging habilitado.
Ressalva do Fast Refresh: Se você alterar o componente que chama transact(), pode precisar reiniciar o app para um estado limpo.
Testando Assinatura de Transações
Adicione um teste de transação à sua tela de debug:
import {
Connection,
PublicKey,
VersionedTransaction,
TransactionMessage,
SystemProgram,
} from '@solana/web3.js';
const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
async function testSendTransaction(log: (msg: string) => void) {
log('Construindo transação...');
await transact(async (wallet) => {
const result = await wallet.authorize({
identity: APP_IDENTITY,
chain: 'solana:devnet',
});
const publicKey = new PublicKey(
toByteArray(result.accounts[0].address)
);
log(`Usando conta: ${publicKey.toBase58()}`);
// Verificar saldo
const balance = await connection.getBalance(publicKey);
log(`Saldo: ${balance / 1e9} SOL`);
if (balance < 0.001 * 1e9) {
log('ERRO: Saldo insuficiente para teste');
return;
}
// Construir transação (enviar 0.001 SOL para si mesmo)
const { blockhash } = await connection.getLatestBlockhash();
const transaction = new VersionedTransaction(
new TransactionMessage({
payerKey: publicKey,
recentBlockhash: blockhash,
instructions: [
SystemProgram.transfer({
fromPubkey: publicKey,
toPubkey: publicKey, // Enviar para si mesmo
lamports: 0.001 * 1e9,
}),
],
}).compileToV0Message()
);
log('Assinando transação...');
const [signature] = await wallet.signAndSendTransactions({
transactions: [transaction],
});
log(`Assinatura: ${signature}`);
// Confirmar
log('Aguardando confirmação...');
const confirmation = await connection.confirmTransaction(signature, 'confirmed');
if (confirmation.value.err) {
log(`ERRO: ${JSON.stringify(confirmation.value.err)}`);
} else {
log('Transação confirmada!');
}
});
}Testando Assinatura de Mensagens
Teste a assinatura de mensagens separadamente:
import nacl from 'tweetnacl';
async function testSignMessage(log: (msg: string) => void) {
const testMessage = 'Olá do teste MWA!';
const messageBytes = new TextEncoder().encode(testMessage);
log(`Assinando mensagem: "${testMessage}"`);
await transact(async (wallet) => {
const result = await wallet.authorize({
identity: APP_IDENTITY,
chain: 'solana:devnet',
});
const publicKey = new PublicKey(
toByteArray(result.accounts[0].address)
);
const signResult = await wallet.signMessages({
addresses: [result.accounts[0].address],
payloads: [messageBytes],
});
const signature = signResult[0];
log(`Assinatura: ${Buffer.from(signature).toString('hex').slice(0, 40)}...`);
// Verificar
const isValid = nacl.sign.detached.verify(
messageBytes,
signature,
publicKey.toBytes()
);
log(`Verificação: ${isValid ? 'APROVADO ✓' : 'FALHOU ✗'}`);
});
}Teste Multi-Device
Se você tem múltiplos dispositivos Android:
# Listar dispositivos
adb devices
# Executar em dispositivo específico
npx react-native run-android --deviceId DEVICE_SERIALTeste com diferentes carteiras em diferentes dispositivos para garantir compatibilidade:
Phantom (mais popular)
Solflare (bom suporte MWA)
Backpack (se disponível)
Teste de Build de Release
Teste builds de release antes de publicar:
# Construir APK de release
cd android
./gradlew assembleRelease
# Instalar no dispositivo
adb install app/build/outputs/apk/release/app-release.apkPara Expo:
npx eas build --platform android --profile previewBuilds de release podem se comportar diferente:
Sem logs de debug
Caminhos de código otimizados
Mensagens de erro diferentes
Sempre teste fluxos MWA em modo release antes de publicar.
Checklist
Antes de considerar a integração MWA completa:
Fluxo de conexão funciona com Phantom
Fluxo de conexão funciona com Solflare
Assinatura de transação tem sucesso
Assinatura de mensagem tem sucesso
Tratamento de erros mostra mensagens amigáveis ao usuário
Caso "nenhuma carteira instalada" é tratado
Cancelamento do usuário não mostra erro
Cache de auth token funciona (reconexão é rápida)
Funciona em build de release
Funciona em dispositivo Android 8.0 (API 26) se suportar telefones mais antigos
Com seu dApp testado em hardware real, você está pronto para construir uma aplicação completa. A lição final reúne tudo com um projeto capstone.