当前位置: 首页 > 科技观察

技术干货-Electron插件开发实践

时间:2023-03-23 01:48:40 科技观察

01前言早期的跨平台桌面应用开发大多使用Qt和C++。受语言学习成本和开发效率的影响,越来越多的人将目光投向了Electron。Electron是一个基于Nodejs和Chromium的跨平台开发框架。Electron基于Web技术开发桌面应用程序。Web技术广泛应用于软件开发领域,生态相对成熟,学习成本低,开发效率高。然而,Web在处理多线程和并发场景时似乎捉襟见肘。Electron底层有Nodejs支持,Nodejs的插件模块有调用C++的能力。C++非常适合处理高并发、音视频等复杂业务,弥补了Web的性能问题。本文介绍js和C++混合编程在Electron桌面程序中的应用。在Nodejs中使用C++有几种方式:将C++程序作为一个独立的子进程使用。由node-ffi调用。Nodejs扩展,它将C++代码编译成Nodejs模块。本文主要介绍这种方法。02C++扩展C++扩展介绍Nodejs本身是用C++编写的,所以我们可以使用自己的C++编写的Nodejs模块,可以像Nodejs原生模块一样使用。C++的扩展格式是.node,其实质是一个动态链接库,相当于Windows下的.dll。C++扩展通过dlopen作为动态链接库加载到Nodejs中。C++扩展架构图:C++扩展的几种实现方式C++扩展的实现方式有3种:nativemode、nan、Node-API。Native模式直接使用NodejsAPI和ChromeV8API进行开发,早已废弃。特点:一旦NodejsAPI和ChromeV8API接口发生变化,依赖这些API的C++扩展将无法使用,特定版本的C++扩展只能在相应版本的Nodejs环境中使用。nan(NativeAbstractionsforNodejs)nan是一组Nodejs抽象接口。nan根据当前的Nodejs版本,使用宏来判断执行对应版本的API。特点:C++扩展运行在不同版本的Nodejs中,需要重新编译。Nodejs升级到高版本后出现接口不兼容问题。Node-APINode-API使用Nodejs二进制接口,比nan方法更稳定。特点:只要不同版本Nodejs的abi版本号一致,C++扩展就可以直接使用,无需重新编译,消除Nodejs版本差异。构建工具node-gypnode-gyp封装了gyp(Chromium编写的构建工具),binding.gyp是其配置文件。node-gyp的工作分为两个过程:结合binding.gyp生成对应平台下的工程配置,例如:在Windwos下生成.sln工程文件。b.编译项目文件并生成C++扩展。binding.gyp配置文件,以Windows为例:{"targets":[{"target_name":"addon_name","type":"static_library"'defines':['DEFINE_FOO','DEFINE_A_VALUE=value',],'include_dirs':['./src/include','#include"engine.h"Napi::ObjectInitAll(Napi::Envenv,Napi::对象导出){returnnertc::Engine::Init(env,exports);}NODE_API_MODULE(addon,InitAll)//engine.h#pragmaonce#include命名空间nertc{classEngine:publicNapi::ObjectWrap{public:staticNapi::ObjectInit(Napi::Envenv,Napi::Objectexports);引擎(constNapi::CallbackInfo&信息);private:Napi::Valueadd(constNapi::CallbackInfo&info);};}//engine.cpp#include"engine.h"namespacenertc{Napi::ObjectEngine::Init(Napi::Envenv,Napi::Objectexports){Napi::Functionfunc=DefineClass(env,"Engine",{InstanceMethod("add",&Engine::add)});Napi::FunctionReference*constructor=newNapi::FunctionReference();*构造函数=Napi::Persistent(func);env.SetInstanceData(构造函数);exports.Set("引擎",func);返回出口;}Engine::Engine(constNapi::CallbackInfo&info):Napi::ObjectWrap(info){}Napi::ValueEngine::add(constNapi::CallbackInfo&info){Napi::Envenv=info.Env();//获取环境变量intret=0;intlength=info.Length();//获取参数个数if(length!=2||!info[0].IsNumber()||!info[1].IsNumber()){Napi::TypeError::New(env,"预期数量").ThrowAsJavaScriptException();ret=-1;返回Napi::Number::New(env,ret);}intnum1=info[0].As().Int32Value();//获取第一个参数intnum2=info[1].As().Int32Value();////获取第二个参数intsum=num1+num2;returnNapi::Number::New(env,sum);//返回结果给js层}}jscallsC++extensionvaraddon=require('bindings')('addon');//调用C++extensionvar引擎=新插件。engine();console.log(`num1+num2=${engine.add(1,2)}`);//输出3在package.json目录下,执行npminstall,npmruntest,可以看到js调用C++接口成功,并输出两个数相加的结果),结合Electron,可以快速实现音视频通话。githubdemo体验地址:https://github.com/netease-im/Basic-Video-Call/tree/master/Group-Video/NERtcSample-GroupVideoCall-Electron04常见问题错误:找不到指定的模块。答:这个错误是指可以找到C++扩展模块(.node)但加载失败,因为.node会依赖其他.dll和C++运行时库。当缺少这些库时,就会报上面的错误。使用depends检查缺少哪个库。只需配置它。运行一个使用了C++扩展的Electron应用,提示Thespecifieldmodulecouldnotbefound。答:这个错误的意思是找不到C++扩展模块。在项目package.json文件中配置extraFiles字段,并将扩展复制到Electron可加载目录中。Electron加载C++扩展时提示:Moduleparsefailed:Unexpectedcharacter'?'。答:webpack只能识别js和json文件,不能识别C++扩展模式。Electron打包时需要在vue.config.js中配置C++扩展的loader。更多FAQ汇总:https://doc.yunxin.163.com/docs/jcyOTA0ODM/jU4NTEwNzg?platformId=50456#9