美文网首页
Flutter与Go交互

Flutter与Go交互

作者: h2coder | 来源:发表于2023-07-27 23:23 被阅读0次

    效果演示

    Flutter与Go交互.jpg

    使用 go mobile 打包Android依赖库

    创建go工程目录

    • 目录名:go-calc

    初始化go模块

    • 开启 go modules功能
    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.aarcalc-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)
                ],
              ),
            ),
          ),
        );
      }
    }
    

    相关文章

      网友评论

          本文标题:Flutter与Go交互

          本文链接:https://www.haomeiwen.com/subject/uierpdtx.html