乐趣区

关于vue.js:Electron播放-RTMP流-实现

在基于 vuecli3 与 electron 的框架外部,实现 rtmp 流的播放,为什么要写这篇文章,因为确实实现起来踩了很多坑,并没有像 web 那样导入 videoJS 就能实现的,闲话不说,上代码:

第一个坑:

须要用到的库
vue-video-player
videojs-flash
留神:下面这个两个库 肯定要用 npm 装置。我试过,其余形式装置实现之后会这个谬误:the flash tech is undefined,如果你遇到这个谬误,肯定先 npm uninstall vue-video-player , 再重新安装一次即可。

第二个坑

播放 rtmp 须要 flash 的反对,Electron 的实现须要代码加载 flash 的 dll 文件来取得反对,Electron 的 app 类中有个 getPath 办法,执行以下代码能获取本机的 flash 文件门路:
app.getPath('pepperFlashSystemPlugin')
我的跑起来获取的地址是:C:WINDOWSsystem32MacromedFlashpepflashplayer64_32_0_0_414.dll
所以让 electron 反对 flash 代码:

app.commandLine.appendSwitch('ppapi-flash-path', app.getPath('pepperFlashSystemPlugin'));

当然最好的计划是可能把 dll 文件间接打包到我的项目外面跟着我的项目一起走,通过在 vue.config.js 中增加以下代码实现

  pluginOptions: {
    electronBuilder: {
      builderOptions: {
       ...
        win: {
          target: 'nsis',
          icon: './public/app.ico',
          extraResources: [
                {
                  "from": "resources/",
                  "to": "./",
                }
          ]
        }
      }
    }
  }

把 dll 文件 copy 到 resources 文件夹下(根目录与 vue.config.js 同级)而后批改文件加载门路:

let plugins = ''if(process.arch =='x64'){plugins =process.env.WEBPACK_DEV_SERVER_URL? path.join(__dirname,`../resources/pepflashplayer64_32_0_0_238.dll`) :path.join(__dirname,`../pepflashplayer64_32_0_0_238.dll`)
  }else{plugins =process.env.WEBPACK_DEV_SERVER_URL? path.join(__dirname,`../resources/pepflashplayer32_29_0_0_238.dll`) :path.join(__dirname,`../pepflashplayer32_29_0_0_238.dll`)
  }
app.commandLine.appendSwitch('ppapi-flash-path', plugins)

第三个坑

以上的货色搞完根本能够实现播放了,然而打包之后发现不能够,看景象 像是加载不出 flash,解决方案就是在启动 Electron 主过程的时候,启动一个本地 express 服务器,配置一下动态文件地址,而后渲染过程通过这个服务器拿到页面,在而后就能够启动 flash 了。
上代码:

'use strict'

import {app, BrowserWindow,ipcMain} from 'electron'
 import {createProtocol} from 'vue-cli-plugin-electron-builder/lib'
// import installExtension, {VUEJS_DEVTOOLS} from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win

let allowPort =null
import express from 'express'

const net = require('net');


async function portInUse(port){return new Promise((resolve, reject)=>{let server = net.createServer().listen(port);
      server.on('listening',function(){server.close();
          resolve(port);
      });
      server.on('error',function(err){if(err.code == 'EADDRINUSE'){
              port++;
              reject(err);
          }
      });        
  });
}

const tryUsePort = function(port,_portAvailableCallback){portInUse(port).then((port)=>{_portAvailableCallback(port);
  }).catch((err)=>{console.log(port+"==== 被占用 ====:\n");
      port++;
      tryUsePort(port,_portAvailableCallback);
  })  
}

tryUsePort(9080,function(port){
  // do something ...
  console.log(port+"==== 端口:"+port+"可用 ====\n");
  allowPort = port
  // net.createServer().listen(port);

  // 解决 flash 本地 file 不平安问题
  if (process.env.NODE_ENV === "production") {let server = express();
    server.use(express.static(__dirname));
    server.listen(port);
  }

  const winURL = process.env.NODE_ENV === 'development'
  ? `http://localhost:${allowPort}` 
  // : `file://${__dirname}/index.html`
  // 解决 flash 在 file 下不平安的问题
  : `http://localhost:${allowPort}/index.html`

  console.log(winURL)
  const path = require('path')

  let plugins = ''if(process.arch =='x64'){plugins =process.env.WEBPACK_DEV_SERVER_URL? path.join(__dirname,`../resources/pepflashplayer64_32_0_0_238.dll`) :path.join(__dirname,`../pepflashplayer64_32_0_0_238.dll`)
  }else{// plugins =process.env.WEBPACK_DEV_SERVER_URL? path.join(__dirname,`../resources/pepflashplayer32_29_0_0_238.dll`) :path.join(__dirname,`../pepflashplayer32_29_0_0_238.dll`)
    plugins =app.getPath('pepperFlashSystemPlugin') 
  }

console.log(app.getPath('pepperFlashSystemPlugin') )
  app.commandLine.appendSwitch('ppapi-flash-path', plugins)
  // Optional: Specify flash version, for example, v17.0.0.169

  function createWindow() {
    // Create the browser window.
    win = new BrowserWindow({
      width: 1000,
      height: 580,
      webPreferences: {
        nodeIntegration: true,
        plugins: true,
        webSecurity: false // 勾销跨域
      },
      autoHideMenuBar:true,
      maximizable: false,
      resizable: false,
      frame: false,
    })

    if (process.env.WEBPACK_DEV_SERVER_URL) {
      // Load the url of the dev server if in development mode
      win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
      // if (!process.env.IS_TEST) win.webContents.openDevTools()} else {

      // 批改前
      createProtocol('app')
      // win.loadURL('app://./index.html')
      // 批改后 
      win.loadURL(winURL)
    }

    win.webContents.openDevTools({mode: 'detach'})

    win.on('closed', () => {win = null})
  }

  // Quit when all windows are closed.
  app.on('window-all-closed', () => {
    // On macOS it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {app.quit()
    }
  })

  app.on('activate', () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (win === null) {createWindow()
    }
  })

  // This method will be called when Electron has finished
  // initialization and is ready to create browser windows.
  // Some APIs can only be used after this event occurs.
  app.on('ready', async () => {// if (isDevelopment && !process.env.IS_TEST) {
    //   // Install Vue Devtools
    //   try {//     await installExtension(VUEJS_DEVTOOLS)
    //   } catch (e) {//     console.error('Vue Devtools failed to install:', e.toString())
    //   }
    // }
    createWindow()})

以上就是局部代码能看清楚解决逻辑,

第四个坑

port 占用,通过 net 对象 写一个递归加一点判断 获取以后可用端口,代码如上

第五个坑

到当初你感觉完事大吉了,然而只能开心一会会,在某些状况下还是会呈现 flash 加载解体问题,这个时候你就要核查下你的 flash 版本问题,我试过 30 以上都不行 29 能够,举荐这个版本:pepflashplayer64_29_0_0_140.dll
pepflashplayer32_29_0_0_140.dll

备注:我的上述代码只是兼容了 64 位的电脑,如果须要兼容 32 位电脑自行加点判断即可

退出移动版