描述
energy默认是多进程模式,当然也可以设置为单进程,但不建议这样做,因为会产生不可预料的问题
多进程带来的不便,energy应用启动后,在同一执行文件会被多次执行,启动多个子进程(也称之为helper进程)它们一搬没有业务功能。
如果我们定义了func init()
函数,或在main函数直接调用其它函数,会导致这些函数在每个进程都被执行一次。
解决方式:
有两种方法
- energy默认提供了
cef.BrowserWindow.SetBrowserInit
回调函数,此函数内是在主进程执行,其原理是在主进程启动app之后创建主窗口时执行且只执行一次,
也可以使用 process.Args.IsMain()
返回bool, 判断当前进程类型来控制执行哪些函数
但无法控制func init()
函数
- 独立子进程执行文件, 此方法需要一个单独的执行文件做为子进程(helper进程),需要预先编译出执行文件,并将其所在目录配置到主进程的
app.SetBrowserSubprocessPath(subProcessExePath)
, 主进程启动后,子进程则使用该执行文件。
注意的是:
- 主进程和子进程的
cef.NewApplication()
一搬配置是一样的。
- 无轮哪种方式,window, chromium对象,窗口组件创建都只能在
cef.BrowserWindow.SetBrowserInit
回调函数内获得, 因为SetBrowserInit是在energy封装的主窗口创建事件内调用的。
两种方式的区别:
第一种,如果默认执行的函数只在主进程中执行,自己控制它们的执行时机。
第二种,相比第一种多出一个执行文件,但不需要控制默认执行函数的执行时机。如果应用项目较复杂,是比较推荐的做法。
Go示例代码 helper-process
主子进程 app/application.go
package app
import "github.com/energye/energy/v2/cef"
var application *cef.TCEFApplication
// GetApplication
//
// 创建 Application 对象,保持主进程和helper进程配置一样
func GetApplication() *cef.TCEFApplication {
if application == nil {
application = cef.NewApplication()
//.. 在这里统一配置
}
return application
}
主进程 main.go
package main
import (
"embed"
"fmt"
"github.com/energye/energy/v2/cef"
"github.com/energye/energy/v2/common"
"github.com/energye/energy/v2/consts"
"github.com/energye/energy/v2/examples/helper-process/app"
"github.com/energye/energy/v2/pkgs/assetserve"
"github.com/energye/golcl/lcl"
"github.com/energye/golcl/pkgs/macapp"
"path/filepath"
)
//go:embed resources
var resources embed.FS
/*
主进程
这个示例演示了 主进程和 子进程相互独立出来,
步骤
1. 先编译好子进程程序
helper
go build
2. 将helper子进程执行文件(helper)在主进程SetBrowseSubprocessPath配置,如果在 CEF框架目录 可直接写文件名
3. 运行主程序
*/
func main() {
//MacOS通过指定 IsCEF ,在开发环境中自动生成可运行的程序包
//MacOS配置要在调用 GlobalInit 它之前设置
//特别说明MacOS:子进程不需要配置 SetBrowseSubprocessPath 来生成 Mac App特定的helper进程
wd := consts.CurrentExecuteDir
if common.IsDarwin() {
// 主进程中 主子进程方式,在这里指定子进程的执行文件
subExePath := filepath.Join(wd, "examples", "helper-process", "helper", "helper")
macapp.MacApp.SetBrowseSubprocessPath(subExePath)
}
//CEF全局初始化
cef.GlobalInit(nil, resources)
// 使用 SetBrowserSubprocessPath 设置子进程执行文件目录
var subName = subExeName()
// 子进程执行文件完整目录
var subExePath = filepath.Join(wd, "helper", subName)
println("subExePath", subExePath)
// 设置子进程执行文件目录
// 子进程执行文件如果在同一目录并且在CEF框架目录可只写文件名
app.GetApplication().SetBrowserSubprocessPath(subExePath)
//主进程初始化
mainBrowserInit()
//启动内置http服务
startHttpServer()
cef.Run(app.GetApplication())
}
func subExeName() (name string) {
if common.IsWindows() {
name = "helper.exe"
} else if common.IsLinux() {
name = "helper"
} else if common.IsDarwin() {
//MacOS SetBrowseSubprocessPath 不起任何作用。
//MacOS 独立的子程序包需要在 macapp.MacApp.SetBrowseSubprocessPath 配置
}
return
}
// 启动内置http服务
func startHttpServer() {
fmt.Println("主进程启动 创建一个内置http服务")
//通过内置http服务加载资源
server := assetserve.NewAssetsHttpServer()
server.PORT = 22022
server.AssetsFSName = "resources" //必须设置目录名
server.Assets = resources
go server.StartHttpServer()
}
// 主进程浏览器初始化
func mainBrowserInit() {
//指定一个URL地址,或本地html文件目录
cef.BrowserWindow.Config.Url = "http://localhost:22022/index.html"
cef.BrowserWindow.Config.Title = "ENERGY 区分主/子进程执行文件"
//主窗口初始化回调函数
//在这个函数里,主进程浏览初始化之前创建窗口之后
//在这里可以设置窗口的属性和事件监听
//SetOnBeforePopup是子进程弹出窗口时触发,可以改变子进程窗口属性
cef.BrowserWindow.SetBrowserInit(func(event *cef.BrowserEvent, window cef.IBrowserWindow) {
fmt.Println("主窗口初始化回调函数")
window.SetCenterWindow(true)
event.SetOnBeforePopup(func(sender lcl.IObject, popupWindow cef.IBrowserWindow, browser *cef.ICefBrowser, frame *cef.ICefFrame, beforePopupInfo *cef.BeforePopupInfo, popupFeatures *cef.TCefPopupFeatures, windowInfo *cef.TCefWindowInfo, resultClient *cef.ICefClient, settings *cef.TCefBrowserSettings, resultExtraInfo *cef.ICefDictionaryValue, noJavascriptAccess *bool) bool {
fmt.Println("OnBeforePopup: " + beforePopupInfo.TargetUrl)
popupWindow.SetTitle("改变了标题 - " + beforePopupInfo.TargetUrl)
return false
})
})
}
子进程 helper/helper_process.go
package main
import (
"fmt"
"github.com/energye/energy/v2/cef"
"github.com/energye/energy/v2/cef/ipc"
"github.com/energye/energy/v2/cef/ipc/context"
"github.com/energye/energy/v2/cef/process"
"github.com/energye/energy/v2/examples/helper-process/app"
)
/*
helper 子进程
子进程需要先编译好得到执行文件, 提供给主进程(SetBrowseSubprocessPath)配置
*/
func main() {
//全局配置初始化
cef.GlobalInit(nil, nil)
//创建Cef应用
application := app.GetApplication()
// 渲染进程监听IPC事件
helperLisIPC()
//启动子进程
application.StartSubProcess()
application.Free()
}
// 渲染进程监听IPC事件
func helperLisIPC() {
fmt.Println("渲染进程IPC事件注册 ProcessType:", process.Args.ProcessType())
//渲染进程监听的事件
ipc.On("sub-process-on-event", func(context context.IContext) {
fmt.Println("sub-process-on-event")
//渲染进程处理程序....
context.Result("返回结果")
})
}