Flutter插件dart_nostr的使用_dart_nostr 是一个用于快速和简便开发 Nostr 客户端应用的 Dart/Flutter 工具包。

发布于 1周前 作者 zlyuanteng 最后一次编辑是 5天前 来自 Flutter

Flutter插件dart_nostr的使用_dart_nostr 是一个用于快速和简便开发 Nostr 客户端应用的 Dart/Flutter 工具包。

dart_nostr 是一个用于快速和简便开发 Nostr 客户端应用的 Dart/Flutter 工具包。

目录

支持的NIPs

如果你正在开发 Nostr 客户端或应用程序,你可以应用并使用以下所有 NIPs(截至 2024-01-18):

标记为“尚未实现”的 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

1 回复

更多关于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'),
            ),
          ],
        ),
      ),
    );
  }
}

注意

  1. 依赖项和API:上面的代码是基于假设的API和依赖项编写的。你需要根据dart_nostr插件的实际文档和API来调整代码。
  2. 错误处理:在生产环境中,你应该添加更详细的错误处理和用户反馈机制。
  3. 安全性:处理钱包地址和交易时,请确保你的应用采取了适当的安全措施,以防止敏感信息泄露。

如果你找不到dart_nostr插件的官方文档,可能需要联系插件的开发者或检查是否有其他类似功能的插件可用。

回到顶部