在基于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
import express from 'express'
const net = require('net');
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)=>{
port++;
tryUsePort(port,_portAvailableCallback);
})
}
tryUsePort(9080,function(port){
console.log(port+" ====端口:"+port+"可用====\n");
//解决flash本地file不安全问题
if (process.env.NODE_ENV === "production") {
let server = express();
server.use(express.static(__dirname));
server.listen(port);
}
const winURL =`http://localhost:${port}/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')
}
app.commandLine.appendSwitch('ppapi-flash-path', plugins)
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) {
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
win.webContents.openDevTools()
} else {
createProtocol('app')
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位电脑自行加点判断即可