Flutter插件dart_nostr的使用_dart_nostr 是一个用于快速和简便开发 Nostr 客户端应用的 Dart/Flutter 工具包。
Flutter插件dart_nostr的使用_dart_nostr 是一个用于快速和简便开发 Nostr 客户端应用的 Dart/Flutter 工具包。
dart_nostr
是一个用于快速和简便开发 Nostr 客户端应用的 Dart/Flutter 工具包。
目录
支持的NIPs
如果你正在开发 Nostr 客户端或应用程序,你可以应用并使用以下所有 NIPs(截至 2024-01-18):
- NIP-01
- NIP-02
- NIP-03
- NIP-04
- NIP-05
- NIP-06
- NIP-08
- NIP-09
- NIP-10
- NIP-11
- NIP-13
- NIP-14
- NIP-15
- NIP-18
- NIP-19
- NIP-21
- NIP-23
- NIP-24
- NIP-25
- NIP-27
- NIP-28
- NIP-30
- NIP-31
- NIP-32
- NIP-36
- NIP-38
- NIP-39
- NIP-40
- NIP-42 (尚未实现)
- NIP-44 (尚未实现)
- NIP-45
- NIP-47
- NIP-48
- NIP-50
- NIP-51
- NIP-52
- NIP-53
- NIP-56
- NIP-57: Lightning Zaps
- NIP-58
- NIP-72
- NIP-75
- NIP-78
- NIP-84
- NIP-89
- NIP-94
- NIP-98
- NIP-99
标记为“尚未实现”的 NIPs 尚未被支持。
一些现有的 NIPs 是平台特定的或无法直接支持,例如仅限 Web 的 NIP 07 或与数据售卖机相关的 NIP 90。
安装
在你的 pubspec.yaml
文件中添加以下内容来安装包:
dependencies:
dart_nostr: any
或者从命令行安装:
# Flutter 项目
flutter pub add dart_nostr
# Dart 项目
dart pub add dart_nostr
使用
单例实例与多个实例
你需要记住的唯一类是 Nostr
,所有方法和实用工具都通过它提供。
Nostr
类可以通过两种方式访问:单例实例,通过调用 Nostr.instance
访问;构造函数,可以用来创建多个 Nostr
实例。
每个实例(包括单例实例)都是独立的,所以你在某个实例上所做的任何事情只能通过该实例访问,包括中继、事件、缓存、回调等。
如果你希望在整个应用程序中使用同一个实例,那么你可以使用单例实例。例如,一旦你连接到一组中继,你可以在应用程序的任何地方访问和使用它们(发送和接收事件)。
如果你想要创建多个 Nostr
实例,那么你可以使用构造函数。例如,如果你想在应用程序的不同部分连接到不同的中继,或者如果你有大量的 Nostr 中继请求,并且你想将它们分离到不同的实例中以避免中继限制。
/// 单例实例
final instance = Nostr.instance;
/// 构造函数
final instance = Nostr();
密钥
生成私钥和公钥
final newKeyPair = instance.keysService.generateKeyPair();
print(newKeyPair.public); // 公钥
print(newKeyPair.private); // 私钥
从私钥生成密钥对
final somePrivateKey = "HERE IS MY PRIVATE KEY";
final newKeyPair = instance.keysService
.generateKeyPairFromExistingPrivateKey(somePrivateKey);
print(somePrivateKey == newKeyPair.private); // true
print(newKeyPair.public); // 公钥
使用私钥签名和验证消息
/// 使用私钥签名消息
final signature = instance.keysService.sign(
privateKey: keyPair.private,
message: "hello world",
);
print(signature);
/// 使用公钥验证消息
final verified = instance.keysService.verify(
publicKey: keyPair.public,
message: "hello world",
signature: signature,
);
print(verified); // true
注意:dart_nostr
提供了更简单的方式来创建、签名和验证 Nostr 事件,详见下文中的中继和事件部分。
更多功能
包中还暴露了一些有用的方法,如:
// 处理 nsec 密钥
instance.keysService.encodePrivateKeyToNsec(privateKey);
instance.keysService.decodeNsecKeyToPrivateKey(privateKey);
// 处理 npub 密钥
instance.keysService.encodePublicKeyToNpub(privateKey);
instance.keysService.decodeNpubKeyToPublicKey(privateKey);
// 更多密钥派生和验证方法
instance.keysService.derivePublicKey(privateKey);
instance.keysService.generatePrivateKey(privateKey);
instance.keysService.isValidPrivateKey(privateKey);
// 与密钥相关的通用实用工具
instance.utilsService.decodeBech32(bech32String);
instance.utilsService.encodeBech32(bech32String);
instance.utilsService.pubKeyFromIdentifierNip05(bech32String);
事件与中继
创建事件
创建事件的最快方法是使用 NostrEvent.fromPartialData
构造函数,它可以为你完成所有繁重的工作,如使用提供的私钥签名事件、生成事件 ID 等。
final event = NostrEvent.fromPartialData(
kind: 1,
content: 'example content',
keyPairs: keyPair, // 将用于签署事件
tags: [
['t', currentDateInMsAsString],
],
);
print(event.id); // 事件 ID
print(event.sig); // 事件签名
print(event.serialized()); // 事件序列化为 JSON
注意:你也可以使用 NostrEvent
构造函数从头开始创建事件,但你需要自己完成繁重的工作,如签名事件、生成事件 ID 等。
连接到中继
对于单个 Nostr
实例,你可以一次性或多次连接到多个中继,这样你就可以稍后发送和接收事件。
try {
final relays = ['wss://relay.damus.io'];
await instance.relaysService.init(
relaysUrl: relays,
);
print("connected successfully")
} catch (e) {
print(e);
}
如果出现任何错误,你会收到一个带有错误消息的异常。
注意:init
方法高度可配置,因此你可以控制连接的行为,如重试次数、超时时间、是否抛出异常、注册连接或事件的回调等。
监听事件
作为流
// 创建要发送给中继的请求。(例如,此请求将获取所提供公钥的所有 kind 1 的事件)
final request = NostrRequest(
filters: [
NostrFilter(
kinds: const [1],
authors: [keyPair.public],
),
],
);
// 开始订阅并监听事件
final nostrStream = Nostr.instance.relaysService.startEventsSubscription(
request: request,
onEose: (ease) => print(ease),
);
print(nostrStream.subscriptionId); // 订阅 ID
// 监听事件
nostrStream.stream.listen((NostrEvent event) {
print(event.content);
});
// 稍后关闭订阅
nostrStream.close();
作为未来(在 EOSE 时解析)
// 创建要发送给中继的请求。(例如,此请求将获取所提供公钥的所有 kind 1 的事件)
final request = NostrRequest(
filters: [
NostrFilter(
kinds: const [1],
authors: [keyPair.public],
),
],
);
// 调用异步方法并等待结果
final events =
await Nostr.instance.relaysService.startEventsSubscriptionAsync(
request: request,
);
// 打印事件
print(events.map((e) => e.content));
注意:startEventsSubscriptionAsync
将在中继发送 EOSE 命令时解析为 List<NostrEvent>
。
重新连接与断开连接
// 重新连接
await Nostr.instance.relaysService.reconnectToRelays(
onRelayListening: onRelayListening,
onRelayConnectionError: onRelayConnectionError,
onRelayConnectionDone: onRelayConnectionDone,
retryOnError: retryOnError,
retryOnClose: retryOnClose,
shouldReconnectToRelayOnNotice: shouldReconnectToRelayOnNotice,
connectionTimeout: connectionTimeout,
ignoreConnectionException: ignoreConnectionException,
lazyListeningToRelays: lazyListeningToRelays,
);
// 断开连接
await Nostr.instance.relaysService.disconnectFromRelays();
发送事件
// 同步发送
Nostr.instance.relaysService.sendEventToRelays(
event,
onOk: (ok) => print(ok),
);
// 带有自定义超时的同步发送
final okCommand = await Nostr.instance.relaysService.sendEventToRelaysAsync(
event,
timeout: const Duration(seconds: 3),
);
print(okCommand);
注意:sendEventToRelaysAsync
将在某个中继接受事件时解析为 OkCommand
。
发送 NIP45 COUNT
// 创建计数事件
final countEvent = NostrCountEvent.fromPartialData(
eventsFilter: NostrFilter(
kinds: const [0],
authors: [keyPair.public],
),
);
// 同步发送计数事件
Nostr.instance.relaysService.sendCountEventToRelays(
countEvent,
onCountResponse: (countRes) {
print('count: $countRes');
},
);
// 异步发送计数事件
final countRes = await Nostr.instance.relaysService.sendCountEventToRelaysAsync(
countEvent,
timeout: const Duration(seconds: 3),
);
print("found ${countRes.count} events");
中继元数据 NIP11
final relayDoc = await Nostr.instance.relaysService.relayInformationsDocumentNip11(
relayUrl: "wss://relay.damus.io",
);
print(relayDoc?.name);
print(relayDoc?.description);
print(relayDoc?.contact);
print(relayDoc?.pubkey);
print(relayDoc?.software);
print(relayDoc?.supportedNips);
print(relayDoc?.version);
更多功能
包中还暴露了一些有用的方法,如:
// 处理 nevent 和 nevent
final nevent = Nostr.instance.utilsService.encodeNevent(
eventId: event.id,
pubkey: pubkey,
userRelays: [],
);
print(nevent);
final map = Nostr.instance.utilsService.decodeNeventToMap(nevent);
print(map);
// 处理 nprofile
final nprofile = Nostr.instance.utilsService.encodeNProfile(
pubkey: pubkey,
userRelays: [],
);
print(nprofile);
final map = Nostr.instance.utilsService.decodeNprofileToMap(nprofile);
print(map);
更多功能
生成随机 64 位十六进制字符串
final random = Nostr.instance.utilsService.random64HexChars();
final randomButBasedOnInput = Nostr.instance.utilsService.consistent64HexChars("input");
print(random);
print(randomButBasedOnInput);
NIP05 相关
/// 验证 NIP05 标识符
final verified = await Nostr.instance.utilsService.verifyNip05(
internetIdentifier: "something@domain.com",
pubKey: pubKey,
);
print(verified); // true
/// 验证 NIP05 标识符格式
final isValid = Nostr.instance.utilsService.isValidNip05Identifier("work@gwhyyy.com");
print(isValid); // true
/// 从 NIP05 标识符获取公钥
final pubKey = await Nostr.instance.utilsService.pubKeyFromIdentifierNip05(
internetIdentifier: "something@somain.c",
);
print(pubKey);
NIP13 十六进制难度
Nostr.instance.utilsService.countDifficultyOfHex("002f");
更多关于Flutter插件dart_nostr的使用_dart_nostr 是一个用于快速和简便开发 Nostr 客户端应用的 Dart/Flutter 工具包。的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter插件dart_nostr的使用_dart_nostr 是一个用于快速和简便开发 Nostr 客户端应用的 Dart/Flutter 工具包。的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,作为一个IT专家,我可以为你提供一个关于如何在Flutter项目中使用dart_nostr
插件的基本示例。不过,需要注意的是,dart_nostr
并不是Flutter社区中广泛认知的标准插件之一,所以我将基于假设的API和一般的Flutter插件使用方式来编写代码。如果dart_nostr
是一个真实存在的插件,你需要根据官方文档进行具体实现。
假设dart_nostr
插件提供了某些特定的功能,比如与Nostr网络(一种假设的区块链网络)进行交互,我们可以按照以下步骤来集成和使用这个插件。
1. 添加依赖
首先,你需要在pubspec.yaml
文件中添加dart_nostr
的依赖。如果这是一个真实存在的插件,你应该能在pub.dev上找到它并获取正确的依赖项名称和版本。
dependencies:
flutter:
sdk: flutter
dart_nostr: ^x.y.z # 假设的版本号
然后运行flutter pub get
来安装依赖。
2. 导入插件
在你的Dart文件中导入dart_nostr
插件。
import 'package:dart_nostr/dart_nostr.dart';
3. 初始化插件并使用其功能
假设dart_nostr
提供了连接到Nostr网络、发送交易和查询余额等功能,下面是一个简单的使用示例:
import 'package:flutter/material.dart';
import 'package:dart_nostr/dart_nostr.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String? balance;
@override
void initState() {
super.initState();
// 初始化插件并连接到Nostr网络
initNostr();
}
void initNostr() async {
// 假设有一个初始化函数
try {
await Nostr.initialize('your_network_config');
// 获取余额
String? result = await Nostr.getBalance('your_wallet_address');
setState(() {
balance = result;
});
} catch (e) {
print('Error initializing Nostr: $e');
}
}
void sendTransaction() async {
// 发送交易的示例
try {
String? txId = await Nostr.sendTransaction(
from: 'your_wallet_address',
to: 'recipient_wallet_address',
amount: '1.0', // 假设金额格式
fee: '0.01', // 假设手续费格式
);
print('Transaction sent with ID: $txId');
} catch (e) {
print('Error sending transaction: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Nostr Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Your Balance:',
),
Text(
balance ?? 'Loading...',
style: TextStyle(fontSize: 24),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: sendTransaction,
child: Text('Send Transaction'),
),
],
),
),
);
}
}
注意
- 依赖项和API:上面的代码是基于假设的API和依赖项编写的。你需要根据
dart_nostr
插件的实际文档和API来调整代码。 - 错误处理:在生产环境中,你应该添加更详细的错误处理和用户反馈机制。
- 安全性:处理钱包地址和交易时,请确保你的应用采取了适当的安全措施,以防止敏感信息泄露。
如果你找不到dart_nostr
插件的官方文档,可能需要联系插件的开发者或检查是否有其他类似功能的插件可用。