使用 Gomobile 库就能够利用 Go 语言开发移动应用或者封装一个原生依赖库,Gomobile 代码仓库:https://github.com/golang/mobile

这篇博客中,我将记录一下这两天在使用过程中遇到的一些坑和总结一下使用经验。

我将利用 Gomobile 封装一个依赖库实现通过 swift 调用 Go 写的函数,以及 swift 实现 Go 定义的接口。

在开始之前你可能需要先了解 Go 基础语法,安装 Xcode 以及 IOS 开发环境,安装 Gomobile 工具。

大部分情况我们将偏向 Swift 利用调用 Go 语言实现相关功能,所以我会先讲一下在 Swift 中怎么调用 Go 构造函数创建 Go struct 实例,然后就是了解一下如何在 Go 中定义需要 Swift 实现的接口。

创建项目结构

我创建了一个简单的项目结构,包含一个 example 文件夹(待会我将会创建一个 IOS App 项目用于演示调用 Library,该文件夹还可以包含 Android 的演示项目),src 文件夹(该文件夹将包含 Go 语言项目代码),以及顶层的 go.mod 和 README.md 等文件。

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

接着我将创建 src/support.go 文件

/*
 * @Author: Bin
 * @Date: 2022-07-20
 * @FilePath: /goMobileDemoApp/src/support.go
 */
package support

import "fmt"

type Support struct {
}

func NewSupport() *Support {
	return &Support{}
}

func (s *Support) Echo() *Support {
	fmt.Println("Init Support Library")
	return s
}

以上代码中,声明了一个 Support 的结构,并且有一个 NewSupport 构造函数用于实例化 Support 结构体,Support 拥有一个 Echo 函数,调用 Echo 函数将会简单的输出一句 Init Support Library

创建 IOS 项目

利用 Xcode 创建一个 IOS Swift 项目到 example 文件夹中。

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

选择 IOS App 模版

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

输入你的项目名称,开发语言选择 Swift 就好了。

创建好 App 之后我们的项目文件结构大致如下:

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

为了方便管理依赖库,我们可以在 ios app 项目中创建一个 frameworks 文件夹,之后将依赖包就统一放到该文件夹下面

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

编译 xcframework IOS 依赖文件

项目准备好之后,回到项目根目录利用 gomobile 可以将 support.go 编译为 IOS 的 xcframework 依赖文件,打开终端执行编译命令

gomobile bind -target ios -o ./libs/GoMobileDemoApp.xcframework ./src/

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

编译成功后,就能看到项目下出现了一个 libs 文件夹,将文件夹下的 GoMobileDemoApp.xcframework 导入到 IOS 项目中

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

然后在 ViewController.swift 代码中导入 import GoMobileDemoApp

//
//  ViewController.swift
//  goMobileDemo01
//
//  Created by Bin on 2022/7/20.
//

import UIKit
import GoMobileDemoApp

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let su = SupportNewSupport()
        su!.echo()
    }

}

导入 GoMobileDemoApp 包之后,调用 SupportNewSupport() 构造函数,就能实例化一个 Support 结构体,即可调用结构体的 echo() 函数

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

编译运行 App 后就能看到输出成功了。

如果 import GoMobileDemoApp 显示找不到的报错,可以先检查一下 GoMobileDemoApp.xcframework 包是否导入成功。如果是能够编译通过,但是编辑器提示 No such module 'GoMobileDemoApp' 可以尝试添加 frameworks 目录到项目 Build Settings 配置选项 "Framework Search Path" 中即可解决编辑器提示包不存在问题。

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

Swift 实现 Go 的接口(传参以及回调)

接下来扩展一下 Support 结构体,我在 support.go 中增加了一个接口声明 SupportObserve 其中需要实现一个 OnCallback 函数,在 Support 结构体上新增两个函数 CallSetObserve,用于模拟传参后请求以及设置监听回调。

/*
 * @Author: Bin
 * @Date: 2022-07-20
 * @FilePath: /goMobileDemoApp/src/support.go
 */
package support

import "fmt"

type SupportObserve interface {
	OnCallback(code int, msg string)
}

type Support struct {
	observe SupportObserve
}

func NewSupport() *Support {
	return &Support{}
}

func (s *Support) Echo() *Support {
	fmt.Println("Init Support Library")
	return s
}

func (s *Support) Call(name string) *Support {
	// TODO: Implement function
	if name == "" {
		s.observe.OnCallback(404, "")
		return s
	}
	s.observe.OnCallback(200, "Hello "+name)
	return s
}

func (s *Support) SetObserve(o SupportObserve) *Support {
	s.observe = o
	return s
}

编译后将新的 xcframework 包替换 IOS App 项目 frameworks 文件夹中的旧依赖库文件,接下来我们使用 swift 实现定义的 SupportObserve ,首先在 IOS App 项目中创建一个 SwiftSupportObserve.swift 类。

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝
初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

创建成功后在 SwiftSupportObserve 中实现 SupportObserve 接口

//
//  SwiftSupportObserve.swift
//  goMobileDemo01
//
//  Created by Bin on 2022/7/20.
//

import UIKit
import GoMobileDemoApp

class SwiftSupportObserve: NSObject, SupportSupportObserveProtocol {
    
    func onCallback(_ code: Int, msg: String?) {
        NSLog("callback code is \(code) msg is \(msg)")
    }
    
}

和之前调用函数一样,首先需要导入 GoMobileDemoApp 包,然后使 SwiftSupportObserve 类实现 SupportSupportObserveProtocol 并需要实现 onCallback 方法,在方法中我只是简单的打印了 code 和 msg,如果有具体的回调业务逻辑将在这里实现。

SupportSupportObserveProtocol 是 Gomobile 的编译命名规范,这里采用 包名 + 接口名 + Protocol 生成具体接口命名。

接下来,在 ViewControllerviewDidLoad 生命周期中调用 SupportsetObserve 设置回调接口,并调用 call 触发回调试试。

//
//  ViewController.swift
//  goMobileDemo01
//
//  Created by Bin on 2022/7/20.
//

import UIKit
import GoMobileDemoApp

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let su = SupportNewSupport()
        su?.echo()
        
        let ob = SwiftSupportObserve()
        su?.setObserve(ob)
        
        su?.call("bin")
        
    }

}

最后编译运行 IOS App,我们就能在控制台看到输出没有问题。

初探 Gomobile ,利用 Go 开发 IOS Library 实现 Swift 调用 Go 函数-天真的小窝

到这里基本上能够实现利用 Golang 封装一个依赖库并且与 Swift 进行交互。

以上代码已经发布到 Github,如果帮助到你了可以点亮 Star 鼓励一下我: https://github.com/PBK-B/gomobile-library-tmp-examples

有问题可以回复到我博客 https://bin.zmide.com/?p=1047

参考链接:

Gomobile Code Warehouse: https://github.com/golang/mobile

Calling Go code from Swift on iOS and vice versa with Gomobile: https://medium.com/@matryer/tutorial-calling-go-code-from-swift-on-ios-and-vice-versa-with-gomobile-7925620c17a4

Gomobile Documentation: https://pkg.go.dev/golang.org/x/mobile/cmd/gomobile
import GoogleMobileAds No such module 'GoogleMobileAds ': https://stackoverflow.com/questions/39347291/import-googlemobileads-no-such-module-googlemobileads