您好,登錄后才能下訂單哦!
問題
在手機應用的開發中,通常會將復雜的業務邏輯層實現放在服務端,客戶端僅負責表現層。但是對于某些手機應用而言,業務邏輯的實現位于服務端反而是不安全的或是不合理的,而是需要將其邏輯直接在手機端實現。
目的
面對不同系統的手機客戶端,單獨重復實現相同的業務邏輯,并非最佳實踐。如何通過第三方語言 Go 語言將業務邏輯封裝成庫的形式,并以靜態打包的方式提供給不同系統的手機客戶端使用,是本次調研的目的。
理想目標圖:
cdn.xitu.io/2019/7/4/16bbd44a4c33a8ce?w=930&h=427&f=png&s=28182">
具體調研內容包括:
其中關于 gRPC 在 iOS 與 Android 的實現,本身官方就已經提供了樣例。本次調研會用到相關內容,所以將其作為調研的一部分記錄下來,方便后來者閱讀。調研中所有涉及的項目代碼均存放于: liujianping/grpc-apps 倉庫中, 需要的朋友可以直接下載測試。
原文發布在我的個人站點: GitDiG.com. 原文鏈接:iOS 應用實現 gRPC 調用 .
作為一名非專職 iOS 的程序員,經常需要調研陌生的技術或者語言。首先是要克服對于未知的畏懼心理。其實很多東西沒那么難,只是需要開始而已。 為了完成目標調研,開始第一部分的調研工作。以文字形式記錄下來,方便后來者。
沒什么好說的,直接 AppStore 下載安裝。有點慢,一邊下載一邊準備其它環境。
類似與其它語言的第三方庫管理工具。也沒什么好說的,登錄官網,按說明安裝。
$: sudo gem install cocoapods
因為 gRPC 的廣泛使用, ProtoBuf 協議被廣泛用于字節編碼與解碼的協議, 其具體指南參考[官網]()。話不多說,安裝:
$: curl -LOk https://github.com/protocolbuffers/protobuf/releases/download/v3.5.1/protoc-3.9.0-rc-1-osx-x86_64.zip
$: unzip protoc-3.9.0-rc-1-osx-x86_64.zip -d proto_buffer && cd proto_buffer
$: sudo cp bin/protoc /usr/local/bin
$: sudo cp -R include/google/protobuf/ /usr/local/include/google/protobuf
$: protoc --version
protoc 主要是通過解析 .proto
格式的文件, 再根據具體插件生成相應語言代碼。
考慮到需要同時實現客戶端與服務端的代碼,所以必須安裝以下三個插件:
swift 插件安裝:
$: git clone https://github.com/grpc/grpc-swift.git
$: cd grpc-swift
$: git checkout tags/0.5.1
$: make
$: sudo cp protoc-gen-swift protoc-gen-swiftgrpc /usr/local/bin
go 插件安裝:
前提是需要安裝 Go 語言的開發環境, 可參考官網。protoc-gen-go
安裝詳細指南.
$: go get -u github.com/golang/protobuf/protoc-gen-go
既然是最簡單的調研,就用最簡單的 Hello 服務。創建項目路徑并定義:
$: mkdir grpc-apps
$: cd grpc-apps
$: mkdir proto
$: cat <<EOF > proto/hello.proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.gitdig.helloworld";
option java_outer_classname = "HelloWorldProto";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
EOF
在項目目錄中創建服務端目錄與proto生成目錄,同時編寫一個簡單的服務端:
$: cd grpc-apps
$: mkdir go go/client go/server go/hello
# 生成 Go 代碼到 go/hello 文件夾
$: protoc -I proto proto/hello.proto --go_out=plugins=grpc:./go/hello/
分別編輯 Go 版本 client 與 server 實現。確認服務正常運行。
編輯 server/server.go
文件:
package main
import (
pb "github.com/liujianping/grpc-apps/go/helloworld"
)
import (
"context"
"fmt"
"log"
"net"
"google.golang.org/grpc"
)
type HelloServer struct{}
// SayHello says 'hi' to the user.
func (hs *HelloServer) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
// create response
res := &pb.HelloReply{
Message: fmt.Sprintf("hello %s from go", req.Name),
}
return res, nil
}
func main() {
var err error
// create socket listener
l, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("error: %v\n", err)
}
// create server
helloServer := &HelloServer{}
// register server with grpc
s := grpc.NewServer()
pb.RegisterGreeterServer(s, helloServer)
log.Println("server serving at: :50051")
// run
s.Serve(l)
}
運行服務端程序:
$: cd grpc-apps/go
$: go run server/server.go
2019/07/03 20:31:06 server serving at: :50051
編輯 client/client.go
文件:
package main
import (
pb "github.com/liujianping/grpc-apps/go/helloworld"
)
import (
"context"
"fmt"
"log"
"google.golang.org/grpc"
)
func main() {
var err error
// connect to server
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
log.Fatalf("error: %v\n", err)
}
defer conn.Close()
// create client
client := pb.NewGreeterClient(conn)
// create request
req := &pb.HelloRequest{Name: "JayL"}
// call method
res, err := client.SayHello(context.Background(), req)
if err != nil {
log.Fatalf("error: %v\n", err)
}
// handle response
fmt.Printf("Received: \"%s\"\n", res.Message)
}
執行客戶端程序:
$: cd grpc-apps/go
$: go run client/client.go
Received: "hello JayL from go"
Go 客戶端/服務端通信成功。
創建一個名為 iosDemo 的單視圖項目,選擇 swift 語言, 存儲路徑放在 grpc-apps
下。完成創建后,正常運行,退出程序。
在命令行執行初始化:
$: cd grpc-apps/iosDemo
# 初始化
$: pod init
$: vim Podfile
編輯 Podfile 如下:
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'iosDemo' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for iosDemo
pod 'SwiftGRPC'
end
完成編輯后保存,執行安裝命令:
$: pod install
安裝完成后,項目目錄發生以下變更:
$: git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: iosDemo.xcodeproj/project.pbxproj
Untracked files:
(use "git add <file>..." to include in what will be committed)
Podfile
Podfile.lock
Pods/
iosDemo.xcworkspace/
no changes added to commit (use "git add" and/or "git commit -a")
通過命令行 open iosDemo.xcworkspace
打開項目,對項目中的info.list的以下設置進行修改:
通過設置,開啟非安全的HTTP訪問方式。
類似 Go 代碼生成,現在生成 swift 代碼:
$: cd grpc-apps
# 創建生成文件存放目錄
$: mkdir swift
# 生成 swift 文件
$: protoc -I proto proto/hello.proto \
--swift_out=./swift/ \
--swiftgrpc_out=Client=true,Server=false:./swift/
# 生成文件查看
$: tree swift
swift
├── hello.grpc.swift
└── hello.pb.swift
XCode中添加生成代碼需要通過拖拽的方式,對于后端開發而言,確實有點不可理喻。不過既然必須這樣就按照規則:
現在在 iOS 的視圖加載函數增加 gRPC 調用過程:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let client = Helloworld_GreeterServiceClient(address: ":50051", secure: false)
var req = Helloworld_HelloRequest()
req.name = "JayL"
do {
let resp = try client.sayHello(req)
print("resp: \(resp.message)")
} catch {
print("error: \(error.localizedDescription)")
}
}
}
查看日志輸出resp: hello iOS from go
, iOS 應用調用 gRPC 服務成功。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。