# electron-remote-control
**Repository Path**: zlmcode/electron-remote-control
## Basic Information
- **Project Name**: electron-remote-control
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 2
- **Created**: 2023-05-19
- **Last Updated**: 2023-05-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 目录结构

```shell
cd app/renderer/src
npx create-react-app main --use-npm
```
## 报错集锦
### 解决在renderer(cra项目)中引入electron模块报错的问题
根本原因是cra的webpack解析不到electron模块所导致
详见 app/renderer/src/main/src/App.js
```jsx
//import {ipcRenderer} from 'electron'; //无法解析electron这个模块 (因为我们cra并没有装,即使装了也和我们外层使用的electron不是同一份)
/** 法一*/
const {ipcRenderer} = window.require('electron'); //window.require是我们外面的electron往本地注入的, 我们这样加载, 就不会触发cra的webpack的解析, 也就不会报错
/** 法二*/
//https://webpack.docschina.org/configuration/target/#root
//将cra的webpack配置的target属性设置为electron-renderer
```
法二 需要安装如下插件
```shell
yarn add customize-cra react-app-rewired --dev
```
这样就不用eject cra配置来做一些webpack改动
改动详见 `app/renderer/src/main/config-overrides.js.back`
然后修改cra项目的启动脚本
```shell
#"start": "cross-env BROWSER=none react-scripts start"
# ↑ 改为 ↓
"start": "cross-env BROWSER=none react-app-rewired start"
```
emmm... 但Electron12.x下会报另外一个错误:`Uncaught ReferenceError: require is not defined` (
已开启`nodeintegration`)
### 安装robotjs报错

> https://github.com/nodejs/node-gyp#on-windows
> 关于node-gyp
>
>编译 C++ 扩展用的。 长久以来 linux 的二进制分发一直是巨坑,npm 为了方便干脆就直接源码分发,用户装的时候再现场编译。不过对另一些人二进制分发就比源码分发简单多了,所以还有个 node-pre-gyp 来干二进制扩展的分发。
windows 下主要是要安装 vs, 安装时勾上 “Desktop development with C++”
另外需要告诉npm你安装的vs版本,需要设置如下
```shell
npm config set msvs_version 2019
```
+ 如果你安装的是vs2019的话
> https://github.com/nodejs/node-gyp#on-windows
或则 你也可以不用安装vs, 而是直接 管理员权限打开执行
```shell
npm install --global --production windows-build-tools
```
+ emmm 笔者没有试过
除此之外 还需要安装python
> https://github.com/nodejs/node-gyp#configuring-python-dependency
>
> https://www.python.org/downloads/release/python-394/
### require robojs 报错


> https://www.electronjs.org/docs/api/app#appallowrendererprocessreuse
>
> https://github.com/mapbox/node-pre-gyp/blob/master/lib/util/abi_crosswalk.json
>
```shell
npm rebuild --runtime=electron --target=12.0.2 --disturl=https://atom.io/download/atom-shell --abi=83 --arch=ia32
```
+ target是electron版本
+ 如果想使用的32位(比如你后面要打包成32位的应用), 这里的robojs依赖就应该rebuild为32位, 就需要设置 `--arch=ia32`
+ 前提是需要你的node安装的是x86 而不是 x64
Electron12.x下可能还会报另外一个错误↓

```shell
app.allowRendererProcessReuse = false;
```
+ 为true时,渲染进程下某些本地native module就不能使用(官方推荐你通过IPC在Main进程下调用这些模块)
## 业务分析



+ 控制端输入傀儡端の识别码 进行控制
### 关键点分析





### 需求汇总

### 技术选型确认


+ `getUserMedia`: 获取多媒体数据
+ `RTCPeerConnection`: 建立p2p连接,传输我们通过`getUserMedia`拿到的视频流


## 代码实现
### 基础业务页面实现

### 基于Electron能力捕获桌面流


详情查看提交历史
### 接受 和 响应指令




### 基于WebRTC传输视频流


简单总结下 就是 我们控制端发起了一个邀请, 傀儡端在确认邀请之后呢, 把自己的桌面流添加到P2P的连接当中, 然后同样返回一个确认的协议, 最后我们控制端将确认的协议也设置上,
这样子的话我们就代表着控制端和傀儡端的P2P连接已经可以开始了
但需要注意的是此时我们还差一个步骤(在控制页还无法看到被控制方的画面), 我们需要知道彼此的公网ip (查看下面的 `p2p 难题` 部分, SDP协议里有ip, 但那个应该是私网的)
#### SDP

#### p2p 难题

p2p连接肯定会比它走服务端会来的快而且还更安全
那为什么我们要做一层服务端的一个转发?
答案很多, 其中有一个原因就是我们在端到端的通信时, 需要知道对方的公网IP和端口号
这并不是意见容易的事, 因为我们的网络环境里充斥着 NAT(`Network Address Translation`) 网络地址转换技术
为什么这技术会出现呢? --- IPv4地址不够用了, 它本来就是一个32位的整数, 理论上只能支持40多亿的地址, 这个数远远小于世界的总人口; 另外IP地址在地里位置上分配不均, 美国非常的多,
中国是非常稀缺的, 中国人均只有0.06个地址, 占据世界人口56%的亚洲只能够分配到9%的地址, 于是人类为了解决地址的问题, NAT 就出现了
NAT 内, 每一个设备它都会有一个独立的区域网地址, 它们在跟外网连接的时候会共用同一个公网IP, 而NAT它负责维护一个包括本地IP端口 和 外网IP端口的一个映射表

那我们怎么样去获得真正的 IP 和 端口呢?
这里面就会涉及到 NAT 打洞
基本方法就是由服务端 跟 其中一方建立一个连接
这个时候呢 NAT 里面就会建立一个端口号的内外网的一个映射, 之后我们服务端就可以知道 Client B 外网的IP 和 端口号,
然后服务端 在把这个信息 传递给 ClientA 即可

以上, 在 `WebRTC` 里 已经有一个集成好的机制(`ICE`)

+ WebRTC它的NAT穿透是一整个机制, 我们管它叫ICE, 而其中上面说的穿越打洞的 STUN 服务 只是其中的一种, 当 STUN服务 失败之后, 我们会进入到TURN的一个降级方案,
它的本质是一个服务器的中转
+ 有8成几率能正式走通, 其中有一种失败是最常见的, 即我们的NAT是对称的NAT

#### 信令服务(Signal Server)
> 信令
>
>signaling

> 第一个作用是转发各种 SDP
ClientA 在拿到 offer 之后, 会通过信令然后转发到我们的 ClientB, 同样我们的 ClientB 创建完 Answer之后, 也是通过信令服务直接转到我们的 Client A
> 第二个作用
我们 ClientA 它去做寻址的时候, 我们拿到 Candidate 也是通过 信令服务 转发到我们的 ClientB, 同样的 ClientB 也是会通过 Signal Server(信令服务)
转发到我们 ClientA, 才完成整个P2P的连接


### 使用 RTCDataChannel 来传输指令

不使用信令服务 是为了 不给服务器造成不必要的鸭梨



## WebRTC 资料补充
> https://www.html5rocks.com/en/tutorials/webrtc/basics/
>
> https://cloud.tencent.com/developer/article/1005489
>
> https://url.cn/5lucoBr
## App 特性
### 关于窗口

### 禁止多开
```jsx
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// 当运行第二个实例时,将会聚焦到myWindow这个窗口
showMainWindow()
})
app.on('ready', () => {
//....
})
}
```
### 窗口假关闭
用户点击窗口关闭按钮时, 应用只是隐藏
右键任务栏窗口图标点击退出应用时, 才真正关闭
> emmm windows 下貌似不行, 必须结合 Tray 才有效果(即必须要设置 Tray托盘)
## 原生GUI
### 菜单

### 托盘


### dialog

## 总结



## 打包



### 软件图片准备



### electron-builder



其中 `nsis` 它是一个开源的,Windows系统安装程序的制作程序,它提供了安装、卸载、系统设置 文件解压缩等功能。
具体它的配置的话有一些细节点, 首先呢如果你想做成那种一直点下一步安装的话, 你需要将 `oneClick` 设成 false, 然后我们可以通过 `language` 来设置我们安装包的语言,
比如2052代表的是中文, 而 `perMachine` 的话代表是不是要给这个系统上所有的用户安装, `allowToChangeInstallationDirectory` 让用自己选择安装目录
`squirrel` 它是一个一键的安装包, 在安装的过程里面, 它只会显示一个动图, 我们可以通过设置动图来去替换它原来的, 另外有一个非常关键的细节点, 你需要设置 `iconUrl` ,
这是一个必备的, 而且还必须是一个远程的url

### 具体步骤
1. 修改cra前端项目的 `package.json` (`app/renderer/src/main/package.json`), 设置 `"homepage": "./"`
。(这样打包的时候资源才能正常的拿到(?))
2. 给 cra前端项目的 `package.json` 添加 `postbuild` 钩子, build完之后去触发资源的挪动
3. 配置electron项目的根`package.json`, 添加如下配置
```json
"build": {
"appId": "com.nobody.konows",
"productName": "electron-remote-control",
"files": "app",
"asar": false,
"extraFiles": [
"app/renderer/**/src"
],
"directories": {
"buildResources": "resource",
"output": "release"
},
"copyright": "Copyright © 2020 dragon",
"mac": {
"target": [
"dmg",
"zip"
],
"icon": "resources/icon.icns"
},
"dmg": {
"background": "resources/background.png",
"window": {
"width": 540,
"height": 380
},
"contents": [
{
"x": 410,
"y": 180,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 180,
"type": "file"
}
],
"iconSize": 128
},
"win": {
"icon": "resources/icon.ico",
"target": [
"squirrel",
"nsis"
]
},
"nsis": {
"oneClick": false,
"language": "2052",
"perMachine": true,
"allowToChangeInstallationDirectory": true
},
"squirrelWindows": {
"iconUrl": "https://raw.githubusercontent.com/dengyaolong/geektime-electron/master/img/icon.ico"
}
}
```
+ `files`: 要打包的文件
+ `extraFiles`: 指定不打包的内容, 要过滤掉cra前端项目的源码
+ `asar`: 为true的话 会进行简单的加密和压缩
4.配置electron项目的根`package.json`, 添加 build、pack命令
### 报错
> Get "https://github.com/electron/electron/releases/download/v12.0.2/electron-v12.0.2-win32-x64.zip": dial tcp 192.30.255.112:443: connec
tex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection fail
ed because connected host has failed to respond.
设置淘宝源, 还不行反复试试多打几次
```shell
"pack:win:64": "npm run build && cross-env NPM_CONFIG_ELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/ electron-builder build --win --x64"
```
### 安装包


### 安装后文件目录分析

### 打包总结

通常我们会基于 npm version, `patch/minor/major` 来去管理升级, 比如我们要去打一个patch的时候, 我们会执行 `npm version patch`, 这样子我们的版本号它就会自动升级 会打commit 打tag, 而当我们做Feature的时候, 通常是一个 minor, 大版本升级是 major
### 资料
+ NSIS 文档 https://nsis.sourceforge.io/Docs/Chapter1.html#intro-about
+ electron-builder https://www.electron.build/configuration/nsis
+ 苹果证书 https://help.apple.com/xcode/mac/current/#/dev80c6204ec
+ electron-builder介绍 https://zhuanlan.zhihu.com/p/45250432
+ 使用 AppVeyor 和 Travis 自动编译 Electron 全平台应用
## 软件更新
### pre








### Electron 更新方式(自动更新)
>https://www.electronjs.org/docs/tutorial/updates
>




#### mac

+ 返回格式必须严格遵守上面的, `electron.autoUpdater` 会依赖返回的内容做出对应的处理。(详情查看 `app/main/updater.js`)
mac下测试时, 可以自建证书

完整客户端更新逻辑如下


#### windows
>http://e.125.la/ciku.html
>




##### 坑
其一: 第一次启动应用时, 不会收到更新
> https://github.com/electron/electron/issues/ 7155#issuecomment-245993316
其二: 更新替换过程如果被中断, 整个应用会报错
#### todo 更新



## 崩溃监控
>https://www.electronjs.org/docs/api/crash-reporter#crashreporterstartoptions


### 服务端接受处理

### 客户端

todo:
1. emmm 我们这 12.x windows系统下, 监控起作用了, 也会发起post请求, 但报告文件貌似没有上传?(通过postman测试 接口是正常的 文件能正常上传, 说明是监控进程没有上传报告 只发送了一个空post)
2. 渲染进程引入 crash-reporter 会报错
### 技巧


### 查看监控进程

### 崩溃解析

crash-reporter 上传的报告是无法直接解读的, 需要用 `minidump` 这个包来解析, 这个包会用到 [symbol](https://github.com/electron/electron/releases/tag/v12.0.2) (←到这里去下载)
>查看 test-minidump

+ 注意 区分arm64 和 x64
### 难点

### 总结 和 最佳实践


### 资料
+ http://seenaburns.com/debugging-electron-memory-usage/
+ https://cloud.tencent.com/developer/article/1084368
+ https://juejin.im/post/5c5ee47be51d457f95354c82
+ https://developers.google.com/web/tools/chrome-devtools/memoryproblems?hl=zh-cn
## Node.js 扩展
```shell
npm install --global --production windows-build-tools (Windows必备,管理员身份运行)
npm install -g node-gyp
```
### node-gyp 介绍 及 安装指南
> https://github.com/nodejs/node-gyp#on-windows
> 关于node-gyp
>
> 是一个创建项目的生成工具, 它解决了跨平台的一些问题, 其中 gyp 就是 generate your project 的意思
>
>编译 C++ 扩展用的。 长久以来 linux 的二进制分发一直是巨坑,npm 为了方便干脆就直接源码分发,用户装的时候再现场编译。不过对另一些人二进制分发就比源码分发简单多了,所以还有个 node-pre-gyp 来干二进制扩展的分发。
windows 下主要是要安装 vs, 安装时勾上 “Desktop development with C++”
另外需要告诉npm你安装的vs版本,需要设置如下
```shell
npm config set msvs_version 2019
```
+ 如果你安装的是vs2019的话
> https://github.com/nodejs/node-gyp#on-windows
或则 你也可以不用安装vs, 而是直接 管理员权限打开执行
```shell
npm install --global --production windows-build-tools
```
+ emmm 笔者没有试过
除此之外 还需要安装python
> https://github.com/nodejs/node-gyp#configuring-python-dependency
>
> https://www.python.org/downloads/release/python-394/
### 法一: Node C++ Addons (扩展)


查看 `node-addons-example/fingerprint-example`
这样将写好的包 发布后
就可以直接在项目中使用了

### 法二: ffi-napi 直接使用动态链接库
本质上是node-ffi是一个JavaScript加载和调用动态库的Node.js扩展
它可以让我们不编写任何的C++代码情况下,创建与本地dll的绑定
同时它还负责了 JavaScript 和 C 的类型转换
相比于 Node.js 的 addon 它主要有几个优点:
+ 不需要源代码
+ 不需要每次都重新编译
+ 不需要写C的代码
劣势
+ 性能会有折损
+ 排查错误比较困难(黑盒)



#### windows



#### mac
mac的话 需要使用 `applescript` 这个包


### 使用其它语言
+ OC: `https://github.com/TooTallNate/NodObjC`
+ Rust: `https://neon-binding.com/docs/`
### require是怎么加载动态库的

### 资料
+ Node Addon 书籍:https://book.douban.com/subject/30247892/
+ Node Addon 例子:https://github.com/nodejs/node-addon-examples
+ Dll 使用介绍:https://www.psvmc.cn/article/2019-10-20-electron-dll.html
+ AppleScript 介绍 https://sspai.com/post/46912
+ require 源码解读:www.ruanyifeng.com/blog/2015/05/require.html
## 测试 和 端到端测试
### pre



### Electron



#### 关于 自定义驱动

### 资料
+ 使用自定义驱动程序进行自动化测试:https://www.electronjs.org/docs/ tutorial/automated-testing-with-a-custom-driver
+ spectron启动失败:https://github.com/electron-userland/spectron/ issues/489
+ 平衡单元测试和端到端测试:https://www.infoq.cn/article/balancing-unitand-end-to-end-tests
+ JS测试:https://www.sitepoint.com/javascript-testing-unit-functionalintegration/
## Electron 如何优化?
主要方向有两个:
+ 流畅
+ Native化
### 流畅
所谓流畅, 第一个是我们启动要快, 第二个是我们交互要快
#### 启动时性能优化
+ 优先加载核心功能,其他非核心流程模块动态加载
+ 不要全部在头部的时候引进来 比如 robojs 不需要在启动时立马加载, 当应用准备完后再加载也是可以的
+ Web 性能优化
+ 多进程多线程技术:BrowserWindow、BrowserView、ChildProcess、WebWorker
+ (windows下)asar 可以轻微加快 require 的速度 (主要是解决windows下的文件目录过长导致的require性能问题)
+ V8的snapshot 可以减少我们代码在启动时候编译的过程, 应用启动时主需要反序列化一下我们的 V8 snapshot 即可启动(Atom就用过这个方式, 具体可见`electron-link`这个仓库)
#### 运行时性能优化技巧
+ 让主进程保持轻量(使用一个渲染进程处理密集计算)
+ 渲染进程跟主进程有一些 Sync IPC 操作(同步的ipc操作)
+ 主进程卡,UI 就会阻塞
+ 不要使用 remote(同步IPC, 会阻碍UI渲染)
+ 使用 requestIdleCallback (空闲时执行, 可以用于检查更新)
+ 窗口复用 (有点像是手机端上的Webview池, 比如在我们的应用中, 我们保留一个没有被使用的窗口, 等到我们真正去需要窗口的时候, 我们可以直接唤起这个窗口, 而无需重新创建)
### native化
表现得像native
#### 白屏
##### 为什么要关注白屏?
+ 2秒内加载完成,超过3秒以后40%用户会离开你
+ Google 加载时间从0.4秒提升到0.9秒导致丢失了20%流量和广告收入
+ 亚马逊页面加载时间每增加100毫秒就意味着1%的销售额损失
##### Electron 应用为什么要关注白屏?
Native PC 是不会出现白屏的, 至少会有一个骨架屏

##### 为什么会白屏?

##### 最基本的解决方式

##### 更好的解决方案

上面最基本的解决方案 会延迟 窗口展现的时机
更好的一个方式是 使用遮罩 loading window


#### 快捷键 的 兼容 与 自定义

#### 本地化(i18n)

#### 开机自启动

### 资料
+ https://zhuanlan.zhihu.com/p/37050595
+ https://phrase.com/blog/posts/building-an-electron-app-withinternationalization-i18n/
+ https://www.iguan7u.cn/2019/06/30/Electron%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E8%AE%AF%E8%AF%A6%E8%A7%A3/
+ https://cloud.tencent.com/developer/article/1558453
+ https://blog.acohome.cn/inside-browser-part1/
## 安全

### XSS 和 RCE
`
`
Electron 不仅是个浏览器, 它还具有操控我们底层的原生能力, XSS 在Electron中就会变成 RCE, 也就是我们的远程代码执行漏洞
`
`
即从原本只对浏览器有影响 变成了 对整个系统产生影响
### 最佳实践

+ 开启Electron自身的Web Security
+ 如果是客新语 或则是 我们的本地协议, 我们才可以允许它取做具体的跳转
### 从架构上要考虑哪些方面

+ https://blog.npmjs.org/tagged/security
+ https://github.com/nodejs/security-wg

### 克隆攻击 与 防范


chrome中不存在这个问题, 但Electron有

解决方案↓

### 资料
+ https://www.electronjs.org/docs/tutorial/security
+ https://www.blackhat.com/docs/us-17/thursday/us-17-CarettoniElectronegativity-A-Study-Of-Electron-Security-wp.pdf

## Electron 不好的地方 及 补救方案
### 包体积大


### 源码安全问题



### 没有LTS(Long-term support)

### 其它

### 资料
+ https://medium.com/commitlog/electron-is-cancer-b066108e6c32
+ https://www.zdnet.com/article/slacks-desktop-client-gets-majorperformance-improvements-after-codebase-rewrite/
+ https://josephg.com/blog/electron-is-flash-for-the-desktop/
+ https://rauchg.com/2020/2019-in-review
## 更多
+ 官方文档
+ YouTube ---> Electron Conf, like CovalenceConf
+ https://github.com/dengyaolong/geektime-electron