终于封装完成了,采用离屏渲染方式,支持JS和C#互相调用,C#方法自动绑定到JS里,中文输入有自动调整输入法位置。
基于开源的CefGlue 移植,本来想用CefSharp,不过这个里面有很多C++的,而且很多代码还是基于Windows编写的,不好移植成跨平台的。
不过CefGlue 里的功能不够完善,没有带JS远程调用功能,Cef是多进程的,JS调用需要在渲染进程,那就需要主进程发送消息给渲染进程来调用JS,还要把调用结果发送回主进程,很麻烦。我这边是采用管道通讯。
C#注册方法到JS里的时候,需要先反射获取方法名,根据方法名注册到JS里,注册之后的方法在被调用的时候,渲染进程会有回调,把回调里的参数和数据信息发送到主进程,再根据参数以及反射获取的C#方法的参数类型对比,并转换为相应的C#数据类型,再调用该C#方法,最后还要把C#调用的结果返回到渲染进程。现在只做了常用的数据类型转换,比如 string,int,double等这些,其他类型转换暂时不支持。
封装不同系统平台,有很多细节不同,有很多坑,比如:
1、MultiThreadedMessageLoop 在Mac里不支持,那你就需要另外搞个Timer,不断调用DoMessageLoopWork
2、由于Mac里的特殊的进程机制,你还需要在CommandLine调用SetProgram设置程序路径,否则无法启动子进程,关键子进程还自带任务栏图标,你还需要想办法把子进程任务栏图标隐藏,cef默认例子里就是靠多个程序目录,里面配置Info.plist为后台进程来隐藏子进程图标。
3、Linux里的话,还需单独设置CommandLine 禁用GPU,设置no-zygote
4、Mac里必须将键盘事件的Characters和UnmodifiedCharacter传给cef,否则还没法触发事件,另外还必须用系统的原生KeyCode设置给cef的键盘事件的NativeKeyCode,而Windows和Linux是设置WindowsKeyCode
5、Xamarin.Mac里有个坑,你无法继承NSApplication重写并增加方法属性,由于CPF.Mac采用的是精简版的Xamarin.Mac,而Xamarin.Mac采用的是绑定原生API的方式实现的,但是对NSApplication的子类没有实现自动注册功能,就是你继承扩展的子类无法在Object-C里获取到对应的对象。而cef在Mac端要求主程序的NSApplication增加IsHandlingSendEvent属性,没有这个属性就无法运行,好在Object-C支持类的动态增加属性,手动调用注册属性就好了
6、cef里封装的输入法搞的真麻烦,明明只要提供个获取光标位置的接口就行,却还搞个拼写过程输入效果,不调用这些接口还无法触发获取光标位置的回调,本来这个功能输入法提供就行的,cef里搞这个功能很坑,尤其是文本框限制字符数量的时候,比如文本框限制最大字符数是2,那你输入中文的时候,用拼音输入,就无法直接完整的拼写完两个中文字符,因为这个长度限制还会限制拼写过程的字母数量。好在可以规避掉这个拼写功能。
去 https://cef-builds.spotifycdn.com/ 下载cef二进制文件有个大坑,就是Linux的libcef.so文件都是1个G的,太大了,估计是配置文件写错了,就只能自己编译过。其他系统平台的都只有100多M。
最终封装成cpf的控件使用就很方便了,案例源码:http://cpf.cskin.net/Item/19