将预编译的二进制文件捆绑到电子应用中

有没有一个很好的解决scheme,如何将imagemagick等第三方预编译的二进制文件包含到电子应用程序中? 有node.js模块,但它们都是封装或本地绑定到系统安装的库。 我想知道是否有可能在发行版中捆绑预编译的二进制文件。

       

网上收集的解决方案 "将预编译的二进制文件捆绑到电子应用中"

我确实find了解决办法,但我不知道这是否被认为是最佳做法。 我无法find任何包含第三方预编译二进制文件的好文档,所以我只是一直弄弄它,直到最终与我的ffmpeg二进制文件一起工作。 这是我做的(从电子快速入门开始,node.js v6):

Mac OS X方法

从app目录中,我在terminal中运行以下命令,将ffmpeg二进制文件作为模块包含在内:

mkdir node_modules/ffmpeg cp /usr/local/bin/ffmpeg node_modules/ffmpeg/ cd node_modules/.bin ln -s ../ffmpeg/ffmpeg ffmpeg 

(用当前的二进制pathreplace/usr/local/bin/ffmpeg ,从这里下载)放置链接允许electron-packager包含我保存到node_modules/ffmpeg/的二进制文件。

然后获得捆绑的应用程序path(以便我可以使用绝对path为我的二进制…相对path似乎没有工作,无论我做了什么)我安装了npm包app-root-dir运行以下命令:

 npm i -S app-root-dir 

现在我有了根应用程序目录,我只是追加了我的二进制文件的子文件夹,并从那里产生。 这是我放在renderer.js中的代码:

 var appRootDir = require('app-root-dir').get(); var ffmpegpath=appRootDir+'/node_modules/ffmpeg/ffmpeg'; console.log(ffmpegpath); const spawn = require( 'child_process' ).spawn, ffmpeg = spawn( ffmpegpath, ['-i',clips_input[0]]); //add whatever switches you need here ffmpeg.stdout.on( 'data', data => { console.log( `stdout: ${data}` ); }); ffmpeg.stderr.on( 'data', data => { console.log( `stderr: ${data}` ); }); 

Windows方法

  1. 打开你的电子基础文件夹(电子快速启动是默认名称),然后进入node_modules文件夹。 在那里创build一个名为ffmpeg的文件夹,并将你的静态二进制文件复制到这个目录中。 注意:它必须是你的二进制文件的静态版本,因为ffmpeg我抓住了最新的Windows版本。
  2. 要获得捆绑的应用程序path(以便我可以使用绝对path为我的二进制文件…相对path似乎没有工作,不pipe我做了什么)我通过运行以下命令安装npm包app-root-dir从我的应用程序目录中的命令提示符:

      npm i -S app-root-dir 
  3. 在您的node_modules文件夹中,导航到.bin子文件夹。 您需要在这里创build几个文本文件来告诉节点包含刚刚复制的二进制exe文件。 使用你最喜欢的文本编辑器,并创build两个文件,一个名为ffmpeg与以下内容:

     #!/bin/sh basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") case `uname` in *CYGWIN*) basedir=`cygpath -w "$basedir"`;; esac if [ -x "$basedir/node" ]; then "$basedir/node" "$basedir/../ffmpeg/ffmpeg" "$@" ret=$? else node "$basedir/../ffmpeg/ffmpeg" "$@" ret=$? fi exit $ret 

    而第二个文本文件名为ffmpeg.cmd

     @IF EXIST "%~dp0\node.exe" ( "%~dp0\node.exe" "%~dp0\..\ffmpeg\ffmpeg" %* ) ELSE ( @SETLOCAL @SET PATHEXT=%PATHEXT:;.JS;=;% node "%~dp0\..\ffmpeg\ffmpeg" %* ) 

接下来,您可以在Windows电子分配(在renderer.js中)中运行ffmpeg,如下所示(我也使用了app-root-dir节点模块)。 请注意添加到二进制path的引号,如果您的应用程序安装到一个空格的目录(例如C:\Program Files\YourApp ),它将无法正常工作。

 var appRootDir = require('app-root-dir').get(); var ffmpegpath = appRootDir + '\\node_modules\\ffmpeg\\ffmpeg'; const spawn = require( 'child_process' ).spawn; var ffmpeg = spawn( 'cmd.exe', ['/c', '"'+ffmpegpath+ '"', '-i', clips_input[0]]); //add whatever switches you need here, test on command line first ffmpeg.stdout.on( 'data', data => { console.log( `stdout: ${data}` ); }); ffmpeg.stderr.on( 'data', data => { console.log( `stderr: ${data}` ); }); 

TL;博士:

是的你可以! 但它需要你编写你自己的独立的插件,它不会对系统库做任何假设。 此外,在某些情况下,您必须确保您的插件是为所需的操作系统编译的。


让我们分几个部分来解决这个问题:

– 插件 (原生模块)

插件是dynamic链接的共享对象。

换句话说,你可以编写你自己的插件,而不需要依赖于系统范围的库(例如,通过静态链接所需的模块)来包含所有你需要的代码。

你必须考虑这种方法是特定于操作系统的,这意味着你需要编译你想要支持的每个操作系统的插件! (取决于你可能使用的其他库)

– 电子本地模块

Electron支持本地节点模块,但是由于Electron使用与官方节点不同的V8版本,因此在构build本地模块时必须手动指定Electron头的位置

这意味着已经build立了针对节点头部的本地模块必须被重build以用于电子内部。 你可以find如何在电子文档。

– 与电子应用捆绑模块

我想你想要你的应用程序作为一个独立的可执行文件,而不需要用户在他们的机器上安装电子。 如果是这样,我可以build议使用电子打包器 。

这是另一种方法,到目前为止已经在Mac和Windows上进行了testing。 需要“app-root-dir”包,不需要手动向node_modules dir添加任何内容。

  1. 把你的文件放在资源/ $ os /下,其中$ os“mac”“linux”“win” 。 构build过程将根据构build目标OS从这些目录中复制文件。

  2. extraFiles选项放置在您的构buildconfiguration中,如下所示:

的package.json

  "build": { "extraFiles": [ { "from": "resources/${os}", "to": "Resources/bin", "filter": ["**/*"] } ], 
  1. 使用这样的东西来确定当前的平台。

得到-platform.js

 import { platform } from 'os'; export default () => { switch (platform()) { case 'aix': case 'freebsd': case 'linux': case 'openbsd': case 'android': return 'linux'; case 'darwin': case 'sunos': return 'mac'; case 'win32': return 'win'; } }; 
  1. 根据env和OS调用应用程序的可执行文件。 在这里,我假设内置版本是在生产模式和其他模式的源版本,但你可以创build自己的调用逻辑。
 import { join as joinPath, dirname } from 'path'; import { exec } from 'child_process'; import appRootDir from 'app-root-dir'; import env from './env'; import getPlatform from './get-platform'; const execPath = (env.name === 'production') ? joinPath(dirname(appRootDir.get()), 'bin'): joinPath(appRootDir.get(), 'resources', getPlatform()); const cmd = `${joinPath(execPath, 'my-executable')}`; exec(cmd, (err, stdout, stderr) => { // do things }); 

我想我是用电子生成器作为基础的,env文件的生成伴随着它。 基本上它只是一个JSONconfiguration文件。