macos程序 swift

2020-04-30 13:56:48 KimBing 阅读数 150

Swift macOS NSWindow runModal() 如何在点击窗口关闭的时候取消程序的 modal 状态

当你用 application.runModal(for: demoWindow) 展示一个 demoWindow 窗口的时候,如果点击这个窗口左上角的关闭按钮关闭了这个窗口,在不做任何处理的情况下,当前应用还处于 Modal 状态,就是说其它窗口此时是无法操作的,只有程序退出 Modal 状态,才能操作其它窗口。

环境是这样的

StoryBoard 中有个 ID 为 DemoWindowController 的窗口 NSWindowController,这个 DemoWindowController 的内容窗口是跟 DemoVC.swift 这个类绑定的窗口

实现关闭时退出 Modal 状态

方法是这样的:

  1. 在要展示窗口之前,把目标窗口 DemoWindow 的 delegate 设置为 DemoVC.swift 自己
  2. DemoWindow.swift 中实现 NSWindowDelegate 这个协议,并实现 func windowShouldClose(_ sender: NSWindow) -> Bool 这个方法
  3. 在这个方法中实现 application.stopModal() 的操作
  4. 这样,在 DemoWindow 执行关闭窗口的操作时,就会通知 delegete 去执行窗口关闭的方法,退出程序的 Modal 状态

代码

WindowController 文件内容片断

  let storyboard = NSStoryboard(name: "Main", bundle: nil)
  // 1. 获取要展示的 WindowController
  let demoWindowController = storyboard.instantiateController(withIdentifier: "DemoWindowController") as! NSWindowController
  
  if let demoWindow = demoWindowController.window{
    // 2. 获取对应这个窗口的内容 ViewController
    let demoVC = demoWindow.contentViewController as! DemoVC
    
    // 3. 展示的时候把窗口的 delegate 指向自己
    demoWindow = demoVC // 设置
    
    // 3. 以 Modal 形式展示窗口
    let application = NSApplication.shared
    application.runModal(for: demoWindow)
    // 4
    demoWindow.close()
  }

要以 Modal 形式展示的窗口内容片断

extension RootFileEditor: NSWindowDelegate {
    func windowShouldClose(_ sender: NSWindow) -> Bool {
        let application = NSApplication.shared
        // 关闭窗口时,退出 Modal 状态
        application.stopModal()
        return true
    }
}
2020-04-17 17:42:51 KimBing 阅读数 274

Swift macOS 点击窗口关闭按钮,退出程序

在项目中的 AppDelegate 文件中添加如下方法

// 意思是,当关闭app的最后一个窗口时,退出 app
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
    true
}
2018-06-01 06:04:54 weixin_34393428 阅读数 151

原文地址

缘起

最近在 MacOS 日常使用当中,发现有个麻烦事情,就是我经常会压缩一些文件(或者文件夹)来分享给好友。
这些 zip 压缩文件除了便于网络传输就没有其他的用处了,所以每次我的操作就是:

  1. 压缩想要分享的 app 或 文件/文件夹
  2. 将压缩后的 zip 文件发送给好友
  3. 删除不再使用的 zip 文件

我觉得每次删除这些 zip 显得非常多余,有没有什么办法能让这些 zip 文件在我分享完了过后自动就消失呢?

答案是:有!这些问题还能难倒软件工程师?

ShadowZip 介绍

当然我的办法并不是调用系统某某神奇的 API,真的是让这些 zip 文件自动消失(如果有,请告诉我? ),
而是用 Swift 编写了一个 MacOS 软件 ShadowZip
来曲线救国,先让我们来看看效果:

20180501152518169155976.gif

使用教程

  1. 复制你要压缩的文件,可选择多个文件以及文件夹
  2. 左键单击 ShadowZip 状态栏的图标,程序会自动将你刚才复制的文件进行压缩,压缩完成后会自动将文件放在你的剪贴板
  3. 直接在目的地粘贴即可,压缩后的文件即被粘贴到目的地

你不用去操心 zip 文件放在什么地方,如何被删除,因为它们都是在系统的缓存目录中,当你重新启动后即会被自动删除。
如果你的确想要查看缓存目录或者手动清除缓存目录,试试右键单击 ShadowZip 状态栏图标。

程序运行机制

其实这个软件所做的工作就只有下面这几步:

  1. 从剪贴板读取需要压缩的文件列表
  2. 创建压缩文件,并且将其放入系统指定的缓存目录里
  3. 将该文件的地址写入到剪贴板里面,从而可以让你直接粘贴发送

如果你也有类似需求,可以到 Github 下载 试一试!

关键代码阅读

今天修复了几个 Bug,时间不太够,先埋坑,改天补上!

原文地址

2018-09-11 11:05:37 weixin_41483813 阅读数 978

MacOS上键盘/鼠标控制应用的Swift语言开发笔记

背景

继续在做小gadget,先学习基本操作。
这次需要实现的功能是程序控制键盘和鼠标,也就是人不需要碰键盘鼠标而键盘自动输入,鼠标自动移动点击的功能。

网上搜索了一下,Objective-C的实现例子倒是不少,可是基本找不到太多讲swift上面实现的例子,无奈自行摸索,在此总结一下。

准备

本功能应该属于Accessibility(辅助功能)的范畴,测试需要给予Xcode相应的操作权限。
打开【系统编好设置】,【安全性与隐私】,【隐私】里面勾选Xcode前面的方框。如果看不到Xcode的话手动添加。

库和官方文件

需要用到Core Graphics里面的
* Quartz Event Services | Apple Developer Documentation
* Quartz Display Services | Apple Developer Documentation

按键事件控制键盘

首先定义所需要的按键事件,然后通过post方法让系统执行事件。
每一次按键需要先按下再离开,通过函数分别定义这两个操作。

属性方面:

  • 这里的CGEventSourceStateID看了一下官方文件,分privateState,combinedSessionState和hidSystemState三种,这里选择最后一个,一般source定义为nil也可以。
  • virtualKey后面是需要的按键的代码,mac的英语键盘的话参考文末的一览表。
  • keyDown当然true是按下,false是松开了
  • tap后面是按键时候的鼠标位置
//按下按键
func keyboardKeyDown(key: CGKeyCode) {

        let source = CGEventSource(stateID: CGEventSourceStateID.hidSystemState)
        let event = CGEvent(keyboardEventSource: source, virtualKey: key, keyDown: true) 
        event?.post(tap: CGEventTapLocation.cghidEventTap)
        print("key \(key) is down")
    }

//松开按键    
func keyboardKeyUp(key: CGKeyCode) {
        let source = CGEventSource(stateID: CGEventSourceStateID.hidSystemState)
        let event = CGEvent(keyboardEventSource: source, virtualKey: key, keyDown: false)
        event?.post(tap: CGEventTapLocation.cghidEventTap)
        print("key \(key) is released")
    }

按键例子

比如说需要按下F5的话,调用上面两个函数就可以

keyboardKeyDown(key: 0x60) //0x60是F5功能键代码
keyboardKeyUp(key: 0x60)

Command+C怎么办?

这时候加入CGEventFlags - Core Graphics | Apple Developer Documentation

let cmd_c_D = CGEventCreateKeyboardEvent(nil, 0x08, true); //0x08是C键代码 cmd-c down
CGEventSetFlags(cmd_c_D, CGEventFlags.MaskCommand);
CGEventPost(CGEventTapLocation.CGHIDEventTap, cmd-c-D);

let cmd_c_U = CGEventCreateKeyboardEvent(nil, 0x08, false); // cmd-c up
CGEventSetFlags(cmd_c_U, CGEventFlags.MaskCommand);
CGEventPost(CGEventTapLocation.CGHIDEventTap, cmd_c_U);

shift,control等都有相应的CGEventSetFlags

鼠标控制

鼠标控制注意

  • 移动鼠标和显示移动后的鼠标是不同的事件操作。
  • 还有注意显示器的坐标轴原点不是左上角,而是左下角。留意别搞错y轴的方向了。

移动点击鼠标事件

// 鼠标左键按下
guard let mouseDown = CGEvent(mouseEventSource: nil,
                        mouseType: .leftMouseDown,
                        mouseCursorPosition: CGPoint(x: 200, y: 300),
                        mouseButton: .left
                        ) else {return}
mouseDown?.post(tap: .cghidEventTap)

// 鼠标左键抬起
guard let mouseUp = CGEvent(mouseEventSource: nil,
                      mouseType: .leftMouseUp,
                      mouseCursorPosition: CGPoint(x: 200, y: 300),
                      mouseButton: .left
                      ) else {return}
mouseUp?.post(tap: .cghidEventTap)

属性一览表:CGEventType - Core Graphics | Apple Developer Documentation

只移动鼠标

guard let moveEvent = CGEvent(mouseEventSource: nil, mouseType: .mouseMoved, 
                      mouseCursorPosition: point, mouseButton: .left 
                      ) else {return}
moveEvent?.post(tap: .cghidEventTap)

移动屏幕上面的鼠标图标

利用上面的事件移动鼠标之后,屏幕上的鼠标图标是不动的。需要再用下面操作才能看到鼠标的图标在屏幕上面移动了。

func CGDisplayMoveCursorToPoint(_ display: CGDirectDisplayID, 
                              _ point: CGPoint) -> CGError

完整的鼠标移动函数

func moveMouse(_ dx:CGFloat , _ dy:CGFloat){
  //先监控移动前鼠标位置
  var mouseLoc = NSEvent.mouseLocation  
  mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLoc.y;
  //计算鼠标新位置
  let newLoc = CGPoint(x: mouseLoc.x-CGFloat(dx), y: mouseLoc.y+CGFloat(dy)) 
  print("moving \(dx) \(dy)")
  CGDisplayMoveCursorToPoint(0, newLoc)
    }

其他先留坑

附录

MouseType类型

/* Constants that specify the different types of input events. */
public enum CGEventType : UInt32 {


    /* The null event. */
    case null


    /* Mouse events. */
    case leftMouseDown

    case leftMouseUp

    case rightMouseDown

    case rightMouseUp

    case mouseMoved

    case leftMouseDragged

    case rightMouseDragged


    /* Keyboard events. */
    case keyDown

    case keyUp

    case flagsChanged


    /* Specialized control devices. */
    case scrollWheel

    case tabletPointer

    case tabletProximity

    case otherMouseDown

    case otherMouseUp

    case otherMouseDragged


    /* Out of band event types. These are delivered to the event tap callback
       to notify it of unusual conditions that disable the event tap. */
    case tapDisabledByTimeout

    case tapDisabledByUserInput
}

Mac的键盘代码一览

/*
 *  Summary:
 *    Virtual keycodes
 *  
 *  Discussion:
 *    These constants are the virtual keycodes defined originally in
 *    Inside Mac Volume V, pg. V-191. They identify physical keys on a
 *    keyboard. Those constants with "ANSI" in the name are labeled
 *    according to the key position on an ANSI-standard US keyboard.
 *    For example, kVK_ANSI_A indicates the virtual keycode for the key
 *    with the letter 'A' in the US keyboard layout. Other keyboard
 *    layouts may have the 'A' key label on a different physical key;
 *    in this case, pressing 'A' will generate a different virtual
 *    keycode.
 */
enum {
  kVK_ANSI_A                    = 0x00,
  kVK_ANSI_S                    = 0x01,
  kVK_ANSI_D                    = 0x02,
  kVK_ANSI_F                    = 0x03,
  kVK_ANSI_H                    = 0x04,
  kVK_ANSI_G                    = 0x05,
  kVK_ANSI_Z                    = 0x06,
  kVK_ANSI_X                    = 0x07,
  kVK_ANSI_C                    = 0x08,
  kVK_ANSI_V                    = 0x09,
  kVK_ANSI_B                    = 0x0B,
  kVK_ANSI_Q                    = 0x0C,
  kVK_ANSI_W                    = 0x0D,
  kVK_ANSI_E                    = 0x0E,
  kVK_ANSI_R                    = 0x0F,
  kVK_ANSI_Y                    = 0x10,
  kVK_ANSI_T                    = 0x11,
  kVK_ANSI_1                    = 0x12,
  kVK_ANSI_2                    = 0x13,
  kVK_ANSI_3                    = 0x14,
  kVK_ANSI_4                    = 0x15,
  kVK_ANSI_6                    = 0x16,
  kVK_ANSI_5                    = 0x17,
  kVK_ANSI_Equal                = 0x18,
  kVK_ANSI_9                    = 0x19,
  kVK_ANSI_7                    = 0x1A,
  kVK_ANSI_Minus                = 0x1B,
  kVK_ANSI_8                    = 0x1C,
  kVK_ANSI_0                    = 0x1D,
  kVK_ANSI_RightBracket         = 0x1E,
  kVK_ANSI_O                    = 0x1F,
  kVK_ANSI_U                    = 0x20,
  kVK_ANSI_LeftBracket          = 0x21,
  kVK_ANSI_I                    = 0x22,
  kVK_ANSI_P                    = 0x23,
  kVK_ANSI_L                    = 0x25,
  kVK_ANSI_J                    = 0x26,
  kVK_ANSI_Quote                = 0x27,
  kVK_ANSI_K                    = 0x28,
  kVK_ANSI_Semicolon            = 0x29,
  kVK_ANSI_Backslash            = 0x2A,
  kVK_ANSI_Comma                = 0x2B,
  kVK_ANSI_Slash                = 0x2C,
  kVK_ANSI_N                    = 0x2D,
  kVK_ANSI_M                    = 0x2E,
  kVK_ANSI_Period               = 0x2F,
  kVK_ANSI_Grave                = 0x32,
  kVK_ANSI_KeypadDecimal        = 0x41,
  kVK_ANSI_KeypadMultiply       = 0x43,
  kVK_ANSI_KeypadPlus           = 0x45,
  kVK_ANSI_KeypadClear          = 0x47,
  kVK_ANSI_KeypadDivide         = 0x4B,
  kVK_ANSI_KeypadEnter          = 0x4C,
  kVK_ANSI_KeypadMinus          = 0x4E,
  kVK_ANSI_KeypadEquals         = 0x51,
  kVK_ANSI_Keypad0              = 0x52,
  kVK_ANSI_Keypad1              = 0x53,
  kVK_ANSI_Keypad2              = 0x54,
  kVK_ANSI_Keypad3              = 0x55,
  kVK_ANSI_Keypad4              = 0x56,
  kVK_ANSI_Keypad5              = 0x57,
  kVK_ANSI_Keypad6              = 0x58,
  kVK_ANSI_Keypad7              = 0x59,
  kVK_ANSI_Keypad8              = 0x5B,
  kVK_ANSI_Keypad9              = 0x5C
};

/* keycodes for keys that are independent of keyboard layout*/
enum {
  kVK_Return                    = 0x24,
  kVK_Tab                       = 0x30,
  kVK_Space                     = 0x31,
  kVK_Delete                    = 0x33,
  kVK_Escape                    = 0x35,
  kVK_Command                   = 0x37,
  kVK_Shift                     = 0x38,
  kVK_CapsLock                  = 0x39,
  kVK_Option                    = 0x3A,
  kVK_Control                   = 0x3B,
  kVK_RightShift                = 0x3C,
  kVK_RightOption               = 0x3D,
  kVK_RightControl              = 0x3E,
  kVK_Function                  = 0x3F,
  kVK_F17                       = 0x40,
  kVK_VolumeUp                  = 0x48,
  kVK_VolumeDown                = 0x49,
  kVK_Mute                      = 0x4A,
  kVK_F18                       = 0x4F,
  kVK_F19                       = 0x50,
  kVK_F20                       = 0x5A,
  kVK_F5                        = 0x60,
  kVK_F6                        = 0x61,
  kVK_F7                        = 0x62,
  kVK_F3                        = 0x63,
  kVK_F8                        = 0x64,
  kVK_F9                        = 0x65,
  kVK_F11                       = 0x67,
  kVK_F13                       = 0x69,
  kVK_F16                       = 0x6A,
  kVK_F14                       = 0x6B,
  kVK_F10                       = 0x6D,
  kVK_F12                       = 0x6F,
  kVK_F15                       = 0x71,
  kVK_Help                      = 0x72,
  kVK_Home                      = 0x73,
  kVK_PageUp                    = 0x74,
  kVK_ForwardDelete             = 0x75,
  kVK_F4                        = 0x76,
  kVK_End                       = 0x77,
  kVK_F2                        = 0x78,
  kVK_PageDown                  = 0x79,
  kVK_F1                        = 0x7A,
  kVK_LeftArrow                 = 0x7B,
  kVK_RightArrow                = 0x7C,
  kVK_DownArrow                 = 0x7D,
  kVK_UpArrow                   = 0x7E
};

参考和其他注意事项:

let opts = NSDictionary(object: kCFBooleanTrue,
                        forKey: kAXTrustedCheckOptionPrompt.takeUnretainedValue() as NSString
                        ) as CFDictionary

guard AXIsProcessTrustedWithOptions(opts) == true else { return }

վ HᴗP ի

2018-11-28 08:48:11 mongo_node 阅读数 259

SwiftyEOS是一个用于与EOS交互的开源框架,用Swift编写。可以在iOS和macOS上使用。

特点:

  • EOS密钥对生成
  • 私钥导入
  • 签名哈希
  • 基本的RPC API(链/历史)可查询客户端
  • 交易(EOS token 转账)
  • 帮助类处理iOS上的脱机钱包
  • 在iOS上加密/解密导入私钥

如何使用它

  • 1.将LibrariesSources文件夹复制到项目中,不需要main.swift
  • 2.如果不是针对iOS平台,请删除Sources/Utils/iOS
  • 3.将Libraries/include添加到Header搜索路径中。
  • 4.将Libraries/include/Bridging-Header.h设置为Objective-C Bridging Header。如果你有自己的bridging header,请复制该文件中的所有导入内容并粘贴到你自己的文件中。
  • 5.编译然后等结果

密钥对生成

SwiftyEOS现在支持secp256k1密钥对。

secp256r1密钥对生成有bug但我无法弄清楚原因。从cleos创建的单元测试创建密钥--r1不会通过。你可能不会将secp256r1视为一个选项,因为cleos wallet命令也无法导入这些键。

生成随机密钥对:

let (pk, pub) = generateRandomKeyPair(enclave: .Secp256k1)

很容易对吧?

print("private key: \(pk!.wif())")
print("public key : \(pub!.wif())")

// private key: PVT_K1_5HxrYTdZX89zodtJhTzCk87MfNZAkiBRfFvSX8kacYjtwaDpTkL
// public key : PUB_K1_4yDYdmcVcXxAxeNsUWRG7x9FKQE4HbJZdzgZFv1AYxk6oSVcLd

PVT_K1_PUB_K1_前缀是标准密钥表示的一部分。但是EOS系统和SwiftyEOS也支持旧方式:

print("private key: \(pk!.rawPrivateKey())")
print("public key : \(pub!.rawPublicKey())")

// private key: 5HxrYTdZX89zodtJhTzCk87MfNZAkiBRfFvSX8kacYjtwaDpTkL
// public key : EOS4yDYdmcVcXxAxeNsUWRG7x9FKQE4HbJZdzgZFv1AYxk6oSVcLd

导入现有密钥:

let importedPk = try PrivateKey(keyString: "5HxrYTdZX89zodtJhTzCk87MfNZAkiBRfFvSX8kacYjtwaDpTkL")
let importedPub = PublicKey(privateKey: importedPk!)

带分隔符和前缀:

let importedPk = try PrivateKey(keyString: "PVT_K1_5HxrYTdZX89zodtJhTzCk87MfNZAkiBRfFvSX8kacYjtwaDpTkL")
let importedPub = PublicKey(privateKey: importedPk!)

RPC API

EOSRPC.sharedInstance.chainInfo { (chainInfo, error) in
    if error == nil {
        print("Success: \(chainInfo!)")
    } else {
        print("Error: \(error!.localizedDescription)")
    }
}

目前我们有一些基本的RPC端点,你可以在Sources/SwiftyEOS/Network找到它。

iOS的密钥存储

我们有SEWallet.swift iOS版离线钱包管理助手。

SEWallet.swift可以方便地保存AES加密的密钥信息到文件系统。默认位置是应用程序的沙盒。

目前还不支持多个钱包管理。

在iOS上创建新钱包

在Objective-C中:

[SEKeystoreService.sharedInstance newAccountWithPasscode:passcode succeed:^(SELocalAccount *account) {
} failed:^(NSError *error) {
        
}];

检索已保存的钱包

[SELocalAccount currentAccount];

如果没有保存钱包,它将返回零。

交易

交易行为目前尚未完全支持,但你仍可以尝试使用main.swift中的示例代码。

整个功能完成后,将提供相关文件。

  • 货币转账(2018.08.15)
  • 提交一般交易(2018.08.16)
  • iOS上的设备上(离线)钱包锁定和解锁(2018.08.17)
  • 押注/取消押注/净值(2018.08.28)
  • 买/卖ram(2018.08.28)
  • 创建账户(2018.10)
  • 用params列表推送交易(2018.11.05)
  • 使用助记符创建/导入密钥对

货币转账

var transfer = Transfer()
transfer.from = "agoodaccount"
transfer.to = "gq3dinztgage"
transfer.quantity = "1.0000 EOS"
transfer.memo = "eureka"

Currency.transferCurrency(transfer: transfer, code: "eosio.token", privateKey: importedPk!, completion: { (result, error) in
    if error != nil {
        if error is RPCErrorResponse {
            print("\((error as! RPCErrorResponse).errorDescription())")
        } else {
            print("other error: \(String(describing: error?.localizedDescription))")
        }
    } else {
        print("done.")
    }
})

提交一般交易

swift:

let account = "raoji"
let asset = "1.0000 EPRA"

let data = "{\"hey\": {\"account\":\"" + account  + "\", \"quantity\":\"" + asset + "\"}}"
let abi = try! AbiJson(code: "prabox1", action: "withdraw", json: data)

TransactionUtil.pushTransaction(abi: abi, account: account, privateKey: importedPk!, completion: { (result, error) in
    if error != nil {
        if (error! as NSError).code == RPCErrorResponse.ErrorCode {
            print("\(((error! as NSError).userInfo[RPCErrorResponse.ErrorKey] as! RPCErrorResponse).errorDescription())")
        } else {
            print("other error: \(String(describing: error?.localizedDescription))")
        }
    } else {
        print("Ok. Txid: \(result!.transactionId)")
    }
})

Objective-C:

AbiJson *your_abi;
[TransactionUtil pushTransactionWithAbi:your_abi
                                account:@"your_account"
                               pkString:@"your_private_key"
                             completion:^(TransactionResult *result, NSError *error) {
        
}];

iOS上的设备上(离线)钱包锁定和解锁

我们添加locktimedUnlock函数到SELocalAccount

Cpu/net/ram 操作

ResourceUtil.swift文件包括ResourceUtil类,包括下面几个方法:

  • stakeResource
  • unstakeResource
  • buyRam
  • sellRam

Stake resource:

ResourceUtil.stakeResource(account: "raoji", net: 1.0, cpu: 1.0, pkString: "5HsaHvRCPrjU3yhapB5rLRyuKHuFTsziidA13Uw6WnQTeJAG3t4", completion: { (result, error) in
})

助记符

建一个新的密钥对:

let (pk, pub, mn) = generateRandomKeyPair(enclave: .Secp256k1)

导入现有助记符:

let (pk, mn) = PrivateKey(enclave: .Secp256k1, mnemonicString: "your words here")

我们在SEWallet.swift中有密钥管理的iOS助手API和助记符。现在可以使用SEKeystoreService类创建和导入助记符(如果你自己存储,则可以使用SEKeystore更深入的API):

SEKeystoreService.sharedInstance.newAccountAndMnemonic(passcode: "your pass here", succeed: { (account, mnemonic) in

}) { (error) in

}

我们正在为所有顶级API使用NSObject固有类,因此在不提供额外桥接文件的情况下调用Objective-C也是一样的。

SEWallet.swift文件中也有iOS的帮助方法。

谢谢。

======================================================================

分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:

  • EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是原文Swift编写的EOS开源框架SwiftyEOS