效果演示
Flutter与Go交互.jpg
使用 go mobile 打包Android依赖库
创建go工程目录
初始化go模块
go env -w GO111MODULE=on
- 在项目根目录下,初始化go modules,执行完后,目录中会生成一个
go.mod
文件
go mod init 工程目录名
安装 go mobile
go get golang.org/x/mobile/cmd/gomobile
编译 go mobile
go build golang.org/x/mobile/cmd/gomobile
初始化 go mobile 环境
gomobile init
编写 go 代码
- 在工程目录下,创建一个
calc
目录,用于存放go代码
- 代码很简单,提供了一个
Calc
函数,传入2个int整形参数,相加后返回
- 注意:go的函数,首字母代码代表是公共方法,首字母小写则是私有方法,这里需要暴露方法出来给JNI调用,所以函数名的首字母必须是大写,否则后面的编译aar操作时,命令执行会报错,提示找不到函数!
package calc
/*
计算
*/
func Calc(x int, y int) int {
return x + y
}
编译 go 代码 为 安卓 aar 文件
- 编译时间可能需要2 ~ 3分钟,需要耐心等待
- 命令执行完后,会生成2个文件,分别是
calc.aar
和calc-sources.jar
,我们需要导入aar
文件
# 注意gomobile可执行文件在根目录,在根目录下执行bind命令,后面跟着go代码的目录
./gomobile bind ./calc/
# 或者直接去到go代码目录,执行命令
../gomobile bind
Flutter工程,依赖go生成的aar依赖库
添加依赖库
- 切换到Flutter的Android工程目录,找到
app
目录下的libs
目录,将aar放进去
- 在
app
目录下的build.gradle
,添加依赖配置
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
//引用libs下的aar文件
implementation(fileTree("libs"))
}
编写Android与Flutter通信代码
- Go生成的JNI类为
Calc.java
,我们的go计算函数会映射为java的calc
静态方法,所以调用比较简单,只需要val calcResult = Calc.calc(x, y)
即可
class MainActivity : FlutterActivity() {
companion object {
/**
* 原生和Flutter交互的通道名
*/
const val CHANNEL_NAME = "channel_flutter_go"
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_NAME)
.setMethodCallHandler { call, result ->
// 判断是计算方法,才执行对应逻辑
if (call.method.equals("calc")) {
val x = call.argument<Any>("x")?.toString()?.toLong() ?: 0
val y = call.argument<Any>("y")?.toString()?.toLong() ?: 0
// 调用Go,进行计算
val calcResult = Calc.calc(x, y)
result.success(calcResult)
} else {
// 找不到指定方法
result.notImplemented()
}
}
}
}
编写Flutter页面,并于Android通信
主程序
import 'package:flutter/material.dart';
import 'home_page.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
/// 主页面
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Go',
theme: ThemeData(
//主题色
primarySwatch: Colors.blue,
//colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
//是否使用Material3风格
useMaterial3: false,
),
home: const HomePage(title: 'Flutter Go'),
);
}
}
首页
- 通过MethodChannel,调用Android提供的方法,而在Android提供的方法中,调用Go的JNI函数
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_go/util/toast_util.dart';
/// 首页
class HomePage extends StatefulWidget {
const HomePage({super.key, required this.title});
/// 页面标题
final String title;
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
/// 原生和Flutter交互的通道名
static const channelName = "channel_flutter_go";
final TextEditingController _number1EditingController =
TextEditingController(text: "1");
final TextEditingController _number2EditingController =
TextEditingController(text: "2");
final TextEditingController _resultEditingController =
TextEditingController(text: "0");
/// 调用Go的方法
Future<int> _callGoMethod(int x, int y) async {
const channel = MethodChannel(channelName);
// 参数
var args = {};
args['x'] = x;
args['y'] = y;
return await channel.invokeMethod<int>('calc', args) ?? 0;
}
/// 处理计算
void _handleCalc() async {
var num1Str = _number1EditingController.text.trim();
var num2Str = _number2EditingController.text.trim();
if (num1Str.isEmpty) {
ToastUtil.toast("请输入第1个数字");
return;
}
if (num2Str.isEmpty) {
ToastUtil.toast("请输入第2个数字");
return;
}
// 调用Go的方法
var result = await _callGoMethod(int.parse(num1Str), int.parse(num2Str));
ToastUtil.toast("计算成功");
_resultEditingController.text = result.toString();
}
/// 构建数字文本输入框
Widget _buildTextField(TextEditingController controller) {
return Expanded(
child: TextField(
textAlign: TextAlign.center,
controller: controller,
// 最大行数
maxLines: 1,
//设置进入页面是否自动弹出键盘
autofocus: false,
// 设置键盘为数字
keyboardType: TextInputType.number,
inputFormatters: [
// 设置只允许输入数字
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
// 输入字符的长度限制
LengthLimitingTextInputFormatter(10)
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.primary,
title: Text(widget.title),
),
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildTextField(_number1EditingController),
Container(
margin: const EdgeInsets.all(10),
child: const Text("+"),
),
_buildTextField(_number2EditingController),
Container(
margin: const EdgeInsets.symmetric(horizontal: 10),
child: ElevatedButton(
child: const Text("="),
onPressed: () async {
_handleCalc();
},
),
),
_buildTextField(_resultEditingController)
],
),
),
),
);
}
}
网友评论