如何将预编译的二进制文件与电子捆绑在一起

Posted

技术标签:

【中文标题】如何将预编译的二进制文件与电子捆绑在一起【英文标题】:How can I bundle a precompiled binary with electron 【发布时间】:2016-11-16 15:36:27 【问题描述】:

我正在尝试在电子应用程序中包含一个预编译的二进制文件。我从电子快速启动应用程序开始,并修改了我的 renderer.js 文件以包含此代码,该代码在文件被拖放到正文时触发:

spawn = require('child_process').spawn,
  ffmpeg = spawn('node_modules/.bin/ffmpeg', ['-i', clips[0], '-an', '-q:v', '1', '-vcodec', 'libx264', '-y', '-pix_fmt', 'yuv420p', '-vf', 'setsar=1,scale=trunc(iw/2)*2:trunc(ih/2)*2,crop=in_w:in_h-50:0:50', '/tmp/out21321.mp4']);

ffmpeg.stdout.on('data', data => 
  console.log(`stdout: $data`);
);
ffmpeg.stderr.on('data', data => 
  console.log(`stderr: $data`);
);

我已将预编译的 ffmpeg 二进制文件放入 node_modules/.bin/。在开发面板中一切正常,但是当我使用电子打包器设置应用程序时,它会在触发时向控制台抛出 spawn error ENOENT。我确实在 SO 上找到了very similar question,但这个问题似乎没有得到明确的回答。 npm page on electron-packager 确实表明它们可以捆绑,但我找不到任何有关如何捆绑的文档。

【问题讨论】:

这个页面告诉你你需要知道的:electron.atom.io/docs/tutorial/application-packaging 所以要么:使用 child_process.execFile,或者不使用 asar 打包 【参考方案1】:

问题在于electron-builderelectron-packager 会将您的依赖项捆绑到asar 文件中。似乎如果依赖项有一个二进制文件到 node_modules/.bin 中,它就足够聪明,不会打包它。

这是关于该主题的electron-builder 的documentation for asar packaging。它说

必须解压的节点模块将被自动检测

我了解它与node_modules/.bin 中的现有二进制文件有关。

如果您使用的模块没有自动解包,您可以完全禁用asar 归档或明确告诉electron-builder 不要打包某些文件。您可以在 package.json 文件中这样做:

  "build": 
    "asarUnpack": [
      "**/app/node_modules/some-module/*"
    ],

针对您的特殊情况

我遇到了与ffmpeg 相同的问题,这就是我所做的:

使用ffmpeg-static。该软件包捆绑了用于 Windows、Mac 和 Linux 的静态编译的 ffmpeg 二进制文件。它还提供了一种方法来获取您正在运行的操作系统的二进制文件的完整路径:require('ffmpeg-static').path 这在开发中可以正常工作,但我们仍需要解决分发问题。

告诉electron-builder不要打包ffmpeg-static模块:

“构建”: “asarUnpack”:[ “**/app/node_modules/ffmpeg-static/*” ],

1234563

如果您使用的是 webpack(或其他 javascript 捆绑器)

我遇到了require('ffmpeg-static').path 在渲染器进程中返回相对路径的问题。但问题似乎是 webpack 改变了模块所需的方式,并阻止了 ffmpeg-static 提供完整路径。在开发工具中,require('ffmpeg-static').path 在手动运行时工作正常,但在捆绑代码中执行相同操作时,我总是得到一个相对路径。所以这就是我所做的。

在主进程打开BrowserWindow之前添加这个:global.ffmpegpath = require('ffmpeg-static').path.replace('app.asar', 'app.asar.unpacked')。在主进程中运行的代码并没有被 webpack 打包,所以我总是得到这段代码的完整路径。 在渲染器进程中以这种方式选择值:require('electron').remote.getGlobal('ffmpegpath')

【讨论】:

Maaan,我只花了大约 24 小时在这个上。不知道拆开的部分。干杯 这是一个很好的问题解决者和节省时间的答案。谢谢。 这个包是只打包操作系统所需的二进制文件,还是包含每个包中的所有二进制文件(强大)。 @Trees4theForest 如果您使用的是 electron-builder,那么您可以在 package.json 中指定哪些文件与哪个平台一起使用,例如mac:files:"bin/mac/*",win:files:"bin/win/*"。有关详细信息,请参阅electron.build/configuration/contents#files。 将构建设置放入 package.json 时出错。我将vue.config.js 添加到我的项目目录中:module.exports = pluginOptions: electronBuilder: builderOptions: "extraFiles": "from":"node_modules/ffmpeg-static/bin", "to":"./resources/app.asar.unpacked/bin/" 【参考方案2】:

我知道我来晚了,但我只想提一下 ffbinaries npm 包,我不久前正是为此目的创建的。

它允许您在应用程序启动期间(因此您无需将其与应用程序捆绑)或在 CI 设置中将 ffmpeg/ffplay/ffserver/ffprobe 二进制文件下载到指定位置。可以自动检测平台,也可以手动指定。

【讨论】:

感谢您的包裹,看起来很棒!【参考方案3】:

如果有人碰巧需要回答这个问题:我确实有一个解决方案,但我不知道这是否被认为是最佳实践。我找不到任何包含 3rd 方预编译二进制文件的好的文档,所以我只是摆弄它,直到它最终起作用。这是我所做的(从电子快速入门,node.js v6 开始):

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

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

(将 /usr/local/bin/ffmpeg 替换为您当前的二进制路径,从此处下载)放置链接允许电子打包器包含我保存到 node_modules/ffmpeg/ 的二进制文件。

然后为了获得捆绑的应用路径,我通过运行以下命令安装了 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` );
    );

【讨论】:

【参考方案4】:

我会这样做:

借鉴tsuriga's answer,这是我的代码:

注意:相应地替换或添加 OS 路径。

创建目录./resources/mac/bin 将二进制文件放在此文件夹中 创建文件./app/binaries.js并粘贴以下代码:
'use strict';

import path from 'path';
import  remote  from 'electron';
import getPlatform from './get-platform';

const IS_PROD = process.env.NODE_ENV === 'production';
const root = process.cwd();
const  isPackaged, getAppPath  = remote.app;

const binariesPath =
  IS_PROD && isPackaged
    ? path.join(path.dirname(getAppPath()), '..', './Resources', './bin')
    : path.join(root, './resources', getPlatform(), './bin');

export const execPath = path.resolve(path.join(binariesPath, './exec-file-name'));
创建文件./app/get-platform.js并粘贴以下代码:
'use strict';

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';
  
;
./package.json 文件中添加以下代码:
"build": 
....

 "extraFiles": [
      
        "from": "resources/mac/bin",
        "to": "Resources/bin",
        "filter": [
          "**/*"
        ]
      
    ],

....
,
导入二进制文件路径为:
import  execPath  from './binaries';

#your program code:
var command = spawn(execPath, arg, );

为什么这样更好?

大多数答案都需要一个名为 app-root-dir

的附加包

原始答案无法正确处理 (env=production) buildpre-packed 版本。他/她只负责开发和后打包版本。

【讨论】:

以上是关于如何将预编译的二进制文件与电子捆绑在一起的主要内容,如果未能解决你的问题,请参考以下文章

如何将第三方二进制文件与 Electron 捆绑在一起?

在调试模式下尝试将预编译头文件与 VS2010 (VC100) 一起使用时,如何消除错误 C2859?

如何在电子应用程序中捆绑ffmpeg

如何将预单元测试步骤添加到我的*** Makefile.am?

如何让 pyinstaller 查看基于主目录的配置文件?

如何让 2 个应用程序共享同一个 Dock 磁贴