Electron加载插件支持Flash

2022-03-24 08:10:06 浏览数 (1)

创建项目

代码语言:javascript复制
git clone https://gitee.com/psvmc/electron-quick-start.git
# 重命名
ren electron-quick-start electron-flash-demo
cd electron-flash-demo
# 删除原来的git文件夹
rmdir /s/q .git
rmdir /s/q .github
npm install
npm start

下载32位的Electron

项目根目录中添加.npmrc

代码语言:javascript复制
arch=ia32
registry=https://registry.npm.taobao.org

设置Flash插件

下载插件

下载pepflashplayer插件

注意

这个插件一定要用老版本,新版本的flash由于中国代理商要赚钱,会检测一个服务是否启动,不启动就会报错,强行让更新新版本。

如图

老版本的Chrome下载 里面带有pepflashplayer插件

https://www.slimjet.com/chrome/google-chrome-old-version.php

这里推荐下载32位的最老的版本

Version

Size

Date

48.0.2564.97

40.76 MB

2020-04-29

这个插件已经很难下载到了,我的方法是下载个360浏览器带极速内核的版本,打开一个带有flash的网页,它就会自动下载插件

在浏览器的安装目录下搜索pepflashplayer,就会找到对应的dll文件。

或者下载下面的DLL

pepflashplayer32_20_0_0_286.dll

链接:https://pan.baidu.com/s/1_eMRkJ8m6jILi40BHSH-4Q 提取码:psvm

注意

这个插件是32位的,一定要保证Electron是32位的。

配置插件

把下载的插件放在项目根目录下libs文件夹下,如图所示:

main.js中添加以下代码

代码语言:javascript复制
let pluginName
switch (process.platform) {
    case 'win32':
        pluginName = 'pepflashplayer.dll'
        break
    case 'darwin':
        pluginName = 'PepperFlashPlayer.plugin'
        break
    case 'linux':
        pluginName = 'libpepflashplayer.so'
        break
}

let plugins_path = path.join(__dirname, "libs", "ppflash", pluginName);
if (__dirname.includes(".asar")) {
    plugins_path = path.join(process.resourcesPath, "libs", "ppflash", pluginName)
}

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

注意:

这里一定要进行判断,因为打包前后的路径是不一致的。

不显示菜单栏

代码语言:javascript复制
const electron = require('electron')
/*获取electron窗体的菜单栏*/
const Menu = electron.Menu
/*隐藏electron创听的菜单栏*/
Menu.setApplicationMenu(null)

页面配置

官方文档:

  • https://www.electronjs.org/zh/docs/latest/api/webview-tag
  • https://www.electronjs.org/zh/docs/latest/api/web-contents

可用于测试Flash的页面:https://sc.chinaz.com/donghua/220315391630.htm

方式1

这种方式最为简单。

主进程 BrowserWindow

BrowserWindow添加webPreferences配置

代码语言:javascript复制
const mainWindow = new BrowserWindow({
    width: 1366,
    height: 768,
    webPreferences: {
        webviewTag: true,
        javascript: true,
        plugins: true,
        webSecurity: false
    }
})

plugins: true 这个配置项是必须的。

如果使用的是webview,在标签里添加 plugins 属性。

代码语言:javascript复制
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Flash</title>
</head>
<body>
<webview src="https://sc.chinaz.com/donghua/220315391630.htm" allowpopups plugins></webview>

<style lang="text/css">
    body {
        margin: 0;
        padding: 0;
    }

    webview {
        display: flex;
        width: 100vw;
        height: 100vh;

    }
</style>
</body>
</html>

请注意,webview 标签的样式使用 display:flex; 来确保 iframe在传统和 flex 布局一起使用的情况下填充其 webview 容器的全部高度和宽度。

在devtools的控制台输入以下命令检查Pepper Flash插件是否被加载。

代码语言:javascript复制
navigator.plugins

注意

这个只能判断是否加载插件,不能判断插件是否可用,比如没有dll就不可用,但是插件列表中已经存在。

方式2

这种方式能控制访问的连接。

首先我们看四种打开新页面的方式

代码语言:javascript复制
<a href="https://www.psvmc.cn" target="_blank">_blank</a>
<span onclick="javascript:window.open('https://www.psvmc.cn')">open</span>

分别是:

  1. _blank
  2. .open

实际运行情况是:

在正常的浏览器中,这两种情况都是能新开窗口的。但是,部分浏览器里面可能会拦截.open这种方式。但是绝对没有任何浏览器会拦截_blank这种。

electronwebview中,

  • 对于_blank是默认拦截的,不会自动打开。
  • 对于.open, 添加allowpopups 就会自动用新窗口打开。

所以添加allowpopups 属性,就可以解决面的情况,

_blank的页面添加allowpopups后也无法打开

为了保证两种方式都能正常打开,页面中添加JS,注意

这时候不要添加allowpopups,否则会打开两个页面。 因为new-window能同时监听到这两种方式。

示例

代码语言:javascript复制
<webview src="https://sc.chinaz.com/donghua/220315391630.htm" plugins></webview>
<script>
  onload = () => {
  const webview = document.querySelector('webview')

  const new_window = (e) => {
    const protocol = (new URL(e.url)).protocol;
    if (protocol === 'http:' || protocol === 'https:') {
      //webview.loadURL(e.url)
      if(e.url.indexOf("sc.chinaz.com")!==-1){
        window.open(e.url)
      }
    }
  }

  const will_navigate = (e) => {
    const protocol = (new URL(e.url)).protocol;
    if (protocol === 'http:' || protocol === 'https:') {
      console.info("will_navigate",e.url);
      if(e.url.indexOf("sc.chinaz.com")===-1){
        webview.reload();
      }
    }
  }

  webview.addEventListener('new-window', new_window);
  webview.addEventListener('will-navigate', will_navigate);
}
  </script>

注意

new-window只能监听到页面内_blank.open,页面的重定向是监听不到的。

方式3

这种方式不但能够控制访问的连接,还能设置窗口属性。

默认的方式其实也是新的进程,和下面的方式一样,但是这种方式我们可以做一些窗口属性的设置。

渲染进程

代码语言:javascript复制
<script>
    const ipcRenderer = window.require('electron').ipcRenderer
    onload = () => {
        const webview = document.querySelector('webview')
        const loadstart = () => {
            console.log("开始加载");
        }

        const loadstop = () => {
            console.log("加载完成");
        }

        const new_window = (e) => {
            const protocol = (new URL(e.url)).protocol;
            if (protocol === 'http:' || protocol === 'https:') {
                //window.open(e.url)
                ipcRenderer.send('open_url',e.url);
            }
        }

        webview.addEventListener('did-start-loading', loadstart);
        webview.addEventListener('did-stop-loading', loadstop);
        webview.addEventListener('new-window', new_window);
    }
</script>

主进程

代码语言:javascript复制
let mainWindow;
function createWindow() {
    // Create the browser window.
     mainWindow = new BrowserWindow({
        width: 1366,
        height: 768,
        webPreferences: {
            webviewTag: true,
            javascript: true,
            plugins: true,
            webSecurity: false,
            nodeIntegration: true,
            enableRemoteModule: true,
            contextIsolation: false,
        }
    })

    // and load the index.html of the app.
    mainWindow.loadFile('index.html')

    // Open the DevTools.
    //mainWindow.webContents.openDevTools()
}

const ipcMain = require('electron').ipcMain
let new_win;
ipcMain.on('open_url',(event, arg)=>
{
    new_win = new BrowserWindow({
        width: 1366,
        height: 768,
        title: "",
        webPreferences: {
            webviewTag: true,
            javascript: true,
            plugins: true,
            webSecurity: false
        },
        frame:true,
        parent: mainWindow,
    })
    new_win.loadURL(arg); 
    new_win.on('closed',()=>{new_win = null})
})

注意

主窗口要设置Node环境nodeIntegration: true,

禁止外链跳转

方式1

按照逻辑我们要限制跳转,只要监听will-navigate事件,阻止它e.preventDefault();就行了,但是实际上这并没有用。

如下(这样写并不生效)

代码语言:javascript复制
const will_navigate = (e) => {
  const protocol = (new URL(e.url)).protocol;
  if (protocol === 'http:' || protocol === 'https:') {
    console.info("will_navigate",e.url);
    if(e.url.indexOf("sc.chinaz.com")===-1){
      e.preventDefault();
    }
  }
}

webview.addEventListener('will-navigate', will_navigate);

原因是

所有的 event.preventDefault() 都应该从主进程中呼叫而不是渲染进程。

所以我们就要在主进程中做如下操作

  1. 最外层 BrowserWindowwebContents 上监听 did-attach-webview 事件,获取新挂上去的 <webview>webContents
  2. 使用获取到的 webContents 监听 will-navigate事件。

这时候,我们就可以在 will-navigate 事件中使用 e.preventDefault() 阻止 <webview> 导航至其他网页了

代码如下:

代码语言:javascript复制
mainWindow.webContents.on('did-attach-webview', (e, wc)=>{
  const will_navigate = (e, url)=>{
    console.info(url);
    if (url.indexOf("sc.chinaz.com") === -1) {
      e.preventDefault();
      wc.reload();
    }
  }

  wc.on('will-navigate', will_navigate);
})

方式2

当然换个思路,虽然我们阻止不了,我们直接重新加载不就行了吗。

代码语言:javascript复制
onload = () => {
  const webview = document.querySelector('webview')

  const new_window = (e) => {
    const protocol = (new URL(e.url)).protocol;
    if (protocol === 'http:' || protocol === 'https:') {
      //webview.loadURL(e.url)
      if(e.url.indexOf("10.88.8.90:9080")!==-1){
        window.open(e.url)
      }
    }
  }

  const will_navigate = (e) => {
    const protocol = (new URL(e.url)).protocol;
    if (protocol === 'http:' || protocol === 'https:') {
      console.info("will_navigate",e.url);
      if(e.url.indexOf("10.88.8.90:9080")===-1){
        webview.reload();
      }
    }
  }

  webview.addEventListener('new-window', new_window);
  webview.addEventListener('will-navigate', will_navigate);
}

我的方案

下面的两种方案 我最终的选择是

上面页面配置的方式3和禁止跳转的方式1相结合,这样就可以同时处理主页面和子页面的跳转限制。

主进程

代码语言:javascript复制
let mainWindow;
function createWindow() {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 1366,
    height: 768,
    webPreferences: {
      webviewTag: true,
      javascript: true,
      plugins: true,
      webSecurity: false,
      nodeIntegration: true,
      enableRemoteModule: true,
      contextIsolation: false,
    }
  })

  // and load the index.html of the app.
  mainWindow.loadFile('index.html')

  // Open the DevTools.
  //mainWindow.webContents.openDevTools()
  addListener(mainWindow);
}

const ipcMain = require('electron').ipcMain
let new_win;
ipcMain.on('open_url',(event, arg)=>
{
  new_win = new BrowserWindow({
    width: 1366,
    height: 768,
    title: "",
    webPreferences: {
      webviewTag: true,
      javascript: true,
      plugins: true,
      webSecurity: false
    },
    frame:true,
    parent: mainWindow,
  })
  new_win.loadURL(arg);
  new_win.on('closed',()=>{new_win = null})
  addListener(new_win);
})

function addListener(win){
  //主页面中的重载
  win.webContents.on('did-attach-webview', (e, wc)=>{
    const will_navigate = (e, url)=>{
      if (url.indexOf("10.88.8.90:9080") === -1) {
        e.preventDefault();
        wc.reload();
      }
    }
    wc.on('will-navigate', will_navigate);
  })

  // 子页面中的重载
  const will_navigate = (e, url)=>{
    if (url.indexOf("10.88.8.90:9080") === -1) {
      e.preventDefault();
      win.webContents.reload();
    }
  }
  win.webContents.on('will-navigate', will_navigate);
}

渲染进程

代码语言:javascript复制
<webview src="http://10.88.8.90:9080/AtomLocal/common/login.faces" disablewebsecurity plugins></webview>
<script>
  const ipcRenderer = window.require('electron').ipcRenderer
  onload = () => {
    const webview = document.querySelector('webview');
    let lastUrl = "";
    const new_window = (e) => {
      // 防止同样的地址,多次调用
      if(!lastUrl){
        const protocol = (new URL(e.url)).protocol;
        if (protocol === 'http:' || protocol === 'https:') {
          if(e.url.indexOf("10.88.8.90:9080")!==-1){
            ipcRenderer.send('open_url',e.url);
            lastUrl = e.url;
            setTimeout(()=>{
              lastUrl = "";
            },1000)
          }
        }
      }
    }
    webview.addEventListener('new-window', new_window);
  }
</script>

打包

添加依赖

代码语言:javascript复制
npm install electron-builder@22.9.1 --save-dev

在pakage.json中,我们build的配置下面内容:

代码语言:javascript复制
{
  "name": "flashapp",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "dist": "electron-builder --win --ia32",
    "dist_dir": "electron-builder --win --ia32 --dir"
  },
  "build": {
    "appId": "cn.psvmc.flashapp",
    "productName": "Flash加载",
    "icon": "app.ico",
    "asar": true,
    "files": [
      "main.js",
      "*.html",
      "app.ico",
      "node_modules/**/*"
    ],
    "mac": {
      "icon": "app.ico",
      "target": [
        "dmg",
        "zip"
      ]
    },
    "win": {
      "icon": "app.ico",
      "target": [
        "zip"
      ],
      "extraResources": "./libs/**/*"
    },
    "nsis": {
      "oneClick": false,
      "allowElevation": true,
      "allowToChangeInstallationDirectory": true,
      "installerIcon": "app.ico",
      "uninstallerIcon": "app.ico",
      "installerHeaderIcon": "app.ico",
      "createDesktopShortcut": true,
      "createStartMenuShortcut": true,
      "license": "LICENSE.txt"
    }
  },
  "devDependencies": {
    "electron": "^11.1.1",
    "electron-builder": "22.9.1"
  }
}

其中最重要的配置就是 "extraResources": "./libs/**/*" 这样的话我们的所有配置就算完成了。

注意NodeJS的版本要在14以上

代码语言:javascript复制
nvm install 14.17.1
nvm use 14.17.1

依赖版本号

代码语言:javascript复制
"electron-builder": "22.9.1"
"electron-builder": "~22.9.1"
"electron-builder": "^22.9.1"

其中

  1. 前面不带符号则版本号的3个数字都匹配
  2. ~则版本号的前2个数字匹配
  3. ^则版本号的第一个数字匹配

建议

使用~ 版本号

0 人点赞