前言
众所周知,Xamarin应该是.net下的跨平台开发工具。2016年之前还处于收费状态,后被微软收购后开源。但似乎有个现象,开源后的Xamarin发展似乎有些停滞,而且维护Xamarin的团队又很固执不愿变通。社区多次建议UI层应该统一绘图引擎,而不是映射原生控件。Xamarin.Forms给人的感觉就是性能差,动画僵硬,效果不好实现。以至于谷歌的Flutter火爆之后,Xamarin社区很多人便转移阵地,你在百度搜索Xamarin,第一个关键词就是xamarin还有人用么。那么对于C#/.net开发者来说,唯一的问题就是界面,就有了开源项目Xamarin.Flutter,但过完年没多久,项目就Archived了,adamped说仅靠他和几个开发人员的业余时间很难搞定。但技术上确实可行,因为Skia在.net下本来就有绑定SkiaSharp,而Flutter底层便使用的Skia引擎。UIWidgets就是在Unity3D下的Flutter实现。那对于我们.net开发者有没有一种可能就是界面使用Flutter,业务逻辑采用C#呢,答案是可行的,请看如下分解。
环境
为了能够使用Flutter调用C#,需要如下工具和环境
Flutter环境
vs2015或者vs2017,并且包含Xamarin安装。
Android Studio, Android SDK,NDKr15c(https://dl.google.com/android/repository/android-ndk-r15c-windows-x86_64.zip)
jdk 1.8
Embeddinator-4000
前面四项不在赘述,请参考官方文档,确保Flutter,Xamarin可以运行项目,Android ndk请使用r15c版本,目前好像仅支持r15c,其他未测试。
Embeddinator-4000是将C#转化为各平台本机代码的工具,可以使用Nuget安装
Install-Package Embeddinator-4000 -Version 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,参加https://github.com/mono/Embeddinator-4000/issues/707
使用方法
1. 创建C#类库(这里只实现Android 下的方法,iOS类推)
这里我们先创建一个类库,我们使用Android Class Lib,如果不是Android 的方法,也可以创建普通的类库
编译后得到Test4Flutter.dll, 运行如下命令
Embeddinator-4000.exe --gen=java -out=test .\Test4Flutter.dll -p=Android -c
出现MSBUILD : error MSB1008: 只能指定一个项目。请确保路径下没有空格,或者复制dll到其他路径重试
在test目录下我们得到一个Test4Flutter.aar文件
2.创建一个Flutter插件
Android 里添加Module,具体参考文档,将Module添加进依赖。
![dump_2046261408567477536](C:\Users\Administrator\Desktop\dump_2046261408567477536.png) 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;}
example内调用测试
调用方法时控制台会打印如下
结
很多时候我们应该摒弃语言之争,语言并无好坏,甚至可以将其融合