mobile

package
v0.0.0-...-63185e8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 1, 2023 License: Apache-2.0 Imports: 22 Imported by: 0

README

开发基于FISCO BCOS区块链的iOS应用

1. 获得iOS SDK

您可以直接下载FiscoBcosIosSdk.framework库,如果您完成了下载,请跳过这一步。

第一步. 准备环境
  1. 安装golang 1.17及以上版本

  2. 安装gomobile

    cd ~
    # 如果您处在国内的网络环境中,请执行设置GORPOXY的步骤
    export GOPROXY=https://goproxy.cn,https://goproxy.io,direct
    # 确保GO111MODULE=on
    export GO111MODULE=on
    # 设置环境变量
    export PATH=$PATH:~/go/bin
    # 安装gomobile
    go get golang.org/x/mobile/cmd/gomobile
    
第二步. 下载go-sdk源码
# 下载代码
mkdir -p ~/go/src/github.com/FISCO-BCOS && cd ~/go/src/github.com/FISCO-BCOS && git clone https://github.com/FISCO-BCOS/go-sdk.git && cd go-sdk
# 切换到develop分支
git checkout -b develop origin/develop
# 下载依赖
go mod download
第三步. 编译iOS SDK
# 编译iOS SDK,当前目录~/go/src/github.com/FISCO-BCOS/go-sdk
export CGO_LDFLAGS_ALLOW=".*"
gomobile bind -target=ios -o FiscoBcosIosSdk.framework  --ldflags='-s -w' :./mobile/ios
# 编译成功后,目录下会多了一个FiscoBcosIosSdk.framework目录

2. 生成Objective-c合约

第一步. 准备Solidity合约
# 当前目录~/go/src/github.com/FISCO-BCOS/go-sdk
mkdir helloworld && cd helloworld
# 将HelloWorld合约拷贝到目录下
cp ../.ci/hello/HelloWorld.sol .

HelloWorld.sol

pragma solidity>=0.4.24 <0.6.11;

contract HelloWorld {
    string value;

    constructor() public {
        value = "Hello, World!";
    }

    function get() public view returns (string memory) {
        return value;
    }

    function set(string v) public {
        value = v;

    }
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
    [alertController addAction:cancelAction];
    [self presentViewController:alertController animated:YES completion:nil];
}

第二步. 编译合约
# 当前目录~/go/src/github.com/FISCO-BCOS/go-sdk/helloworld
# 下载编译器
bash ../tools/download_solc.sh -v 0.8.11
# 编译合约
./solc-0.8.11 --bin --abi -o ./ ./HelloWorld.sol
# 得到HelloWorld.abi, HelloWorld.bin, HelloWorld.sol, solc-0.8.11, 生成了ABI和Bin文件
第三步. 生成Objective-c调用接口
# 当前目录~/go/src/github.com/FISCO-BCOS/go-sdk/helloworld
# 编译生成abigen工具
go build ../cmd/abigen
# 生成Objective-c合约
./abigen --bin ./HelloWorld.bin --abi ./HelloWorld.abi --lang objc --pkg helloworld --type HelloWorld --out ./HelloWorld.m
ls
# 得到了HelloWorld.h,HelloWorld.m Objective-C调用接口

3. 开发基于FISCO BCOS区块链的iOS应用

第一步. 准备环境

安装Xcode:请打开AppStore -> 搜索Xcode -> 点击Get

第二步. 新建一个iOS应用项目

打开Xcode

点击Create a new Xcode project

选择iOSApp,点击next

在Product Name中输入HelloWorld, 并选择属性 Interface:Storyboard, LifeCycle:UIKit App Delegate, language:Objective-C1, 点击Next

选择项目所在的文件夹,点击Create,完成项目创建。

第三步. 将合约和iOS SDK引入项目中

将合约和iOS SDK放入项目中

# 当前位置 ~/go/src/github.com/FISCO-BCOS/go-sdk/helloworld
# 请替换 ~/code 为您存放HelloWorld项目的正确目录
cp -r HelloWorld.h HelloWorld.m ../FiscoBcosIosSdk.framework 你的项目路径/HelloWorld/HelloWorld/
# 拷贝私钥文件
cp ../.ci/0x83309d045a19c44dc3722d15a6abd472f95866ac.pem 你的项目路径/HelloWorld/HelloWorld/key.pem

私钥也可以参考这里,使用工具生成。

打开Finder,进入项目目录HelloWorld/HelloWorld,得到我们刚刚复制进去的文件和目录包括HelloWorld.h、HelloWorld.m、FiscoBcosIosSdk.framework、key.pem。选中这些文件和目录拖入Xcode中左边的项目文件夹结构的HelloWorld > HelloWorld下,点击确认

第四部. 搭建区块链网络和代理

区块链网络搭建:https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/installation.html

搭建代理:https://github.com/FISCO-BCOS/bcos-node-proxy/tree/feature_mobile_http

第五步. 开发应用

修改页面

点击Main.storyboard, 展示手机界面

创建一个按钮。点击+ 按钮, 选择Button,并拖拽至页面。修改按钮名称“Button” -> "Deploy"

创建一个按钮。点击+ 按钮, 选择Button,并拖拽至页面。修改按钮名称“Button” -> "Set"

创建一个输入框。点击+ 按钮, 选择Text Field,并拖拽至页面。

创建一个按钮。点击+ 按钮, 选择Button,并拖拽至页面。修改按钮名称“Button” -> "Get"

创建Button相关的事件

同时按下Control+Option+Command+Enter四个键,打开辅助功能。

添加Deploy按钮按下事件。右键手机屏幕上的Set按钮,在弹出的菜单中找到Touch Down,按住右边的圆圈并拖拽鼠标至下方的代码的- (void)viewDidLoad函数结束的下一行,并输入Name为deploy,点击connect,完成Deploy按钮按下事件的设置。

添加Set按钮按下事件。右键手机屏幕上的Set按钮,在弹出的菜单中找到Touch Down,按住右边的圆圈并拖拽鼠标至下方的代码的- (IBAction)deploy:(id)sender函数结束的下一行,并输入Name为set,点击connect,完成Set按钮按下事件的设置。

添加Get按钮按下事件。右键手机屏幕上的Get按钮,在弹出的菜单中找到Touch Down,按住右边的圆圈并拖拽鼠标至下方的代码的- (IBAction)set:(id)sender函数结束的下一行,并输入Name为get,点击connect,完成Get按钮按下事件的设置。

添加文本框作为属性。按住Control,点击手机屏幕上的文本框,拖动至下方代码的@interface ViewControler()的下一行,输入Name为setValue。

事件创建完成,得到如下ViewController.m的文件。

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *setValue;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}
- (IBAction)deploy:(id)sender {
}
- (IBAction)set:(id)sender {
}
- (IBAction)get:(id)sender {
}
@end

实现消息发送类

在HelloWorld/HelloWorld文件夹下单击右键New File.., 选择iOS, Cocoa Touch Class,点击next

输入Class: MyPostCallback, Subclass of: 空, language:Objective-C1, 点击Next , 然后点击Create,创建出MyPostCallback.h和MyPostCallback.m

MyPostCallback.h

#import <FiscoBcosIosSdk/FiscoBcosIosSdk.h>

NS_ASSUME_NONNULL_BEGIN

@interface MyPostCallback : NSObject<MobilePostCallback>

@end

NS_ASSUME_NONNULL_END

MyPostCallback.m

#import "MyPostCallback.h"

@implementation MyPostCallback

- (NSString* _Nonnull)sendRequest:(NSString* _Nullable)rpcRequest{
    NSURL *nsurl = [NSURL URLWithString:@"http://localhost:8170/Bcos-node-proxy/rpc/v1"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:nsurl];

    //设置请求类型
    request.HTTPMethod = @"POST";

    //将需要的信息放入请求头
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];//token

    //把参数放到请求体内
    request.HTTPBody = [rpcRequest dataUsingEncoding:NSUTF8StringEncoding];

    NSData *resultData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil] ;
    NSString * resultString = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
    NSLog(@"Get response: %@",resultString);
    return resultString;

}
@end

当你使用HTTP协议的Proxy时,请注意修改安全设置:

在项目的info.plist中添加一个Key:App Transport Security Settings,类型为字典类型。然后给它添加一个Key:Allow Arbitrary Loads,类型为Boolean类型,值为YES。

具体的,点击info.plist。在空白处右键Add Row, 输入App Transport Security Settings。在这个节点处点+按钮,添加新Key ,Allow Arbitrary Loads,类型为Boolean类型,值为YES

打开Finder将HelloWorld项目下HelloWorld/key.pem拖到Xcode右边项目栏HelloWorld文件夹下,得到目录

HelloWorld
|-----HelloWorld
|			|-----FiscoBcosIosSdk.framework
|			|-----HelloWorld.m
|			|-----HelloWorld.h
|			|-----Key.pem
|			|-----AppDelegate.h
|			|-----AppDelegate.m
|			|-----SceneDelegate.h
|			|-----SceneDelegate.m
|			|-----Main.storyboard
|			|-----Assets.xcassets
|			|-----LaunchScrean.storyboard
|			|-----Info.plist
|			|-----main.m
|			|-----MyPostCallback.h
|			|-----MyPostCallback.m
|
|-----HelloWorldTest (省略内部文件)
|-----HelloWorldUITest (省略内部文件)
|-----Products (省略内部文件)

调用Objective-C合约

在ViewController.m中实现方法

//
//  ViewController.m
//  HelloWorld
//
//  Created by Maggie WU on 2021/1/28.
//

#import "ViewController.h"
#import <FiscoBcosIosSdk/FiscoBcosIosSdk.h>
#import "MyPostCallback.h"
#import "HelloWorld.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *setValue;
@property (nonatomic,strong)MobileBcosSDK* sdk;
@property HelloWorld * contract;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *path = [NSBundle mainBundle].bundlePath;
    NSString *keyFile = [NSString stringWithFormat:@"%@/%@", path, @"key.pem" ];

    [super viewDidLoad];
    self.sdk = [[MobileBcosSDK alloc]init];
    MobileBuildSDKResult* result = [self.sdk buildSDKWithParam:keyFile groupID:1 chainID:1 isSMCrypto:false callback:[[MyPostCallback alloc] init]];
}
- (IBAction)deploy:(id)sender {
    UIAlertController *alertController;
    self.contract = [[HelloWorld alloc]init:self.sdk];
    MobileReceiptResult *dr = [self.contract deploy];
    long zero = 0;
    if (dr.code != zero){
        NSLog(@"send tx error : %@", dr.message);
        alertController = [UIAlertController alertControllerWithTitle:@"Result" message:dr.message preferredStyle:UIAlertControllerStyleAlert];
    }else{
        NSLog(@"send tx success : %@", dr.receipt.contractAddress);
        alertController = [UIAlertController alertControllerWithTitle:@"Result" message:dr.receipt.contractAddress preferredStyle:UIAlertControllerStyleAlert];
        self.contract = [self.contract initWithAddress:dr.receipt.contractAddress sdk:self.sdk];
    }
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
    [alertController addAction:cancelAction];
    [self presentViewController:alertController animated:YES completion:nil];
}
- (IBAction)set:(id)sender {
    UIAlertController *alertController;
    MobileReceiptResult *result = [self.contract set: self.setValue.text];

    long zero = 0;
    if (result.code != zero){
        NSLog(@"send tx error : %@", result.message);
        alertController = [UIAlertController alertControllerWithTitle:@"Result" message:result.message preferredStyle:UIAlertControllerStyleAlert];
    }else{
        NSLog(@"send tx success : %@", result.receipt.blockNumber);
        alertController = [UIAlertController alertControllerWithTitle:@"Result" message:result.receipt.blockNumber preferredStyle:UIAlertControllerStyleAlert];
    }
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
    [alertController addAction:cancelAction];
    [self presentViewController:alertController animated:YES completion:nil];
}
- (IBAction)get:(id)sender {
    UIAlertController *alertController;
    MobileCallResult *result = [self.contract get];
    long zero = 0;
    if (result.code != zero){
        NSLog(@"send tx error : %@", result.message);
        alertController = [UIAlertController alertControllerWithTitle:@"Result" message:result.message preferredStyle:UIAlertControllerStyleAlert];
    }else{
        NSLog(@"send tx success : %@", result.result);
        alertController = [UIAlertController alertControllerWithTitle:@"Result" message:result.result preferredStyle:UIAlertControllerStyleAlert];
    }
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
    [alertController addAction:cancelAction];
    [self presentViewController:alertController animated:YES completion:nil];
}
@end

运行应用

在标题栏设置设备为iPhone12,再点击标题栏左上角的三角形的运行按钮。

在显示的模拟器中进行合约操作。

首先,点击Deploy按钮部署HelloWorld合约。

然后,点击Get按钮显示值。

接着,在文本框中填写你想设置的值,点击Set按钮。

最后,点击Get按钮显示值。

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNoResult = errors.New("no result in JSON-RPC response")
)

Functions

This section is empty.

Types

type BcosSDK

type BcosSDK struct {
	// contains filtered or unexported fields
}

func (*BcosSDK) BuildSDKWithParam

func (sdk *BcosSDK) BuildSDKWithParam(keyFile string, callback PostCallback, groupID string, chainID string, isSMCrypto bool) *BuildSDKResult

BuildSDKWithParam Connect to the proxy or FISCO BCOS node. Please make sure ca.crt, sdk.crt, sdk.key under path certPath. Please provider full keyFile path

func (*BcosSDK) Call

func (sdk *BcosSDK) Call(abiContract string, address string, method string, params string, outputNum int) *CallResult

Call is a function to call a smart contract function without sending transaction return CallResult

func (*BcosSDK) DeployContract

func (sdk *BcosSDK) DeployContract(contractAbi string, contractBin string, params string) *ReceiptResult

DeployContract is a function to deploy a FISCO BCOS smart contract Return receipt

func (*BcosSDK) GetBlockNumber

func (sdk *BcosSDK) GetBlockNumber() *RPCResult

GetBlockNumber is to query the blockchain and get the latest block number. Return the latest block number

func (*BcosSDK) GetCallOpts

func (sdk *BcosSDK) GetCallOpts() *bind.CallOpts

GetCallOpts return *bind.CallOpts

func (*BcosSDK) GetClientVersion

func (sdk *BcosSDK) GetClientVersion() *RPCResult

RPC calls GetClientVersion is to query the client version of connected nodes

func (*BcosSDK) GetTransactOpts

func (sdk *BcosSDK) GetTransactOpts() *bind.TransactOpts

GetTransactOpts return *bind.TransactOpts

func (*BcosSDK) GetTransactionByHash

func (sdk *BcosSDK) GetTransactionByHash(txHash string) *TransactionResult

GetTransactionByHash is to query the blockchain and get the transaction of a transaction hash. Get transaction by tx hash

func (*BcosSDK) GetTransactionReceipt

func (sdk *BcosSDK) GetTransactionReceipt(txHash string) *ReceiptResult

GetTransactionReceipt is to query the blockchain and get the receipt of a transaction.

func (*BcosSDK) SendTransaction

func (sdk *BcosSDK) SendTransaction(contractAbi string, address string, method string, params string) *ReceiptResult

SendTransaction is a function to send an transaction to call smart contract function. return receipt

type BuildSDKResult

type BuildSDKResult struct {
	IsSuccess   bool   `json:"isSuccess"`
	Information string `json:"information"`
}

BuildSDKResult return when build sdk

type CallResult

type CallResult struct {
	Code    int
	Message string
	Result  string
}

CallResult return by call function

type ContractParams

type ContractParams struct {
	ValueType string      `json:"type"`
	Value     interface{} `json:"value"`
}

ContractParams Parameters

type ContractProxy

type ContractProxy struct {
	// contains filtered or unexported fields
}

func (*ContractProxy) AsyncSendTransaction

func (c *ContractProxy) AsyncSendTransaction(ctx context.Context, tx *types.Transaction, contract *common.Address, input []byte, handler func(*types.Receipt, error)) error

AsyncSendTransaction injects the transaction into the pending pool for execution.

func (*ContractProxy) Call

func (c *ContractProxy) Call(ctx context.Context, groupID string, msg ethereum.CallMsg) ([]byte, error)

func (*ContractProxy) CallContext

func (c *ContractProxy) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error

func (*ContractProxy) CallContract

func (c *ContractProxy) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)

ContractCall executes a Solidity contract call with the specified data as the input.

func (*ContractProxy) CodeAt

func (c *ContractProxy) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error)

CodeAt returns the code of the given account. This is needed to differentiate between contract internal errors and the local chain being out of sync.

func (*ContractProxy) GetBlockLimit

func (c *ContractProxy) GetBlockLimit(ctx context.Context) (*big.Int, error)

GetBlockLimit returns the blocklimit for current blocknumber

func (*ContractProxy) GetChainID

func (c *ContractProxy) GetChainID(ctx context.Context) (string, error)

GetChainID returns the chainID of the blockchain

func (*ContractProxy) GetContractAddress

func (c *ContractProxy) GetContractAddress(ctx context.Context, txHash common.Hash) (common.Address, error)

GetContractAddress returns the contract address once it was deployed

func (*ContractProxy) GetGroupID

func (c *ContractProxy) GetGroupID() string

GetGroupID returns the groupID of the client

func (*ContractProxy) PendingCodeAt

func (c *ContractProxy) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error)

PendingCodeAt returns the code of the given account in the pending state.

func (*ContractProxy) SMCrypto

func (c *ContractProxy) SMCrypto() bool

SMCrypto returns true if use sm crypto

func (*ContractProxy) SendTransaction

func (c *ContractProxy) SendTransaction(ctx context.Context, tx *types.Transaction, contract *common.Address, input []byte) (*types.Receipt, error)

SendTransaction injects the transaction into the pending pool for execution. todo ios 怎么处理?

func (*ContractProxy) SubscribeEventLogs

func (c *ContractProxy) SubscribeEventLogs(ctx context.Context, eventLogParams types.EventLogParams, handler func(int, []types.Log)) (string, error)

SubscribeEventLogs

func (*ContractProxy) UnSubscribeEventLogs

func (c *ContractProxy) UnSubscribeEventLogs(ctx context.Context, filterID string) error

type FullTransaction

type FullTransaction struct {
	BlockHash        string `json:"blockHash"`
	BlockNumber      string `json:"blockNumber"`
	From             string `json:"from"`
	Gas              string `json:"gas"`
	GasPrice         string `json:"gasPrice"`
	Hash             string `json:"hash"`
	Input            string `json:"input"`
	Nonce            string `json:"nonce"`
	To               string `json:"to"`
	TransactionIndex string `json:"transactionIndex"`
	Value            string `json:"value"`
}

type NetworkResponse

type NetworkResponse struct {
	Code    int             `json:"code"`
	Message string          `json:"message"`
	Result  json.RawMessage `json:"data"`
}

NetworkResponse data type return from the post callback

type PostCallback

type PostCallback interface {
	SendRequest(rpcRequest string) string
}

PostCallback delegate callback function, will implement in outside objc code

type RPCResult

type RPCResult struct {
	Code    int
	Message string
	Result  string
}

RPCResult return by rpc request

type ReceiptResult

type ReceiptResult struct {
	Code    int
	Message string
	Receipt *TxReceipt
}

ReceiptResult return by deploy and sendTransaction function.

type TransactionResult

type TransactionResult struct {
	Code        int
	Message     string
	Transaction *FullTransaction
}

TransactionResult result with transaction

type TxReceipt

type TxReceipt struct {
	TransactionHash string `json:"transactionHash"`
	BlockNumber     string `json:"blockNumber"`
	GasUsed         string `json:"gasUsed"`
	ContractAddress string `json:"contractAddress"`
	Status          int    `json:"status"`
	From            string `json:"from"`
	To              string `json:"to"`
	Input           string `json:"input"`
	Output          string `json:"output"`
	Logs            string `json:"logs"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL