feat(desktop): add desktop inject

pull/100/head
moonrailgun 3 years ago
parent eb83f784a1
commit 27eee90034

@ -0,0 +1,36 @@
import { app } from 'electron';
/**
* Webviewjs
*/
export function generateInstallPluginScript() {
/**
* manifest copy from:
* com.msgbyte.env.rn/manifest.json
*/
const inner = `function main() {
window.tailchat
.installPlugin({
label: 'Electron Support',
'label.zh-CN': 'Electron 支持',
name: 'com.msgbyte.env.electron',
url: '/plugins/com.msgbyte.env.electron/index.js',
version: '0.0.0',
author: 'moonrailgun',
description: 'Add support for Electron environment in Tailchat',
'description.zh-CN': '在 Tailchat 添加对 Electron 环境的支持',
requireRestart: true,
});
}`;
const raw = `(${inner})()`;
return raw;
}
export function generateInjectedScript(): string {
return [generateDeviceInfo()].join(';');
}
function generateDeviceInfo() {
return `window.__electronDeviceInfo = { version: "${app.getVersion()}", name: "${app.getName()}" }`;
}

@ -0,0 +1,15 @@
import { generateInstallPluginScript } from '.';
import log from 'electron-log';
export function handleTailchatMessage(
type: string,
payload: any,
webview: Electron.WebContents
) {
log.info('onMessage receive:', type, payload);
if (type === 'init') {
webview.executeJavaScript(generateInstallPluginScript());
return;
}
}

@ -17,6 +17,8 @@ import { getMainWindowUrl } from './util';
import windowStateKeeper from 'electron-window-state'; import windowStateKeeper from 'electron-window-state';
import is from 'electron-is'; import is from 'electron-is';
import { initScreenshots } from './screenshots'; import { initScreenshots } from './screenshots';
import { generateInjectedScript } from './inject';
import { handleTailchatMessage } from './inject/message-handler';
log.info('Start...'); log.info('Start...');
@ -103,6 +105,7 @@ const createWindow = async () => {
width: mainWindowState.width, width: mainWindowState.width,
icon: getAssetPath('icon.png'), icon: getAssetPath('icon.png'),
webPreferences: { webPreferences: {
nodeIntegration: false,
preload: app.isPackaged preload: app.isPackaged
? path.join(__dirname, 'preload.js') ? path.join(__dirname, 'preload.js')
: path.join(__dirname, '../../.erb/dll/preload.js'), : path.join(__dirname, '../../.erb/dll/preload.js'),
@ -142,6 +145,21 @@ const createWindow = async () => {
}); });
} }
mainWindow.webContents.on('did-start-navigation', () => {
if (mainWindow) {
mainWindow.webContents.executeJavaScript(generateInjectedScript());
}
});
mainWindow.webContents.on('ipc-message', (e, channel, data) => {
if (channel === 'webview-message') {
const obj = JSON.parse(data);
if (typeof obj === 'object' && obj._isTailchat === true && mainWindow) {
handleTailchatMessage(obj.type, obj.payload, mainWindow.webContents);
}
}
});
mainWindow.on('ready-to-show', () => { mainWindow.on('ready-to-show', () => {
if (!mainWindow) { if (!mainWindow) {
throw new Error('"mainWindow" is not defined'); throw new Error('"mainWindow" is not defined');
@ -167,6 +185,8 @@ const createWindow = async () => {
return { action: 'deny' }; return { action: 'deny' };
}); });
mainWindowState.manage(mainWindow);
// Remove this if your app does not use auto updates // Remove this if your app does not use auto updates
new AppUpdater(); new AppUpdater();
} catch (err) { } catch (err) {

@ -1,11 +1,16 @@
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'; import {
contextBridge,
ipcRenderer,
IpcRendererEvent,
webFrame,
} from 'electron';
export type Channels = 'ipc-example'; export type Channels = 'ipc-example' | 'webview-message';
contextBridge.exposeInMainWorld('electron', { contextBridge.exposeInMainWorld('electron', {
ipcRenderer: { ipcRenderer: {
sendMessage(channel: Channels, args: unknown[]) { sendMessage(channel: Channels, ...args: unknown[]) {
ipcRenderer.send(channel, args); ipcRenderer.send(channel, ...args);
}, },
on(channel: Channels, func: (...args: unknown[]) => void) { on(channel: Channels, func: (...args: unknown[]) => void) {
const subscription = (_event: IpcRendererEvent, ...args: unknown[]) => const subscription = (_event: IpcRendererEvent, ...args: unknown[]) =>
@ -19,3 +24,9 @@ contextBridge.exposeInMainWorld('electron', {
}, },
}, },
}); });
const postMessageOverride = `window.postMessage = function (data) {
window.electron.ipcRenderer.sendMessage('webview-message', JSON.stringify(data));
};`;
webFrame.executeJavaScript(postMessageOverride);

@ -2,6 +2,7 @@ import React from 'react';
import { Translate } from './translate'; import { Translate } from './translate';
interface WindowElectronDeviceInfo { interface WindowElectronDeviceInfo {
name: string;
version: string; version: string;
} }
@ -10,6 +11,9 @@ export const DeviceInfoPanel: React.FC = React.memo(() => {
(window as any).__electronDeviceInfo ?? {}; (window as any).__electronDeviceInfo ?? {};
return ( return (
<div> <div>
<div>
{Translate.clientName}: {deviceInfo.name}
</div>
<div> <div>
{Translate.clientVersion}: {deviceInfo.version} {Translate.clientVersion}: {deviceInfo.version}
</div> </div>

@ -5,6 +5,10 @@ export const Translate = {
'zh-CN': '设备信息', 'zh-CN': '设备信息',
'en-US': 'Device Info', 'en-US': 'Device Info',
}), }),
clientName: localTrans({
'zh-CN': '客户端名称',
'en-US': 'Client Name',
}),
clientVersion: localTrans({ clientVersion: localTrans({
'zh-CN': '客户端版本号', 'zh-CN': '客户端版本号',
'en-US': 'Client Version', 'en-US': 'Client Version',

Loading…
Cancel
Save