使用 Go Mobile 开发跨平台 Library

前情提要:

使用 Kotlin Native 开发跨平台 Library

为什么使用 Go Mobile

相对于 Kotlin Native 而言,Go 有更完善的生态支持,更小的二进制体积。

虽然 Go Mobile 维护者有跑路的嫌疑,但通过第三方的 Fork 我们已经可以支持 Apple Silicon 和 Catalyst.

下面还是用和使用 Kotlin Native 开发跨平台 Library里一样的 NASA API 来做一个 SDK,看看使用体验如何。

创建 Go Module

你可以到 gomobile-lib-demo 下载已经完成的项目

首先定义 GOPATH,我选了用户 zhoukaiwen 目录的 golang 文件夹。

export GOPATH=/Users/zhoukaiwen/golang

找个 GOPATH 之外的地方,创建 module 文件夹

mkdir go_lib_demo
cd go_lib_demo
go mod init Hello

编辑 go.mod 增加一个好用点的 HTTP 库 resty 依赖,以及解决了 Catalyst 和 Apple Silicon 的第三方 gomobile github.com/ydnar/gomobile

module Hello

go 1.16

require (
github.com/go-resty/resty/v2 v2.6.0
golang.org/x/mobile v0.0.0-20210614202936-7c8f154d1008 // indirect
)

replace golang.org/x/mobile v0.0.0-20210614202936-7c8f154d1008 => github.com/ydnar/gomobile v0.0.0-20210301201239-fb6ffafc9ef9

获取依赖

go get github.com/go-resty/resty/v2
go get golang.org/x/mobile/cmd/gomobile
go get golang.org/x/mobile/bind

初始化 gomobile

gomobile init

创建 API

使用 NASA 的 API 获得 Astronomy Picture of the Day 的 JSON 数据.

https://api.nasa.gov/planetary/apod?api_key={API_KEY}

src/hello/Nasa.go

package hello
import (
"encoding/json"
"fmt"
"github.com/go-resty/resty/v2"
)
type APOD struct {
Date string `json:"date"`
Explanation string `json:"explanation"`
HDurl string `json:"hdurl"`
MediaType string `json:"media_type"`
ServiceVersion string `json:"service_version"`
Title string `json:"title"`
Url string `json:"url"`
}
type NasaPath string
const (
nasaBaseURL NasaPath = "https://api.nasa.gov"
)
var (
apodPath NasaPath = "/planetary/apod"
)
func (m NasaPath) fullPath() string {
return fmt.Sprint(nasaBaseURL + m)
}
type NasaClient struct {
ApiKey string
}
func (nasaClient *NasaClient) GetAPOD() (*APOD, error) {
url := apodPath.fullPath()
client := resty.New()
resp, err := client.R().
SetQueryParams(map[string]string{
"api_key": nasaClient.ApiKey,
}).
Get(url)
if err != nil {
return nil, err
}
var apod APOD
if err := json.Unmarshal([]byte(resp.Body()), &apod); err != nil {
return nil, err
}
return &apod, nil
}

编译出 xcframework

gomobile bind -target ios ./src/hello 

创建 Swift Package

方法和使用 Kotlin Native 开发跨平台 Library一样,你可以到 go_lib_swift_package_demo 查看已经完工的项目。

import PackageDescription
let package = Package(
name: "go_lib_swift_package_demo",
products: [
.library(
name: "go_lib_swift_package_demo",
targets: ["go_lib_swift_package_demo", "HappyNasa"]),
],
targets: [
.target(
name: "go_lib_swift_package_demo",
dependencies: []),
.binaryTarget(
name: "HappyNasa",
path: "Sources/hello.xcframework"),
.testTarget(
name: "go_lib_swift_package_demoTests",
dependencies: ["go_lib_swift_package_demo"]),
]
)

在 iOS 中使用

你可以到 go_lib_ios_demo 查看已经完工的项目。

import UIKit
import Hello
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let client = HelloNasaClient()
client.apiKey = "{API_KEY}"
do {
let apod = try client.getAPOD()
print(apod.title)
print(apod.explanation)
} catch let error {
print(error.localizedDescription)
}
}
}

后记

相对于 Kotlin Native,Go 编译出的 SDK 要小很多,但比较遗憾的是 go func 在 Go Mobile 中并不能使用。如果你在函数里使用了 go func, 在编译后这个函数会被自动删除。