奇淫巧技-Flutter调用C#

523 阅读3分钟

前言

大约,Xamarin应该是.net下的跨平台开发工具。2016年之前还处于收费状态,后被微软收购后开源。但似乎有个现象,开源后的Xamarin发展似乎有些停滞,而且维护Xamarin的团队又很固执不愿变通。社区多次建议UI层应该统一绘图引擎,而不是映射原生控件。

以至于谷歌的Flutter火爆之后,Xamarin社区很多人便转移阵地,你在百度搜索Xamarin,第一个关键字就是xamarin还有人用么。

那么对于C#/。net开发者来说,唯一的问题就是界面,就有了开源项目Xamarin.Flutter,但过完年没多久,项目就已经存档了,经过改进说只靠他和几个开发人员的临时时间很难搞定。但技术上确实可行,因为Skia在.net下本来就有绑定SkiaSharp,而Flutter可以便用的Skia引擎。UIWidgets在Unity3D下的Flutter实现。那对于我们.net开发者有没有一种可能就是界面使用Flutter,业务逻辑采用C#呢,答案是可行的,请看如下分解。

环境

为了能够使用Flutter调用C#,需要如下工具和环境

颤振环境

vs2015或者vs2017,并且包含Xamarin安装。

Android Studio,Android SDK,NDKr15c

杰克1.8

Embeddinator-4000

前面四项没有多余的描述,请参考官方文档,确保Flutter,Xamarin可以运行项目,Android ndk请使用r15c版本,目前好像仅支持r15c,其他未测试。

Embeddinator-4000是将C#转化为各平台本机代码的工具,可以使用Nuget安装

安装软件包Embeddinator-4000-版本0.4.0

将工具路径添加到系统环境PATH,建议添加nuget的堆栈缓存,类似

C:\ Users \ Administrator \ .nuget \ packages \ embeddinator-4000 \ 0.4.0 \ tools

如果工具使用出错,请检查sdk,或ndk版本,并确认Xamarin设置sdk,ndk路径正确。

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Novell]

[HKEY_CURRENT_USER\Software\Novell\Mono for Android]
"AndroidNdkDirectory"="C:\\Program Files (x86)\\Android\\android-sdk\\ndk-bundle"
"AndroidSdkDirectory"="C:\\Program Files (x86)\\Android\\android-sdk"
"JavaSdkDirectory"="C:\\Program Files\\Android\\jdk\\microsoft_dist_openjdk_1.8.0.25\\"`

因为当前visualstudio的校准信息都是独立文件形式,这可能是工具本身的BUG。

使用方法

1.创建C#类库(这里只实现Android下的方法,iOS类推)

这里我们先创建一个类库,我们使用Android Class Lib,如果不是Android的方法,也可以创建普通的类库

编译后得到Test4Flutter.dll,运行如下命令

Embeddinator-4000.exe --gen = java -out = test。\ Test4Flutter.dll -p = Android -c

出现MSBUILD:错误MSB1008:只能指定一个项目。请确保路径下没有空格,或者复制dll到其他路径重试

在test目录下我们得到一个Test4Flutter.aar文件

2.创建一个Flutter插件

Android里添加模块,具体参考文档,将模块添加进依赖。

public void onMethodCall(MethodCall call, Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    }
    else if (call.method.equals("getHelloString")){
      result.success(test.getHelloString());
    }
    else if(call.method.equals("add")){
      result.success(test.add((int)call.argument("x"),(int)call.argument("y")));
    }
    else {
      result.notImplemented();
    }
  }

  static Future<String> getHelloString() async {
    return await _channel.invokeMethod('getHelloString');
  }

  static Future<int> add(int x,int y) async{
    final int ret = await _channel.invokeMethod('add',<String, dynamic>{
      'x': x,
      'y': y,
    });
    return ret;
  }

示例内调用测试

调用方法时控制台会打印如下

I/mono-stdout( 5946): call net function ->GetHelloString
I/mono-stdout( 5946): call net function ->Add
I/mono-stdout( 5946): call net function ->Add