electron-bridge
github鏈接 求star
Motivition如果想一套代碼同時能跑在web環(huán)境和electron環(huán)境中,就需要在代碼中先判斷環(huán)境,再分別寫對應(yīng)的邏輯。每次寫到electron環(huán)境下的邏輯,又要區(qū)分渲染進(jìn)程和主進(jìn)程,因為有些事只能渲染進(jìn)程做,有些事只能主進(jìn)程做。所以,我希望能將這些抽象出來,某個方法,只能在electron環(huán)境下被調(diào)用,并且不需要關(guān)心在什么進(jìn)程下,web只要判斷環(huán)境,調(diào)不同的方法就行,不需要關(guān)心和electron的交互。
如果,我需要快速的開啟另一個electron的項目,我希望我web里的代碼能輕易的獲取到electron的能力,而不是重新開始編寫,這個時候,我希望有一層對electron能力的封裝。
團(tuán)隊內(nèi)有些成員對web很熟悉,但是對electron不是很了解,如果加入項目,就需要去學(xué)習(xí)electron的知識,這個時候,如果能有一個庫列出了所有electron能做的事,你只需要調(diào)用,無需關(guān)心它是怎么實現(xiàn)的,能很大程度提高開發(fā)效率。
Goals給web注入適當(dāng)?shù)沫h(huán)境變量,讓web知道自己的環(huán)境
給web注入一個對象,包含所有electron能做的事(包括主進(jìn)程、渲染進(jìn)程)
How to do在load web頁面的時候,有個webPreferences配置,我們在這里預(yù)加載一個js文件,就是electron-bridge.js
這個文件擁有node的能力,并且它是屬于渲染進(jìn)程的,所以它能做渲染進(jìn)程里的事, 也能跟主進(jìn)程通訊。
st=>start: start op0=>operation: index.js去調(diào)用bridge.js暴露出來的方法, ElectronBridge.setFullScreen() op1=>operation: bridge.js通過ipcRender告訴ipacMain做什么,并把回調(diào)暫存起來 op2=>operation: 主進(jìn)程做完告訴bridge.js做完了,發(fā)送數(shù)據(jù) op4=>operation: bridge.js帶上收到的數(shù)據(jù),執(zhí)行暫存的回調(diào) op3=>operation: bridge.js直接做完,觸發(fā)回調(diào) cond=>condition: bridge.js判斷是不是主進(jìn)程做的事? e=>end: end st->op0->cond cond(yes)->op1->op2->op4->e cond(no)->op3->eLet"s do it 給web注入適當(dāng)?shù)沫h(huán)境變量
加載bridge.js
win = new BrowserWindow({ width: 800, height: 600, show: false, webPreferences: { preload: path.join(__dirname, "../bridge/bridge.js"), plugins: true } });
當(dāng)我們啟動electron的時候,主進(jìn)程開始通知這個渲染進(jìn)程,給渲染進(jìn)程注入主進(jìn)程的環(huán)境變量,再有渲染進(jìn)程掛載到window對象上,這樣web就能獲取自己的環(huán)境信息
//bridge.js const {ipcRenderer} = require("electron"); //監(jiān)聽主進(jìn)程,設(shè)置環(huán)境變量 ipcRenderer.on("set-env", (event, msg) => { for (const key in msg) { window[key] = msg[key]; } });
//main.js const {BrowserWindow, ipcMain} = require("electron"); const win = new BrowserWindow({...}); //獲取創(chuàng)建好的window對象發(fā)送消息 win.webContents.on("did-finish-load", function() { win.webContents.send("set-env", { //設(shè)置web環(huán)境變量 __ELECTRON__: true, __DEV__: true, __PRO__: false, __SERVER__: false, windowLoaded: true }); });通過bridge.js 來調(diào)用主進(jìn)程的方法
我們通過ipcRender給主進(jìn)程發(fā)送一系列消息,包括做什么事情(eventName), 根據(jù)哪些參數(shù)(params),對外根據(jù)不同的事件暴露不同的方法,接受參數(shù),和回調(diào)函數(shù)。
先將回調(diào)函數(shù)放在 eventsMap上暫存起來,因為ipcRender不能發(fā)送函數(shù),所有的信息會被序列化后再發(fā)送給主進(jìn)程,所以,我們先生成一個時間戳,讓 eventsMap[時間戳] = cb 并把時間戳一同發(fā)送過去,等一會兒,主進(jìn)程通知渲染進(jìn)程調(diào)用哪個時間戳函數(shù)
通過"resist-event"頻道, 發(fā)送參數(shù),包括 eventName、params、timeStamp
//bridge.js const {ipcRenderer} = require("electron"); const eventsMap = {}; //調(diào)用原生事件 function registEvent(eventName, params, cb) { //允許只傳兩個數(shù)據(jù) if (!cb) { cb = params; params = {}; } //如果win還未ready if (!windowLoaded) { cb(new Error("window not ready")); return; } const stamp = String(new Date().getTime()); const opts = Object.assign({eventName}, params, {stamp}); eventsMap[stamp] = cb; //注冊唯一函數(shù) ipcRenderer.send("regist-event", opts); //發(fā)送事件 } //進(jìn)入全屏 function setFullScreen(cb) { registEvent(SET_FULL_SCREEN, cb); } window.ElectronBridge = { setFullScreen };
主進(jìn)程監(jiān)聽‘resist-event’頻道,做對應(yīng)的事。我們會將所有主進(jìn)程能做的事,放在eventsList對象下,當(dāng)接受到渲染進(jìn)程的通知,去eventsList找有沒有對應(yīng)的事能做,有,做完通過promise,或者通過回調(diào)函數(shù),去在‘fire-event’頻道通知,渲染進(jìn)程,事情已經(jīng)做完,并把數(shù)據(jù)傳回去,包括 stamp(之前渲染進(jìn)程傳過來的,現(xiàn)在傳回去,告訴渲染進(jìn)程執(zhí)行哪個回調(diào)函數(shù)) 、 payload(返回數(shù)據(jù)) 、err (錯誤信息)
//main.js const {ipcMain} = require("electron"); //監(jiān)聽對原生的調(diào)用 ipcMain.on("regist-event", (event, arg) => { const nativeEvent = eventsList[arg.eventName]; if (nativeEvent) { const result = nativeEvent(app, win, arg.params); if (isPromise(result)) { result.then(res => { event.sender.send("fire-event", { stamp: arg.stamp, payload: res }); }).catch(err => { event.sender.send("fire-event", { stamp: arg.stamp, err }); }); } else { event.sender.send("fire-event", { stamp: arg.stamp, payload: result }); } } else { event.sender.send("fire-event", { stamp: arg.stamp, err: new Error("event not support") }); } });
渲染進(jìn)程監(jiān)聽‘fire-event’執(zhí)行對應(yīng)時間戳回調(diào)函數(shù),并把主進(jìn)程傳過來的數(shù)據(jù)傳給回調(diào)函數(shù)。觸發(fā)完成后,刪掉該回調(diào)函數(shù)。
//bridge.js //觸發(fā)事件回調(diào) ipcRenderer.on("fire-event", (event, arg) => { const cb = eventsMap[arg.stamp]; if (cb) { if (arg.err) { cb(arg.err, arg.payload); } else { cb(false, arg.payload); } delete eventsMap[arg.stamp]; } });
如果是渲染進(jìn)程能做的事,就不需要再和主進(jìn)程通訊,可以直接完成觸發(fā)回調(diào)
//bridge.js const {webFrame} = require("electron"); //設(shè)置縮放比,只能在渲染進(jìn)程中實現(xiàn) function setZoomFactor(params, cb) { webFrame.setZoomFactor(params); cb && cb(); } window.ElectronBridge = { setZoomFactor };
最終web中的js代碼去調(diào)用bridge.js暴露出來的方法
// ../web/index.js $btn1.addEventListener("click", function() { if (__ELECTRON__ && ElectronBridge) { //electron 環(huán)境 ElectronBridge.setFullScreen((err) => { if (err) return; console.log("done"); }); } else { //web 環(huán)境 alert("不能設(shè)置全屏") //do something else } });
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/83226.html
摘要:要構(gòu)建自適應(yīng)實例,先要有自適應(yīng)的實現(xiàn)類,實現(xiàn)類有兩種方式一種通過配置文件,一種是通過是字節(jié)碼的方式動態(tài)生成。 SPI機(jī)制 SPI,即(service provider interface)機(jī)制,有很多組件的實現(xiàn),如日志、數(shù)據(jù)庫訪問等都是采用這樣的方式,一般通用組件為了提升可擴(kuò)展性,基于接口編程,將操作接口形成標(biāo)準(zhǔn)規(guī)范,但是可以開放多種擴(kuò)展實現(xiàn),這種做法也符合開閉設(shè)計原則,使組件具有可插...
摘要:練習(xí)項目備選清單文件下載器功能概要設(shè)計實現(xiàn)新建下載功能以為基礎(chǔ)給出下載鏈接可以啟動下載任務(wù)實現(xiàn)局域網(wǎng)內(nèi)下載傳輸文件以單線程下載方式實現(xiàn)附加功能支持?jǐn)帱c(diǎn)續(xù)傳實現(xiàn)多線程下載實現(xiàn)下載參考技術(shù)套接字編程多線程編程音視頻播放器功能概要設(shè)計實現(xiàn)播放常見 練習(xí)項目備選清單 Utilities 1. 文件下載器 功能概要設(shè)計: 實現(xiàn)新建下載功能(以ftp為基礎(chǔ)) 給出下載鏈接可以啟動下載任務(wù) 實現(xiàn)局...
摘要:練習(xí)項目備選清單文件下載器功能概要設(shè)計實現(xiàn)新建下載功能以為基礎(chǔ)給出下載鏈接可以啟動下載任務(wù)實現(xiàn)局域網(wǎng)內(nèi)下載傳輸文件以單線程下載方式實現(xiàn)附加功能支持?jǐn)帱c(diǎn)續(xù)傳實現(xiàn)多線程下載實現(xiàn)下載參考技術(shù)套接字編程多線程編程音視頻播放器功能概要設(shè)計實現(xiàn)播放常見 練習(xí)項目備選清單 Utilities 1. 文件下載器 功能概要設(shè)計: 實現(xiàn)新建下載功能(以ftp為基礎(chǔ)) 給出下載鏈接可以啟動下載任務(wù) 實現(xiàn)局...
摘要:如何實現(xiàn)前端路由要實現(xiàn)前端路由,需要解決兩個核心如何改變卻不引起頁面刷新如何檢測變化了下面分別使用和兩種實現(xiàn)方式回答上面的兩個核心問題。 原文鏈接:github.com/whinc/blog/… 在單頁應(yīng)用如此流行的今天,曾經(jīng)令人驚嘆的前端路由已經(jīng)成為各大框架的基礎(chǔ)標(biāo)配,每個框架都提供了強(qiáng)大的路由功能,導(dǎo)致路由實現(xiàn)變的復(fù)雜。想要搞懂路由內(nèi)部實現(xiàn)還是有些困難的,但是如果只想了解路由實現(xiàn)基本...
閱讀 3318·2023-04-25 19:42
閱讀 1336·2021-11-23 10:11
閱讀 2274·2021-11-16 11:51
閱讀 1598·2019-08-30 15:54
閱讀 2043·2019-08-29 18:44
閱讀 1624·2019-08-23 18:24
閱讀 497·2019-08-23 17:52
閱讀 1772·2019-08-23 15:33