solana_kit_mobile_wallet_adapter 0.2.1
solana_kit_mobile_wallet_adapter: ^0.2.1 copied to clipboard
Flutter plugin for the Solana Mobile Wallet Adapter protocol. Enables dApps to communicate with wallet apps for transaction signing on Android. iOS compiles but is a no-op.
solana_kit_mobile_wallet_adapter #
Flutter plugin for the Solana Mobile Wallet Adapter (MWA) protocol.
This package provides both:
- dApp-side client flows (launch wallet, establish session, request signatures)
- wallet-side server flows (receive authorize/sign requests from dApps)
Platform support #
| Platform | dApp (client) | Wallet (server) |
|---|---|---|
| Android | Supported | Supported |
| iOS | No-op | No-op |
| Web | N/A | N/A |
Use isMwaSupported() / assertMwaSupported() before invoking MWA APIs.
What this package includes #
dApp-side APIs #
transact()for simple one-call session lifecycleLocalAssociationScenariofor explicit same-device controlstartRemoteScenario()for reflector-based cross-device sessionsKitMobileWallettyped wrapper over the protocol wallet interface
wallet-side APIs #
WalletScenariolifecycle and request routingWalletScenarioCallbacksfor authorize/sign/deauthorize handling- Typed request objects (
AuthorizeDappRequest,SignTransactionsRequest, etc.) MwaDigitalAssetLinksHostApifor Android package verification
Installation #
flutter pub add solana_kit_mobile_wallet_adapter
Inside this monorepo, workspace dependency resolution is automatic.
dApp usage #
Simple lifecycle (transact) #
import 'package:solana_kit_mobile_wallet_adapter/solana_kit_mobile_wallet_adapter.dart';
final auth = await transact((wallet) async {
final authorizeResult = await wallet.authorize(
identity: const AppIdentity(name: 'My dApp'),
chain: 'solana:mainnet',
);
await wallet.signTransactions(
payloads: [base64EncodedTransaction],
);
return authorizeResult;
});
Manual local association #
final scenario = LocalAssociationScenario();
try {
final rawWallet = await scenario.start();
final wallet = wrapWithKitApi(rawWallet);
final auth = await wallet.authorize(
identity: const AppIdentity(name: 'My dApp'),
chain: 'solana:devnet',
);
final signed = await wallet.signTransactions(
payloads: ['base64tx1', 'base64tx2'],
);
} finally {
await scenario.close();
}
Remote association (cross-device) #
startRemoteScenario resolves once a real reflector ID has been negotiated and a valid association URI is available.
final remote = await startRemoteScenario(
const RemoteWalletAssociationConfig(
reflectorHost: 'reflector.example.com',
),
);
// Display this as QR for wallet scan.
final uriForQr = remote.associationUri;
try {
final wallet = await remote.wallet;
await wallet.getCapabilities();
} finally {
remote.close();
}
wallet usage #
Start a wallet scenario #
class MyWalletCallbacks implements WalletScenarioCallbacks {
@override
void onAuthorizeRequest(AuthorizeDappRequest request) {
request.completeWithAuthorize(
accounts: [
AuthorizedAccount(
address: base64PublicKey,
label: 'Main Account',
),
],
authToken: 'issued-token',
);
}
@override
void onSignTransactionsRequest(SignTransactionsRequest request) {
final signed = signPayloads(request.payloads);
request.completeWithSignedPayloads(signed);
}
@override
void onReauthorizeRequest(ReauthorizeDappRequest request) {
request.completeWithReauthorize(
accounts: [AuthorizedAccount(address: base64PublicKey)],
authToken: 'renewed-token',
);
}
@override
void onScenarioReady() {}
@override
void onScenarioServingClients() {}
@override
void onScenarioServingComplete() {}
@override
void onScenarioComplete() {}
@override
void onScenarioError(Object? error) {}
@override
void onScenarioTeardownComplete() {}
@override
void onSignMessagesRequest(SignMessagesRequest request) {}
@override
void onSignAndSendTransactionsRequest(SignAndSendTransactionsRequest request) {}
@override
void onDeauthorizedEvent(DeauthorizedEvent event) {}
}
final scenario = WalletScenario(
walletName: 'My Wallet',
config: const MobileWalletAdapterConfig(
maxTransactionsPerSigningRequest: 10,
optionalFeatures: ['solana:signTransactions'],
),
callbacks: MyWalletCallbacks(),
);
await scenario.start();
Digital Asset Links verification (wallet-side) #
final dal = MwaDigitalAssetLinksHostApi();
final callingPackage = await dal.getCallingPackage();
final isVerified = await dal.verifyCallingPackage(
clientIdentityUri: 'https://example.com',
);
This is useful when wallet policy requires Android app-origin verification before honoring sensitive requests.
Native parity and behavior notes #
- Android wallet-side implementation is backed by Solana Mobile
walletlibrequest/scenario APIs. - Request lifecycle is explicit:
- native request -> Dart callback ->
completeWith*-> native resolve/cancel
- native request -> Dart callback ->
- Local/remote transport handling enforces inbound encrypted sequence ordering.
- Remote association supports reflector protocol negotiation (
binaryandbase64).
Maintenance and CI #
- Android native compile safety is enforced in CI by building a temporary Android Flutter app that depends on this plugin.
- Local equivalent command:
./scripts/check-mobile-wallet-adapter-android-compile.sh
Architecture #
- Dart: protocol/session handling via
solana_kit_mobile_wallet_adapter_protocol - Android Kotlin: intent launch + walletlib/DAL host bridges
- iOS Swift: safe no-op plugin for mixed-platform app compatibility
Manual testing app #
A runnable Flutter Android example app is available in example/.
cd packages/solana_kit_mobile_wallet_adapter/example
flutter pub get
flutter run
For emulator/device wallet setup (including Solana's mock MWA wallet), follow:
Example #
Use example/main.dart as a runnable starting point for solana_kit_mobile_wallet_adapter.
- Import path:
package:solana_kit_mobile_wallet_adapter/solana_kit_mobile_wallet_adapter.dart - This section is centrally maintained with
mdtto keep package guidance aligned. - After updating shared docs templates, run
docs:updatefrom the repo root.
Maintenance #
- Validate docs in CI and locally with
docs:check. - Keep examples focused on one workflow and reference package README sections for deeper API details.