问题java
在手机应用的开发中,一般会将复杂的业务逻辑层实现放在服务端,客户端仅负责表现层。可是对于某些手机应用而言,业务逻辑的实现位于服务端反而是不安全的或是不合理的,而是须要将其逻辑直接在手机端实现。android
目的ios
面对不一样系统的手机客户端,单独重复实现相同的业务逻辑,并不是最佳实践。如何经过第三方语言 Go 语言将业务逻辑封装成库的形式,并以静态打包的方式提供给不一样系统的手机客户端使用,是本次调研的目的。git
理想目标图:github
具体调研内容包括:golang
其中关于 gRPC 在 iOS 与 Android 的实现,自己官方就已经提供了样例。本次调研会用到相关内容,因此将其做为调研的一部分记录下来,方便后来者阅读。调研中全部涉及的项目代码均存放于: grpc-apps 仓库中, 须要的朋友能够直接下载测试。sql
首先保证开发环境处于"全球通"状态,保证顺利安装相关依赖包与工具。数据库
注意: GoMobile 不支持最新的 Go Module 包依赖功能,因此建议在开始本教程以前, 执行
export GO111MODULE=off
关闭 Go Module 功能。编程
经过如下命令直接源码安装swift
$: 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。
XCode 安装是必备的,请参考:iOS 应用实现 gRPC 调用。
若是使用gomobile
生成 iOS SDK,还须要安装Command Line Tools for XCode
工具, 直接经过开发者帐号登陆苹果官网上下载.
安装完成后执行:
$: xcode-select -s /Applications/Xcode.app/
复制代码
Android Studio 安装是必备的,请参考:Android 应用实现 gRPC 调用。
若是使用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 勾选安装:
过程有点慢,耐心等待。完成安装后,设置环境变量便可。
export ANDROID_HOME=~/Library/Android/sdk/
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle
复制代码
在官方的GoMobile/Wiki上,安装包内就已经提供了最简单的样例代码了,能够直接使用。由于是现成的代码,缺乏过程,因此这里仍是从头开始建立,记录过程。
首先建立一个新的本地 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了。
生成 iOS SDK 过程很简单:
$: gomobile bind -target=ios github.com/liujianping/golib
$: ls
Golib.framework golib.go
复制代码
完成命令后,在当前目录下就生成了Golib.framework
的目录,固然也能够经过指定-o
设置输出路径。
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.
打开iOS 应用实现 gRPC 调用中建立的项目,将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的集成。
在 Android 上集成没有 iOS 上拖拽那么简单, 能够按如下步骤经过新建一个新Module的方式将 Golib SDK 导入到项目中。
打开Android 应用实现 gRPC 调用中建立的项目,执行 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的集成。
完成了 GoMobile SDK 的集成工做, 如今看看它能作什么。
在 GoMobile SDK 上的日志输出是否能够正常的在 iOS 与 Android 平台正常输出,不妨在 Golib 的实现上增长 log.Println
输出。
经过验证,GoMobile SDK 上的日志输出在 iOS 与 Android 上能够正常输出。有了日志输出就能够很是方便的调试 GoMobile SDK 的具体功能了。
不一样的手机系统平台,第三方应用的文件目录存储路径不同的。因此,具体路径仍是让上层调用代码做为参数传入比较合理。
在 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,再集成测试。
大部分手机应用的本地数据存储都会使用sqlite
做为数据库存储。因此就sqlite
再GoMobile SDK 中的实现进行调研。
$: get get github.com/mattn/go-sqlite3
复制代码
能够直接取github.com/mattn/go-sqlite3
仓库中的样例代码进行实验。具体代码请参考:golib/sqlite.go。
编译从新集成测试可知,在 GoMobile SDK在 iOS/Android实现 sqlite 的功能可行。
网络操做是最不须要验证的功能了,SDK 中彻底能够将手机应用的网络操做所有封装到其中。
本文仅仅是对 GoMobile SDK 在集成与边界的简单验证,提供一套解决手机应用混合编程的新思路。虽然可以完成本次调研的预期目的,可是若是须要用于生产环境中,请进行更多的功能验证。