lvsti / CEF.swift

Swift bindings for the Chromium Embedded Framework
BSD 3-Clause "New" or "Revised" License
94 stars 29 forks source link

CEFRenderProcessHandler.onContextCreated not called when using multi-process mode #30

Closed WarWithinMe closed 6 years ago

WarWithinMe commented 6 years ago

In my app, I wrote something like this:

class CustomCEFApp: CEFApp, CEFRenderProcessHandler {
  var renderProcessHandler: CEFRenderProcessHandler? { return self }
  func onContextCreated(browser: CEFBrowser, frame: CEFFrame, context: CEFV8Context) {
     print("ContextCreated")
  }
}

var settings = CEFSettings()
settings.useSingleProcess = true

_ = CEFProcessUtils.initializeMain(
  with: CEFMainArgs(arguments: CommandLine.arguments),
  settings: settings,
  app: CustomCEFApp()
)

ContextCreated will be printed. However, if I set useSingleProcess to false, ContextCreated will not be printed.

I guess I might need to implement some logic in the helper app, but I'm not sure how. Please shed some light on how to use multi-process mode. Many thanks~

lvsti commented 6 years ago

You should implement CEFRenderProcessHandler in the helper app.

WarWithinMe commented 6 years ago

@lvsti Should I also call CEFProcessUtils.initializeMain in the helper app? Not sure how to tell CEF that I would provide the CEFRednerProcessHandler

lvsti commented 6 years ago

right, the demo app's helper is just a dummy... I might add a more useful helper app in the future, until then take a look at this example:

class App: CEFApp, CEFRenderProcessHandler {
    var renderProcessHandler: CEFRenderProcessHandler? {
        return self
    }

    func onContextCreated(browser: CEFBrowser, frame: CEFFrame, context: CEFV8Context) {
        context.enter()
        let v8Str = CEFV8Value.createString("Hello World!")
        NSLog("\(v8Str?.stringValue)")

        context.exit()
    }
}

let mainArgs = CEFMainArgs(arguments: CommandLine.arguments)
let commandLine = CEFCommandLine()!
commandLine.initFromArguments(CommandLine.arguments)

let retval: Int
if commandLine.switchValue(for: "type") == "renderer" {
    retval = CEFProcessUtils.executeProcess(with: mainArgs, app: App())
}
else {
    retval = CEFProcessUtils.executeProcess(with: mainArgs)
}

exit(Int32(retval))
lvsti commented 6 years ago

Pro tip: debugging the helper app is not trivial since it runs in a separate process. In order to attach Xcode to the running render process, place the following line somewhere in the helper:

raise(SIGSTOP)

This will make the process hang and wait at that point until the debugger is attached. After that, you can use breakpoints as usual.

WarWithinMe commented 6 years ago

Thank you for the information

WarWithinMe commented 6 years ago

To use multi-process mode, if I want to implement logics (for example, js bindings) in main process, then I will need to use IPC to communicate with the render process. Or maybe I just move all the logics to render process, and only leave window management logics in the main process?

It seems that it will take a lot of effort to use multi-process mode.

lvsti commented 6 years ago

It is indeed a lot of effort but so far neither I have found another way. Moving the logic over to the render process probably won't solve all your problems because that process is sandboxed, meaning it cannot access the filesystem, network etc.

WarWithinMe commented 6 years ago

Checked CefSharp, it sends message from the RenderProcess to MainProcess, to allow handling JS binding on the MainProcess. I'll try porting CefSharp's Subprocess logics to CEF.swift when I have time.