使用Golang一处编写,横跨中Android & IOS 多端场景使用。golang提供gomobile跨平台开发库,我们可快速编译可直接Android & IOS 原生调用的SDK包,借助这一优势,可更加方便使用,白哪个比较Rust需要使用FFI转化调用更加方便。
本文主要介绍了Flutter 集成Golang,所以并不会在Flutter、Golang等开发环境搭建以及Dart、go语言上做介绍,本次使用VSCode作为编辑器。
考虑Android & IOS 同时演示效果,所以本文使用MacOS系统作为演示,如仅仅需做安卓上测试可跳过相关IOS的配置等操作。
本地环境
Flutter版本
Golang版本
Golang环境
从官网下载go安装包 https://golang.google.cn/dl/ 解压到本地,这里安装存放到 /usr/local/go 目录下
- GOPATH: go工作区, 即编写代码存放的目录
- GOROOT: go的安装目录
- 在
GOPATH
工作区目录下, 一般有3个目录, 分别是
- bin: 存储可执行bin文件
- pkg: 编译完成的文件
- src: 源代码文件
wget -c https://golang.google.cn/dl/go1.18.3.darwin-arm64.tar.gz
sudo tar -xzvf go1.18.3.darwin-arm64.tar.gz -C /usr/local
cd /usr/local/go
code ~/.bash_profile
# 增加如下几行 到 .bash_profile
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
export GO111MODULE=on
export GOPROXY=https://goproxy.cn
# 添加 ~/.bash_profile 后保存
code ~/.zshrc
source ~/.bash_profile
# 执行让环境变量生效
source ~/.zshrc
mkdir -p $GOPATH/src
mkdir -p $GOPATH/bin
mkdir -p $GOPATH/pkg
Golang 内容相关
创建项目
cd $GOPATH/src
mkdir demo
go mod init demo
编写案例
创建 greeting.go 文件,并编写如下内容,中后面调用时候传入内容并返回传入内容结果,以便演示数据互相传递
安装gomobile并初始化
gomobile init 初始化失败,请查看 完整流程 Flutter 集成 Rust 多语言跨端开发基础案例 中配置NDK相关内容配置好NDK之后,在执行 gomobile init
go get golang.org/x/mobile/cmd/gomobile
gomobile init
构建多平台SDK
Android
gomobile bind -target=android
IOS
gomobile bind -target=ios
构建后结果
构建后得到如图Android与IOS两个SDK文件
Flutter 内容相关
创建Flutter插件
这里直接使用Android Studio创建插件,也可以使用vscode或命令方式创建插件
导入Golang生成的SDK
将golang项目构建出的Android与IOS平台SDK导入 Flutter 插件项目各种目录中
导入 Android 所需SDK 至 android/libs 目录下,首次需要创建libs目录。导入完成后目录图如下
导入 IOS 所需SDK 到 ios/Frameworks 目录下,首次需要创建Frameworks目录。导入完成后目录如下图所示
这里要注意的是 构建出 IOS SDK 目录Greeting.xcframework中有两个
我们导入 ios-arm64_x86_64-simulator 目录下的 Greeting.framework
Android 调用SDK
打开android目录下build.gradle,添加引用SDK
project插件项目名称,file指定目录
打开 src/main/kotlin/com/example/demo/GomobileDemoPlugin.kt 文件,增加如下判断,调用golang sdk
IOS 调用SDK
修改 demo.podspec 添加引用SDK
打开 ios/Classes/SwiftGomobileDemoPlugin.swift 文件增加如下判断,调用golang sdk
由于这边Flutter 版本是3.0.2,生成插件分三个文件,旧版本是一个,为方便演示,不做目录结构修改,这里修改lib三个文件调用,由于难度较低,这里直接贴上修改后结果
gomobile_demo.dart
import 'gomobile_demo_platform_interface.dart';
class GomobileDemo {
Future<String?> getPlatformVersion() {
return GomobileDemoPlatform.instance.getPlatformVersion();
}
Future<String?> getSayHi(String text) {
return GomobileDemoPlatform.instance.getSayHi(text);
}
}
gomobile_demo_method_channel.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'gomobile_demo_platform_interface.dart';
/// An implementation of [GomobileDemoPlatform] that uses method channels.
class MethodChannelGomobileDemo extends GomobileDemoPlatform {
/// The method channel used to interact with the native platform.
@visibleForTesting
final methodChannel = const MethodChannel('gomobile_demo');
@override
Future<String?> getPlatformVersion() async {
final version =
await methodChannel.invokeMethod<String>('getPlatformVersion');
return version;
}
@override
Future<String?> getSayHi(String text) async {
final sayHi = await methodChannel.invokeMethod<String>(
'getSayHi',
{"text": text},
);
return sayHi;
}
}
gomobile_demo_platform_interface.dart
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'gomobile_demo_method_channel.dart';
abstract class GomobileDemoPlatform extends PlatformInterface {
/// Constructs a GomobileDemoPlatform.
GomobileDemoPlatform() : super(token: _token);
static final Object _token = Object();
static GomobileDemoPlatform _instance = MethodChannelGomobileDemo();
/// The default instance of [GomobileDemoPlatform] to use.
///
/// Defaults to [MethodChannelGomobileDemo].
static GomobileDemoPlatform get instance => _instance;
/// Platform-specific implementations should set this with their own
/// platform-specific class that extends [GomobileDemoPlatform] when
/// they register themselves.
static set instance(GomobileDemoPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
Future<String?> getPlatformVersion() {
throw UnimplementedError('platformVersion() has not been implemented.');
}
Future<String?> getSayHi(String text) {
throw UnimplementedError('platformVersion() has not been implemented.');
}
}D
修改插件example调用测试
打开example中main.dart 文件,将如下代码直接复制全部替换,这些都是基础内容,看不明白可以去flutter官网或者查阅相关基础教程
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:gomobile_demo/gomobile_demo.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
String _sayHi = 'Unknown';
final _gomobileDemoPlugin = GomobileDemo();
@override
void initState() {
super.initState();
initPlatformState();
initSayHiState();
}
Future<void> initPlatformState() async {
String platformVersion;
try {
platformVersion = await _gomobileDemoPlugin.getPlatformVersion() ??
'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
Future<void> initSayHiState() async {
String sayHi;
try {
sayHi = await _gomobileDemoPlugin.getSayHi('你好') ??
'Unknown platform version';
} on PlatformException {
sayHi = 'Failed to get platform version.';
}
if (!mounted) return;
setState(() {
_sayHi = sayHi;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
children: [
Text('Running on: $_platformVersion\n'),
Text('Hi: $_sayHi\n'),
],
),
),
),
);
}
}