go打包aar及flutter调用aar流程详解

目录
  • 一、目的
  • 二、背景
  • 三、流程
    • 问题:
    • 问题一:go如何打包为移动端的包
      • 1.环境配置
      • 2.go配置与打包
    • 问题二:flutter如何调用aar
      • 第一步:存放aar与修改gradle配置
      • 第二步:修改MainActivity.java入口代码
      • 第三步:flutter调用
  • 四、结论

一、目的

本篇文章的目的是记录本人使用flutter加载与调用第三方aar包。

二、背景

本人go后端,业余时间喜欢玩玩flutter。一直有一个想法,go可以编译为第三方平台的可执行程序,而flutter可以是一个用于开发跨平台UI的工具,如果开发一个程序,go用于后台服务,flutter只用于描绘UI,是否可以做到。

查询了下github上的开源项目,有几个类似的:

上述三个,大致都是将flutter做为一个跨平台的UI工具来进行使用(思源不是flutter),然后使用第三方语言实现基本业务逻辑。

三、流程

问题:

  • go如何打包为移动端的包
  • flutter如何调用该包

问题一:go如何打包为移动端的包

1.环境配置

第一步需要解决的是环境配置,想打包安卓的包,肯定需要安卓的工具。

下载android studio

打开SDK Tools 工具库,安装NDK,请务必安装该版本:21.0.6113669

NDK解释:

Native Development Kit,是 Android的一个工具开发包

快速开发CC++的动态库,并自动将so和应用一起打包成 APK,即可通过NDKAndroid中 使用JNI与本地代码(如C、C++)交互

踩坑:默认安装是23最高版本,打包失败,请勾选show package details,会展开更加详细的NDK版本,务必下载21.0.6113669 版本!!!

2.go配置与打包

golang.org/x/mobile/cmd/gomobile

在项目中执行命令:

go build golang.org/x/mobile/cmd/gomobile
gomobile init

使用gomobile库可以将go程序打包为移动端的包

本项目程序截图:

在cmd/mobile中有一个kernel.go文件,该文件就是提供给移动端方法调用的入口StartKernel,里面是启动一个协程,该协程中会启动对应的http服务。

在我本地,我增加了一个构建安卓aar包的脚本

#!/usr/bin/env bash
# 构建移动端脚本
CRTDIR=$(pwd)
# 判断是否有output文件夹
if [ ! -d "${CRTDIR}/output" ]; then
  mkdir ${CRTDIR}/output
fi
# gomobile bind [-target android|ios|iossimulator|macos|maccatalyst] [-bootclasspath <path>] [-classpath <path>] [-o output] [build flags] [package]
# gomobile bind ./kernel/
gomobile bind -target=android -o=./output/mobile.aar -ldflags '-s -w'  ./cmd/mobile

执行该脚本,本地output会生成两文件:

  • mobile-sources.jar -- 具体实现的可以看该包,内部提供了一些静态本地方法
  • mobile.aar -- 我们真正需要的包

mobile-sources.jar内容:

// Code generated by gobind. DO NOT EDIT.
// Java class mobile.Mobile is a proxy for talking to a Go program.
//
//   autogenerated by gobind -lang=java github.com/clz.skywalker/event.shop/kernal/cmd/mobile
package mobile;
import go.Seq;
public abstract class Mobile {
	static {
		Seq.touch(); // for loading the native library
		_init();
	}
	private Mobile() {} // uninstantiable
	// touch is called from other bound packages to initialize this package
	public static void touch() {}
	private static native void _init();
	public static native void startKernel(long port, long local, String mode, String dbPath, String logPath);
}

好了,现在我们已经拿到了aar包了。

问题二:flutter如何调用aar

找半天文章,没有看到flutter直接调用aar包,如果你找到了请告诉我。

我现在的解决方案是参考官网的:用写插件的方式去实现,安卓加载aar,然后flutter再调用。

第一步:存放aar与修改gradle配置

在android文件夹下的app/libs 中放入mobile.aar文件,如果没有libs文件夹的话就创一个。

编辑app/build.gradle文件,增加如下代码:

dependencies {
    // implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    // implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
    // implementation files('libs/kernel.aar')
    implementation(name:'mobile',ext:'aar')
}

注释的是本人尝试后有问题的使用方式,本人非安卓开发人员,不是很清楚为什么不能那么使用,如果你知道的话可以告诉下我,没有注释的是本人亲试没问题的加载方式。

第二步:修改MainActivity.java入口代码

参考该文章,实现 configureFlutterEngine 方法,通过向 configureFlutterEngine 注册方法,可以实现调用native的方法。

MethodChannel的名字与flutter代码约定好,必须一模一样。

package github.com/ClzSkywalker;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import java.util.Objects;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
// 引入go打包的aar库
import mobile.Mobile;
public class MainActivity extends FlutterActivity {
    // 约定通道的名称,flutter可以通过通道名调用对应的方法
    private static final String CHANNEL = "kernel.startKernel";
    private static boolean kernelIsRunning = false;
    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
      GeneratedPluginRegistrant.registerWith(flutterEngine);
      new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
              .setMethodCallHandler(
                      (call, result) -> {
                          if (call.method.contentEquals("startKernel")) {
                            if (kernelIsRunning) {
                              result.success("");
                              return;
                            }
                            long port= Long.parseLong(Objects.requireNonNull(call.argument("port")).toString());
                              long local= Long.parseLong(Objects.requireNonNull(call.argument("local")).toString());
                              String mode= Objects.requireNonNull(call.argument("mode")).toString();
                              String dbPath= Objects.requireNonNull(call.argument("dbPath")).toString();
                              String logPath= Objects.requireNonNull(call.argument("logPath")).toString();
                              new Thread(() -> {
                                  // 调用aar中的方法
                                  Mobile.startKernel(port,local,mode,dbPath,logPath);
                              }).start();
                            kernelIsRunning=true;
                            result.success("");
                          }else{
                              result.notImplemented();
                          }
                      }
              );
  }
}

第三步:flutter调用

简短写一下,调用还是挺简单的,MethodChannel("name"),name的名字必须要与java中约定的通道名称一致。

    static const channel = MethodChannel('kernel.startKernel');
    kernelMap['port'] = 4935;
    kernelMap['local'] = 0;
    if (kDebugMode) {
      kernelMap['mode'] = 'test';
    } else {
      kernelMap['mode'] = 'release';
    }
    kernelMap['dbPath'] = dirPath;
    kernelMap['logPath'] = logPath.path;
    await channel.invokeMethod<void>('startKernel', kernelMap);

四、结论

总的来说难度没有那么大,在过去的时候尝试过类似操作,不过一直想的是flutter直接调用第三方平台库,错误的思路实现起来阻塞重重。

如果要调用第三方库,可以尝试做成一个flutter插件。

以上就是go打包aar及flutter调用aar流程详解的详细内容,更多关于go打包aar flutter调用aar的资料请关注我们其它相关文章!

(0)

相关推荐

  • go sync.Once实现高效单例模式详解

    目录 1. 简介 2. 基本实现 2.1 单例模式定义 2.2 sync.Once实现单例模式 2.3 其他方式实现单例模式 2.3.1 全局变量定义时赋值,实现单例模式 2.3.2 init 函数实现单例模式 2.3.3 使用互斥锁实现单例模式 2.4 使用sync.Once实现单例模式的优点 2.5 sync.Once和init方法适用场景 3. gin中单例模式的使用 3.1 背景 3.2 具体实现 3.3 sync.Once实现单例的好处 4.总结 1. 简介 本文介绍使用sync.On

  • Golang使用ChatGPT生成单元测试实践

    目录 前言 Part1 easy:单个函数,无复杂依赖 Part2 normal :里面有一些外部import Part3 hard:对外部repo进行mock(gomock举例) 一些痛点 其他用法 前言 目前gpt本质上是续写,所以在待测函数函数定义清晰的情况下,单元测试可以适当依赖它进行生成. 收益是什么: 辅助生成测试用例&测试代码,降低单元测试编写的心智成本 辅助code review,帮助发现代码显式/潜在问题 本文测试环境: gpt: gpt-3.5-turbo go:go 1.1

  • 深入浅出Golang中的sync.Pool

    目录 一.原理分析 1.1 结构依赖关系图 1.2 用图让代码说话 1.3 Put过程分析 二.学习收获 2.1 如何自己实现一个无锁队列 学习到的内容: 1.一个64位的int类型值,充分利用高32位和低32位,进行相关加减以及从一个64位中拆出高32位和低32位. 扩展:如何自己实现一个无锁队列. 如何判断队列是否满. 如何实现无锁化. 优化方面需要思考的东西. 2.内存相关操作以及优化 内存对齐 CPU Cache Line 直接操作内存. 一.原理分析 1.1 结构依赖关系图 下面是相关

  • Go interface接口声明实现及作用详解

    目录 什么是接口 接口的定义与作用 接口的声明和实现 接口的声明 接口的实现 接口类型断言 空接口 接口实际用途 通过接口实现面向对象多态特性 通过接口实现一个简单的 IoC (Inversion of Control) 什么是接口 接口是一种定义规范,规定了对象应该具有哪些方法,但并不指定这些方法的具体实现.在 Go 语言中,接口是由一组方法签名(方法名.参数类型.返回值类型)定义的.任何实现了这组方法的类型都可以被认为是实现了这个接口. 这种方式使得接口能够描述任意类型的行为,而不用关心其实

  • go并发利器sync.Once使用示例详解

    目录 1. 简介 2. 基本使用 2.1 基本定义 2.2 使用方式 2.3 使用例子 3. 原理 4. 使用注意事项 4.1 不能将sync.Once作为函数局部变量 4.2 不能在once.Do中再次调用once.Do 4.3 需要对传入的函数进行错误处理 4.3.1 基本说明 4.3.2 未错误处理导致的问题 4.3.3 处理方式 5. 总结 1. 简介 本文主要介绍 Go 语言中的 Once 并发原语,包括 Once 的基本使用方法.原理和注意事项,从而对 Once 的使用有基本的了解.

  • Go CSV包实现结构体和csv内容互转工具详解

    目录 引言 gocsv小档案 gocsv的基本功能 gocsv.UnmarshalFile函数:csv内容转成结构体 gocsv.MarshalFile函数:结构体转成csv文件 自定义类型转换器 自定义CSV的Reader/Writer gocsv包的特点总结 引言 大家在开发中一定遇到过将数据导出成csv格式文件的需求.go标准库中的csv包是只能写入字符串类型的切片.而在go中一般都是将内容写入到结构体中.所以,若使用标准的csv包,就需要将结构体先转换成对应的字符串类型,再写入文件.那可

  • go打包aar及flutter调用aar流程详解

    目录 一.目的 二.背景 三.流程 问题: 问题一:go如何打包为移动端的包 1.环境配置 2.go配置与打包 问题二:flutter如何调用aar 第一步:存放aar与修改gradle配置 第二步:修改MainActivity.java入口代码 第三步:flutter调用 四.结论 一.目的 本篇文章的目的是记录本人使用flutter加载与调用第三方aar包. 二.背景 本人go后端,业余时间喜欢玩玩flutter.一直有一个想法,go可以编译为第三方平台的可执行程序,而flutter可以是一

  • Flutter异步操作实现流程详解

    目录 一.FutureBuilder 二.StreamBuilder 在Flutter中,借助 FutureBuilder 组件和 StreamBuilder 组件,可以非常方便地完成异步操作. 一.FutureBuilder 在讲解FutureBuilder之前,你首先要知道Future是什么,了解了这个,后面再了解该组件就轻松许多. 在不同的编程语言中会有不同的名词来定义,在Dart语言中 选择使用Future类型配合async.await关键字来实现异步支持. Future 表示一个现在不

  • C++调用libcurl开源库实现邮件的发送功能流程详解

    目录 1.为啥要选择libcurl库去实现邮件的发送 2.调用libcurl库的API接口实现邮件发送 3.构造待发送的邮件内容 4.开通163发送邮件账号的SMTP服务 5.排查接收的邮件内容为空的问题 libcurl中封装了支持这些协议的网络通信模块,支持跨平台,支持Windows,Unix,Linux等多个操作系统.libcurl提供了一套统一样式的API接口,我们不用关注各种协议下网络通信的实现细节,只需要调用这些API就能轻松地实现基于这些协议的数据通信.本文将简单地讲述一下使用lib

  • Maven 命令行打包 和 pom.xml的常用配置详解

    maven 命令行打包 mvn -v, --show-version 现在最新的maven版本是 3.6,我这里用的还是 2017 年下载的 3.1.1 版本(虽然有点过时,但是大版本不变,指令基本一样) mvn -h, --help 使用 help 命令可以看到 maven 命令的帮助文档,下面主要介绍两个常用的指令 -- D 和 P. mvn -D, --define <arg> mvn -DpropertyName=propertyValue clean package 可以用来临时定义

  • Android view绘制流程详解

    绘制流程 measure 流程测量出 View 的宽高尺寸. layout 流程确定 View 的位置及最终尺寸. draw 流程将 View 绘制在屏幕上. Measure 测量流程 系统是通过 MeasureSpec 测量 View 的,在了解测量过程之前一定要了解这个 MeasureSpec . MeasureSpec MeasureSpec 是一个 32 位的 int 值打包而来的,打包为 MeasureSpec 主要是为了避免过多的对象内存分配. 为了方便操作,MeasureSpec

  • Android Flutter绘制扇形图详解

    目录 简介 CustomPaint介绍 CustomPainter介绍 paint介绍 shouldRepaint介绍 示例 使用CustomPaint 自定义Painter 绘制 触摸事件处理 动画实现 简介 在开发过程中通常会遇到一些不规则的UI,比如不规则的线条,多边形,统计图表等等,用那些通用组件通过组合的方式无法进行实现,这就需要我们自己进行绘制.可以通过使用CuntomPaint组件并结合画笔CustomPainter去进行手动绘制各种图形. CustomPaint介绍 Custom

  • 浅谈Python生成器generator之next和send的运行流程(详解)

    对于普通的生成器,第一个next调用,相当于启动生成器,会从生成器函数的第一行代码开始执行,直到第一次执行完yield语句(第4行)后,跳出生成器函数. 然后第二个next调用,进入生成器函数后,从yield语句的下一句语句(第5行)开始执行,然后重新运行到yield语句,执行后,跳出生成器函数,后面再次调用next,依次类推. 下面是一个列子: def consumer(): r = 'here' for i in xrange(3): yield r r = '200 OK'+ str(i)

  • java存储以及java对象创建的流程(详解)

    java存储: 1)寄存器:这是最快的存储区,位于处理器的内部.但是寄存器的数量有限,所以寄存器根据需求进行分配.我们不能直接进行操作. 2)堆栈:位于通用RAM中,可以通过堆栈指针从处理器那里获取直接支持.堆栈指针往下移动,则分配新的内存.网上移动,则释放内存.但是 在创建程序的时候必须知道存储在堆栈中的所有项的具体生命周期,以便上下的移动指针.一般存储基本类型和java对象引用. 3)堆:位于通用RAM中,存放所有的java对象,不需要知道具体的生命周期. 4)常量存储:常量值通常直接存放在

  • Android Bluetooth蓝牙技术使用流程详解

    在上篇文章给大家介绍了Android Bluetooth蓝牙技术初体验相关内容,感兴趣的朋友可以点击了解详情. 一:蓝牙设备之间的通信主要包括了四个步骤 设置蓝牙设备 寻找局域网内可能或者匹配的设备 连接设备 设备之间的数据传输 二:具体编程实现 1. 启动蓝牙功能 首先通过调用静态方法getDefaultAdapter()获取蓝牙适配器BluetoothAdapter,如果返回为空,则无法继续执行了.例如: BluetoothAdapter mBluetoothAdapter = Blueto

  • MVC+DAO设计模式下的设计流程详解

    DAO设计 : DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,DAO层的设计首先是设计DAO的接口,然后在Spring的配置文件中定义此接口的实现类,然后就可在模块中调用此接口来进行数据业务的处理,而不用关心此接口的具体实现类是哪个类,显得结构非常清晰,DAO层的数据源配置,以及有关数据库连接的参数都在Spring的配置文件中进行配置. 在该层主要完成对象-关系映射的建立,通过这个映射,再通过访问业务对象即可实现对数据库的访问,使得开发中不必再用SQL语句编写复杂的

随机推荐