关于 gRPC 在 iOS 与 Android 的实现,本身官方就已经提供了样例。本次调研会用到相关内容,所以将其作为调研的一部分记录下来,方便后来者阅读。调研中所有涉及的项目代码均存放于: liujianping/grpc-apps 仓库中, 需要的朋友可以直接下载测试。
1. 环境安装
1.1 GoMobile 工具安装
首先保证开发环境处于"全球通"状态,保证顺利安装相关依赖包与工具。
注意: GoMobile 不支持最新的 Go Module 包依赖功能,所以建议在开始本教程之前, 执行
export GO111MODULE=off
关闭 Go Module 功能。
通过以下命令直接源码安装
$: go get golang.org/x/mobile/cmd/gomobile
$: gomobile -h
Usage:
gomobile command [arguments]
Commands:
bind build a library for Android and iOS
build compile android APK and iOS app
clean remove object files and cached gomobile files
init build OpenAL for Android
install compile android APK and install on device
version print version
从命令输出能够看出,gomobile 能够通过子命令build
直接构建不同系统的客户端应用,还可以通过子命令bind
构建支持不同系统的开发库。基于本次调研的目的,主要使用bind
子命令生成相应平台的SDK。
1.2 iOS 工具安装
XCode 安装是必备的,请参考:iOS 环境准备。
如果使用gomobile
生成 iOS SDK,还需要安装Command Line Tools for XCode
工具, 直接通过开发者账号登录苹果官网上下载.
安装完成后执行:
$: xcode-select -s /Applications/Xcode.app/
1.3 Android 工具安装
Android Studio 安装是必备的,请参考:Android 环境准备。
如果使用gomobile
生成 Android SDK,还需要安装 Android NDK 环境。未安装时会报以下错误:
$: gomobile bind -target=android github.com/liujianping/golib
gomobile: no Android NDK found in $ANDROID_HOME/ndk-bundle nor in $ANDROID_NDK_HOME
打开 Android Studio,进入Tools > Android > SDK Manager 勾选安装:
- LLDB
- CMAKE
- NDK
过程有点慢,耐心等待。完成安装后,设置环境变量即可。
export ANDROID_HOME=~/Library/Android/sdk/
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle
2. Go SDK 样例实现
在官方的GoMobile/Wiki上,安装包内就已经提供了最简单的样例代码了,可以直接使用。因为是现成的代码,缺少过程,所以这里还是从头开始创建,记录过程。
2.1 Golib 实现
首先创建一个新的本地 Go 项目:Golib
, 具体代码放在Golib中。
$: mkdir -p $GOPATH/src/github.com/liujianping/golib
$: cd $GOPATH/src/github.com/liujianping/golib
$: cat <<EOF > golib.go
package golib
import (
"errors"
"fmt"
)
func Greetings(name string) string {
return fmt.Sprintf("Hello, %s!", name)
}
func NumberError(num int) (int, error) {
if num >= 10 {
return 0, errors.New("num > 10")
}
return num, nil
}
EOF
这个样例程序比官方的多了一个函数NumberError
实现。因为真实项目一定会存在异常处理,所以增加这个函数顺便调研一下。
如果前一节的环境全部都安装成功的话,现在我们就可以生成相应平台的SDK了。
2.2 生成 iOS SDK
生成 iOS SDK 过程很简单:
$: gomobile bind -target=ios github.com/liujianping/golib
$: ls
Golib.framework golib.go
完成命令后,在当前目录下就生成了Golib.framework
的目录,当然也可以通过指定-o
设置输出路径。
2.3 生成 Andorid SDK
Android SDK 的生成过程,同样很简单:
$: gomobile bind -target=android github.com/liujianping/golib
$: ls
golib-sources.jar golib.aar Golib.framework golib.go
不同的是,android 平台生成的是 jar
与 arr
两个包。具体 jar
与 arr
包的区别,贴下 google 的结果:
The main difference between a Jar and a AAR is that AARs include resources such as layouts, drawables etc. This makes it a lot easier to create self-contained visual components.
3. GoMobile SDK 的集成
3.1 在 iOS 上集成
打开iOS 环境准备中创建的项目,将Golib.framework
拖拽到项目中。
打开ViewController.swift
文件:
import UIKit
import Golib
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// gRPC client
...
// golib
let reply = GolibGreetings("JayL")
print("golib reply: \(reply)")
// golib error
var err1: NSError?
var num: Int = 0
GolibNumberError(11, &num, &err1)
print("golib num: \(num), err: \(err1)")
}
}
重新编译并执行测试项目,在控制台输出得出预期结果。完成 iOS 上集成 GoMobile SDK的集成。
3.2 在 Android 上集成
在 Android 上集成没有 iOS 上拖拽那么简单, 可以按以下步骤通过新建一个新Module的方式将 Golib SDK 导入到项目中。
打开Android 环境准备中创建的项目,执行 File -> New -> NewModule
菜单创建一个新的 Module golib。再打开 Module: app
的Gradle
文件,引入 Module: golib
, 即增加项目依赖: implementation project(":golib")
。如下图:
完成上面步骤,就可以在代码中引用该 SDK 了。 打开主实现 java 文件:
String goLib_hello = Golib.greetings("GoLib Hello");
Log.i("golib", goLib_hello);
try {
long l = Golib.numberError(11);
Log.i("golib", Long.toString(l));
}
catch (Exception e) {
Log.e("golib", e.getMessage());
}
设置不同的Golib.numberError(11)
输入参数,查看控制台的输出情况。完成 Android 上集成 GoMobile SDK的集成。
4. GoMobile SDK 功能边界
完成了 GoMobile SDK 的集成工作, 现在看看它能做什么。
4.1 日志打印
在 GoMobile SDK 上的日志输出是否可以正常的在 iOS 与 Android 平台正常输出,不妨在 Golib 的实现上增加 log.Println
输出。
通过验证,GoMobile SDK 上的日志输出在 iOS 与 Android 上可以正常输出。有了日志输出就可以非常方便的调试 GoMobile SDK 的具体功能了。
4.2 文件系统
不同的手机系统平台,第三方应用的文件目录存储路径不一样的。所以,具体路径还是让上层调用代码作为参数传入比较合理。
在 golib 实现库中增加目录枚举函数,并增加日志:
package golib
import (
"fmt"
"log"
"os"
"path/filepath"
)
func WalkDirectory(path string) error {
return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
log.Println("walk fn failed: ", err)
return err
}
log.Printf("walked file or dir: %q\n", path)
return nil
})
}
重新编译生成对应平台的SDK,再集成测试。
4.3 数据存储
大部分手机应用的本地数据存储都会使用sqlite
数据库来实现。所以就sqlite
再GoMobile SDK 中的实现进行调研。
$: get get github.com/mattn/go-sqlite3
可以直接取github.com/mattn/go-sqlite3
封装其中的样例代码进行实验。具体代码请参考:golib/sqlite.go。
编译重新集成测试可知,在 GoMobile SDK在 iOS/Android实现 sqlite 的功能可行。
4.4 网络操作
网络操作是最不需要验证的功能了,SDK 中完全可以将手机应用的网络操作全部封装到其中。
小结
本文仅仅是对 GoMobile SDK 在集成与边界的初步验证,提供一套解决手机应用混合编程的新思路。虽然能够完成本次调研的预期目的,但是如果需要用于生产环境中,请进行更多的功能验证。