Dieser Inhalt wird übersetzt und wird hier verfügbar sein, sobald er fertig ist.
Environment Setup

In the next twenty minutes, you'll have a React Native project ready to connect to any Solana mobile wallet. No dApp browser required, no wallet extension needed. Just native app-to-app communication.
Getting Solana development working in React Native requires some careful setup. The Solana JavaScript libraries assume a Node.js environment with crypto APIs that don't exist in React Native. We need to provide polyfills, which are shims that implement these missing APIs.
Project Initialization
The fastest path to a working project is the Solana Mobile scaffold. It handles all the configuration we'd otherwise do manually.
npm create solana-dapp@latestWhen prompted, select Solana Mobile as the framework. This generates a project with:
React Native (via Expo)
Mobile Wallet Adapter libraries pre-configured
Polyfills already set up
Example screens for authorization and signing
After generation:
cd your-app-name
npm installStarting from Scratch
If you prefer to build from a blank slate, or need to add MWA to an existing project, here's the manual approach.
Create a new Expo project:
npx create-expo-app SolanaMobileApp --template blank-typescript
cd SolanaMobileAppInstall the required dependencies:
npm install @solana-mobile/mobile-wallet-adapter-protocol-web3js \
@solana-mobile/mobile-wallet-adapter-protocol \
@solana/web3.js \
react-native-get-random-values \
@craftzdog/react-native-buffer \
react-native-quick-base64 \
@react-native-async-storage/async-storageThen install the safe area context for proper layout handling:
npx expo install react-native-safe-area-contextNote: We use @craftzdog/react-native-buffer rather than the Node.js buffer package. This package is optimized for React Native and works correctly with Expo.
Polyfill Configuration
React Native's JavaScript runtime lacks several APIs that @solana/web3.js expects:
crypto.getRandomValues(): for generating keypairsBuffer: for byte array manipulation
These must be polyfilled before any Solana code runs. Order matters critically here.
The Polyfill File
Create a file that will run first in your application:
// src/polyfills.ts
import 'react-native-get-random-values';
import { Buffer } from '@craftzdog/react-native-buffer';
// Make Buffer globally available
// Type assertion needed: @craftzdog/react-native-buffer is API-compatible
// but has a different TypeScript signature than Node's BufferConstructor
if (typeof global.Buffer === 'undefined') {
global.Buffer = Buffer as unknown as typeof global.Buffer;
}Loading Polyfills First
The import order in your entry point determines execution order. Polyfills must come before any other imports:
// index.ts or App.tsx (your entry point)
import './src/polyfills'; // MUST be first
import { registerRootComponent } from 'expo';
import App from './App';
registerRootComponent(App);If you're using Expo's default structure with App.tsx as the entry:
// App.tsx
import './src/polyfills'; // First line
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, View } from 'react-native';
// ... rest of importsVerifying Your Setup
Before going further, verify that your polyfills work correctly. Add a test that runs on app startup:
// src/utils/verifySetup.ts
import { Keypair } from '@solana/web3.js';
export function verifyPolyfills(): boolean {
try {
// Test 1: crypto.getRandomValues must work
const randomBytes = new Uint8Array(32);
crypto.getRandomValues(randomBytes);
// Test 2: Keypair generation must work
const keypair = Keypair.generate();
console.log('✓ Test keypair generated:', keypair.publicKey.toBase58());
// Test 3: Buffer must work
const buffer = Buffer.from('test', 'utf-8');
console.log('✓ Buffer working:', buffer.toString('hex'));
// Test 4: TextEncoder must work
const encoded = new TextEncoder().encode('test');
console.log('✓ TextEncoder working:', encoded.length, 'bytes');
return true;
} catch (error) {
console.error('Polyfill verification failed:', error);
return false;
}
}Call this in your app:
// App.tsx
import './src/polyfills';
import { useEffect } from 'react';
import { verifyPolyfills } from './src/utils/verifySetup';
export default function App() {
useEffect(() => {
const ready = verifyPolyfills();
if (!ready) {
console.error('Polyfills not loaded correctly!');
}
}, []);
// ... rest of your app
}Run the app and check your console. You should see all four checks pass. If any fail, your polyfills aren't loading in the correct order.
Expo Development Build
Here's something that trips up many developers: Expo Go cannot run MWA apps.
Expo Go is the app you download from the app store that runs Expo projects instantly. It's great for quick development, but it bundles its own JavaScript runtime without the native modules MWA needs.
For Mobile Wallet Adapter, you need a Development Build: a custom version of Expo that includes the native code your app requires.
Creating a Development Build
First, install the expo-dev-client:
npx expo install expo-dev-clientThen build for Android locally:
npx expo run:androidThis compiles native Android code and installs a custom Expo client on your device or emulator. It takes longer than Expo Go but only needs to run once (unless you change native dependencies).
Connecting Your Device
For testing on a physical device:
Enable Developer Options on your Android phone (tap Build Number 7 times in Settings > About)
Enable USB Debugging in Developer Options
Connect via USB
Run
adb devicesto verify connectionRun
npx expo run:android
For testing on an emulator with Mock MWA:
Install Mock MWA from https://github.com/solana-mobile/mock-mwa-wallet
Follow the Mock MWA instructions to set up the emulator for MWA testing.
Run
npx expo run:androidto install the development build on the emulator.
Project Structure
Organize your project for a clean separation between Solana-specific code and UI:
src/
├── polyfills.ts # Crypto shims (loads first)
├── App.tsx # Root component
├── providers/
│ ├── AuthorizationProvider.tsx # MWA state management
│ └── ConnectionProvider.tsx # RPC connection
├── hooks/
│ ├── useAuthorization.ts # Auth context hook
│ └── useTransactions.ts # Transaction helpers
├── screens/
│ ├── HomeScreen.tsx
│ └── SendScreen.tsx
├── utils/
│ ├── verifySetup.ts # Polyfill verification
│ └── constants.ts # App identity, RPC URLs
└── components/
├── ConnectButton.tsx
└── TransactionStatus.tsxThis structure separates concerns:
Providers handle wallet state and RPC connections
Hooks expose that state to components
Screens compose the UI
Utils contain pure functions and constants
App Constants
Define your app identity and network configuration in one place:
// src/utils/constants.ts
export const APP_IDENTITY = {
name: 'My Solana dApp',
uri: 'https://mydapp.com',
icon: 'favicon.ico', // Relative to uri
};
export const RPC_ENDPOINT = 'https://api.devnet.solana.com';
export const CLUSTER = 'solana:devnet' as const;
// Alternative endpoints for production
export const MAINNET_RPC = 'https://api.mainnet-beta.solana.com';
export const MAINNET_CLUSTER = 'solana:mainnet' as const;The APP_IDENTITY object appears in wallet authorization prompts. Use a real domain that you control. Wallets may verify ownership.
Common Setup Issues
crypto.getRandomValues is not a function
The polyfill isn't loading before Solana code runs. Check:
import './src/polyfills'is literally the first import in your entry fileThe polyfill file correctly imports
react-native-get-random-valuesYou rebuilt the development client after adding the package
Buffer is not defined
Similar cause: the Buffer polyfill isn't available globally. Ensure:
Your polyfill file sets
global.Buffer = BufferThe polyfill runs before any code that uses Buffer
Build fails with native module errors
You're probably running in Expo Go instead of a development build. MWA requires native code that Expo Go doesn't include.
# Stop Expo Go and build a dev client
npx expo run:androidSDK location not found
When running npx expo run:android for the first time, you may see:
SDK location not found. Define a valid SDK location with an
ANDROID_HOME environment variable or by setting the sdk.dir
path in your project's local properties fileExpo prebuild generates the android/ folder but doesn't auto-create local.properties. Create it manually:
# android/local.properties
sdk.dir=/Users/YOUR_USERNAME/Library/Android/sdkOr set ANDROID_HOME in your shell profile (~/.zshrc or ~/.bashrc):
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/platform-toolsThis file is gitignored by default, so each developer sets their own SDK path.
Metro bundler caching old code
Sometimes Metro caches previous failed builds:
npx expo start --clearOr nuke the cache entirely:
rm -rf node_modules/.cache
npx expo start --clearConnection refused on localhost
The wallet couldn't start its WebSocket server, or your app tried to connect before it was ready. This often happens in emulators where timing is different from real devices.
Test on a real device first. If the issue persists, check that no other app is using the randomly selected port.
Testing Without a Physical Device
You can develop UI and MWA features on an emulator using Mock MWA, a dedicated tool for simulating MWA interactions. However, for full Mobile Wallet Adapter protocol testing, a real Android device is still recommended, use either:
A real Android device with Phantom/Solflare installed
A wallet that supports emulator connections (check wallet documentation)
For the MWA protocol specifically, real device testing is strongly recommended. Emulators have timing differences that can cause spurious connection failures.
Note: MWA doesn't work on iOS. The protocol uses Android Intents and localhost WebSockets, which iOS doesn't support in the same way. The MWA specification lists iOS as "planned for a future version." If you need iOS support, skip to Course 3 (Embedded Wallets) for cross-platform solutions.
Next Steps
Your environment is ready. You have:
A React Native project with proper polyfills
Development build capability for native module support
Organized project structure
Verification tests to catch configuration errors
In the next lesson, we'll use transact() to actually connect to a wallet and retrieve the user's public key.