Flutter Solana钱包管理插件solana_wallet_provider的使用
Flutter Solana钱包管理插件 solana_wallet_provider
的使用
概述
solana_wallet_provider
是一个用于在Flutter应用中集成Solana钱包管理功能的插件。它提供了对 solana_web3
和 solana_wallet_adapter
的访问,并创建了围绕 Mobile Wallet Adapter Specification 方法调用的UI包装器。
示例图示
示例应用
API
以下是该插件提供的主要API方法:
connect
- 授权应用程序与可用的钱包或呈现下载选项列表。disconnect
- 显示授权账户和断开连接按钮以取消应用程序的授权。signTransactions
- 使用授权账户签署交易。signAndSendTransactions
- 使用授权账户签署交易,然后将它们广播到网络。signMessages
- 使用授权账户签署消息。
便利小部件
SolanaWalletButton
- 一个切换应用程序与钱包授权状态的按钮小部件。
Dapp身份验证
钱包端点将使用您的 AppIdentity
信息来决定是否信任您的dapp。
AppIdentity(
uri: Uri.parse('https://<YOUR_DOMAIN>'),
icon: Uri.parse('favicon.png'),
name: '<APP_NAME>'
)
Android设置
-
获取您的应用程序ID。
// FILE: /android/app/build.gradle defaultConfig { applicationId "<APPLICATION_ID>" }
-
生成应用程序的sha256指纹。
$ cd android $ ./gradlew app:signingReport // Output: // ... // SHA-256: <SHA256_FINGERPRINT> // ...
-
托管包含以下内容的数字资产链接文件:
// GET: https:://<YOUR_DOMAIN>/.well-known/assetlinks.json [{ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "<APPLICATION_ID>", "sha256_cert_fingerprints": ["<SHA256_FINGERPRINT>"] } }]
主题定制
添加 SolanaWalletThemeExtension
作为 ThemeData
的扩展以自定义提供者的外观。
ThemeData(
extensions: const [
SolanaWalletThemeExtension(
cardTheme: SolanaWalletCardTheme(
color: Colors.indigo,
),
),
],
);
示例:连接
下面是一个如何使用该插件授权应用程序与Solana钱包的示例:
import 'package:flutter/material.dart';
import 'package:solana_wallet_provider/solana_wallet_provider.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({super.key});
[@override](/user/override)
Widget build(final BuildContext context) {
return SolanaWalletProvider.create(
identity: const AppIdentity(),
child: MaterialApp(
home: Scaffold(
body: FutureBuilder(
future: SolanaWalletProvider.initialize(),
builder: ((context, snapshot) {
final provider = SolanaWalletProvider.of(context);
return TextButton(
onPressed: () => provider.connect(context),
child: const Center(
child: Text('Example App'),
),
);
}),
),
),
),
);
}
}
完整示例Demo
以下是一个更完整的示例,展示了如何使用 solana_wallet_provider
插件执行多种操作,如连接、断开连接、签署交易、发送交易等:
import 'package:flutter/material.dart';
import 'package:solana_wallet_provider/solana_wallet_provider.dart';
void main() {
runApp(const MaterialApp(home: ExampleApp()));
}
class ExampleApp extends StatefulWidget {
const ExampleApp({super.key});
[@override](/user/override)
State<ExampleApp> createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
String? _status;
[@override](/user/override)
Widget build(final BuildContext context) {
return SolanaWalletProvider.create(
httpCluster: Cluster.devnet,
identity: AppIdentity(
uri: Uri.parse('https://my_dapp.com'),
icon: Uri.parse('favicon.png'),
name: 'My Dapp',
),
child: MaterialApp(
home: Scaffold(
body: FutureBuilder(
future: SolanaWalletProvider.initialize(),
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return const CircularProgressIndicator();
}
final provider = SolanaWalletProvider.of(context);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Wallet Button'),
SolanaWalletButton(),
const Divider(),
const Text('Wallet Methods'),
Wrap(
spacing: 24.0,
children: [
_textButton(
'Connect',
enabled: !provider.adapter.isAuthorized,
onPressed: () => _connect(context, provider),
),
_textButton(
'Disconnect',
enabled: provider.adapter.isAuthorized,
onPressed: () => _disconnect(context, provider),
),
_textButton(
'Sign Transactions (1)',
enabled: provider.adapter.isAuthorized,
onPressed: () => _signTransactions(context, provider, 1),
),
_textButton(
'Sign And Send Transactions (1)',
enabled: provider.adapter.isAuthorized,
onPressed: () => _signAndSendTransactions(context, provider, 1),
),
_textButton(
'Sign Messages (1)',
enabled: provider.adapter.isAuthorized,
onPressed: () => _signMessages(context, provider, 1),
),
],
),
const Divider(),
const Text('Output'),
Text(_status ?? '-'),
],
);
},
),
),
),
);
}
Future<void> _connect(BuildContext context, SolanaWalletProvider provider) async {
if (!provider.adapter.isAuthorized) {
await provider.connect(context);
setState(() {});
}
}
Future<void> _disconnect(BuildContext context, SolanaWalletProvider provider) async {
if (provider.adapter.isAuthorized) {
await provider.disconnect(context);
setState(() {});
}
}
void _signTransactions(BuildContext context, SolanaWalletProvider provider, int count) async {
try {
setState(() => _status = "Create Sign Transactions...");
final List<TransferData> transfers = await _createTransfers(provider.connection, provider.adapter, count: count);
setState(() => _status = "Sign Transactions...");
final result = await provider.signTransactions(
context,
transactions: transfers.map((transfer) => transfer.transaction).toList(),
);
setState(() => _status = "Broadcast Transactions...");
final signatures = await provider.connection.sendSignedTransactions(result.signedPayloads, eagerError: true);
setState(() => _status = "Confirm Transactions...");
await _confirmTransfers(provider.connection, signatures: signatures.map((e) => base58To64Encode(e!)).toList(), transfers: transfers);
} catch (error, stack) {
print('Sign Transactions Error: $error');
print('Sign Transactions Stack: $stack');
setState(() => _status = error.toString());
}
}
void _signAndSendTransactions(BuildContext context, SolanaWalletProvider provider, int count) async {
try {
setState(() => _status = "Create Sign And Send Transactions...");
final List<TransferData> transfers = await _createTransfers(provider.connection, provider.adapter, count: count);
setState(() => _status = "Sign And Send Transactions...");
final result = await provider.signAndSendTransactions(
context,
transactions: transfers.map((transfer) => transfer.transaction).toList(),
);
setState(() => _status = "Confirm Transactions...");
await _confirmTransfers(provider.connection, signatures: result.signatures, transfers: transfers);
} catch (error, stack) {
print('Sign And Send Transactions Error: $error');
print('Sign And Send Transactions Stack: $stack');
setState(() => _status = error.toString());
}
}
void _signMessages(BuildContext context, SolanaWalletProvider provider, int count) async {
try {
setState(() => _status = "Create Sign Messages...");
final messages = List.generate(count, (index) => 'Sign message $index');
setState(() => _status = "Sign Messages...");
final result = await provider.signMessages(
context,
messages: messages,
addresses: [provider.adapter.encodeAccount(provider.adapter.connectedAccount!)],
);
setState(() => _status = "Signed Messages ${result.signedPayloads.join('\n')}");
} catch (error, stack) {
print('Sign Messages Error: $error');
print('Sign Messages Stack: $stack');
setState(() => _status = error.toString());
}
}
Future<void> _airdrop(Connection connection, Pubkey wallet) async {
if (connection.httpCluster != Cluster.mainnet) {
setState(() => _status = "Requesting airdrop...");
await connection.requestAndConfirmAirdrop(wallet, solToLamports(2).toInt());
}
}
Future<List<TransferData>> _createTransfers(Connection connection, SolanaWalletAdapter adapter, {required int count}) async {
final wallet = Pubkey.tryFromBase64(adapter.connectedAccount?.address);
if (wallet == null) throw 'Wallet not connected';
final balance = await connection.getBalance(wallet);
if (balance < lamportsPerSol) await _airdrop(connection, wallet);
final latestBlockhash = await connection.getLatestBlockhash();
final txs = [];
for (int i = 0; i < count; ++i) {
final receiver = Keypair.generateSync();
final lamports = solToLamports(0.1);
final transaction = Transaction.v0(
payer: wallet,
recentBlockhash: latestBlockhash.blockhash,
instructions: [
SystemProgram.transfer(fromPubkey: wallet, toPubkey: receiver.pubkey, lamports: lamports),
],
);
txs.add(TransferData(transaction: transaction, receiver: receiver, lamports: lamports));
}
return txs;
}
Future<void> _confirmTransfers(Connection connection, {required List<String?> signatures, required List<TransferData> transfers}) async {
await Future.wait([for (final sig in signatures) connection.confirmTransaction(base58To64Decode(sig!))], eagerError: true);
final receiverBalances = await Future.wait([for (final transfer in transfers) connection.getBalance(transfer.receiver.pubkey)], eagerError: true);
final results = [];
for (int i = 0; i < receiverBalances.length; ++i) {
final transfer = transfers[i];
final pubkey = transfer.receiver.pubkey;
final balance = receiverBalances[i].toBigInt();
if (balance != transfer.lamports) throw Exception('Post transaction balance mismatch.');
results.add("Transfer: Address $pubkey received $balance SOL");
}
setState(() => _status = "Success!\n\n"
"Signatures: $signatures\n\n"
"${results.join('\n')}"
"\n");
}
TextButton _textButton(String text, {required bool enabled, required void Function() onPressed}) => TextButton(
onPressed: enabled ? onPressed : null,
child: Text(text),
);
}
class TransferData {
const TransferData({
required this.transaction,
required this.receiver,
required this.lamports,
});
final Transaction transaction;
final Keypair receiver;
final BigInt lamports;
}
更多关于Flutter Solana钱包管理插件solana_wallet_provider的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter Solana钱包管理插件solana_wallet_provider的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用solana_wallet_provider
插件来管理Solana钱包的示例代码。请注意,实际使用时需要根据solana_wallet_provider
插件的最新版本和API文档进行调整。
首先,确保你已经将solana_wallet_provider
添加到你的pubspec.yaml
文件中:
dependencies:
flutter:
sdk: flutter
solana_wallet_provider: ^最新版本号 # 替换为实际的最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,在你的Flutter项目中,你可以按照以下步骤使用solana_wallet_provider
来管理Solana钱包。
1. 初始化Solana钱包提供者
在你的主应用文件(通常是main.dart
)中,初始化SolanaWalletProvider
。
import 'package:flutter/material.dart';
import 'package:solana_wallet_provider/solana_wallet_provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => SolanaWalletProvider()),
],
child: MaterialApp(
title: 'Flutter Solana Wallet Management',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
),
);
}
}
2. 连接到Solana钱包
在你的MyHomePage
或其他需要管理钱包的页面中,连接到Solana钱包。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:solana_wallet_provider/solana_wallet_provider.dart';
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
final walletProvider = Provider.of<SolanaWalletProvider>(context);
return Scaffold(
appBar: AppBar(
title: Text('Solana Wallet Management'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _controller,
decoration: InputDecoration(hintText: 'Enter wallet address'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
try {
await walletProvider.connectWallet(walletAddress: _controller.text);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Connected to wallet')));
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Failed to connect: ${e.message}')));
}
},
child: Text('Connect Wallet'),
),
SizedBox(height: 16),
if (walletProvider.isConnected) {
Text('Connected Wallet Address: ${walletProvider.walletAddress}')
} else {
Text('No wallet connected')
},
],
),
),
);
}
}
3. 断开Solana钱包连接
你可以添加一个按钮来断开钱包连接。
// 在Column中添加一个断开连接的按钮
ElevatedButton(
onPressed: () {
final walletProvider = Provider.of<SolanaWalletProvider>(context);
walletProvider.disconnectWallet();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Disconnected from wallet')));
},
child: Text('Disconnect Wallet'),
),
4. 显示钱包余额(示例)
你可以添加一个方法来获取并显示钱包的余额(注意:这只是一个示例,具体实现取决于solana_wallet_provider
是否提供了相关API)。
// 假设有一个获取余额的方法
Future<void> fetchBalance() async {
final walletProvider = Provider.of<SolanaWalletProvider>(context);
try {
// 假设有一个获取余额的API
final balance = await walletProvider.getBalance();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Balance: $balance')));
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Failed to fetch balance: ${e.message}')));
}
}
// 在Column中添加一个获取余额的按钮
ElevatedButton(
onPressed: fetchBalance,
child: Text('Fetch Balance'),
),
请注意,上述代码中的getBalance
方法是一个假设的方法,因为solana_wallet_provider
的实际API可能会有所不同。你需要查阅solana_wallet_provider
的文档来找到正确的方法来获取钱包余额。
这个示例展示了如何在Flutter中使用solana_wallet_provider
插件来管理Solana钱包的连接和断开连接。根据插件的实际API和功能,你可以进一步扩展和自定义你的应用。