Building a Mobile dApp
React Native and Expo integration with @solana/kit and MWA.
Recipe
npx create-solana-dapp@latest my-mobile-dapp
cd my-mobile-dapp && npx expo start --dev-clientWhen to reach for this:
- Shipping Android-first Solana consumer apps.
- Reusing kit business logic from web project in monorepo.
- Seeker ecosystem launches.
Working Example
import { useCallback, useState } from "react";
import { Button, Text, View } from "react-native";
import { createSolanaRpc, address } from "@solana/kit";
import { transact } from "@solana-mobile/mobile-wallet-adapter-protocol-web3js";
const rpc = createSolanaRpc("https://api.devnet.solana.com");
export function App() {
const [addr, setAddr] = useState<string | null>(null);
const connect = useCallback(async () => {
await transact(async (wallet) => {
const auth = await wallet.authorize({
cluster: "devnet",
identity: { name: "Demo", uri: "https://example.com", icon: "icon.png" },
});
setAddr(auth.accounts[0].address);
});
}, []);
return (
<View>
<Button title="Connect" onPress={connect} />
{addr && <Text>{addr}</Text>}
</View>
);
}What this demonstrates:
- RN UI + kit RPC + MWA authorize in one screen.
- Dev client required for native MWA module.
- Share types with web app via monorepo packages.
Deep Dive
How It Works
- Expo prebuild generates Android project with intent filters.
- kit runs in Hermes JS engine - use bigint consistently.
- Monorepo can share Codama clients between web and mobile.
- OTA updates via Expo do not replace native wallet SDK upgrades.
Gotchas
- Expo Go without dev client - MWA native module missing. Fix: custom dev client build.
- Blocking UI thread during transact - ANR on Android. Fix: async patterns only.
- Huge bundle with all program clients - slow startup. Fix: split imports.
- Secure storage for tokens - use platform secure store for auth tokens.
- iOS assumptions - verify platform support matrix before marketing iOS.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| PWA mobile web | Zero install | MWA native UX |
| Flutter SMS SDK | Dart team | React shop |
FAQs
App Router?
Providers in client layout.tsx; pages mix server + client components.
Secrets?
Server env only for keypairs; NEXT_PUBLIC_ for RPC URLs.
kit 7.0.0?
All examples use @solana/kit, not web3.js v1.
Wallet?
Signing only in client components.
Caching?
Revalidate on-chain reads carefully - chain is source of truth.
Actions?
HTTPS endpoints returning Solana Actions JSON.
Mobile?
Separate React Native app with MWA.
Testing?
Surfpool for integration; mock RPC in unit tests.
Mainnet?
Separate env files and program IDs.
Errors?
Decode simulation logs for user-facing messages.
Related
- Mobile Wallet Adapter - connect API
- dApp Integration Basics - parallel web patterns
- @solana/kit Basics - kit core
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.