private void RequestNativeBrowser(int newBrowserId = 0) { if (browserId != 0 || browserIdRequested) { return; } browserIdRequested = true; try { BrowserNative.LoadNative(); } catch { base.gameObject.SetActive(value: false); throw; } int newId; if (newBrowserId == 0) { BrowserNative.ZFBSettings zFBSettings = default(BrowserNative.ZFBSettings); zFBSettings.bgR = backgroundColor.r; zFBSettings.bgG = backgroundColor.g; zFBSettings.bgB = backgroundColor.b; zFBSettings.bgA = backgroundColor.a; zFBSettings.offscreen = 1; BrowserNative.ZFBSettings settings = zFBSettings; newId = BrowserNative.zfb_createBrowser(settings); } else { newId = newBrowserId; } unsafeBrowserId = newId; lock (allThingsToRemember) { allThingsToRemember[newId] = thingsToRemember; } BrowserNative.ForwardJSCallFunc forwardJSCallFunc = delegate(int bId, int id, string data, int size) { lock (thingsToDo) { thingsToDo.Add(delegate { if (!registeredCallbacks.TryGetValue(id, out var value)) { Debug.LogWarning("Got a JS callback for event " + id + ", but no such event is registered."); } else { bool isError = false; if (data.StartsWith("fail-")) { isError = true; data = data.Substring(5); } JSONNode value2; try { value2 = JSONNode.Parse(data); } catch (SerializationException) { Debug.LogWarning("Invalid JSON sent from browser: " + data); return; } try { value(value2, isError); } catch (Exception exception) { Debug.LogException(exception); } } }); }
/** * Sets up a new native browser. * If newBrowserId is zero, allocates a new browser and sets it up. * If newBrowserId is nonzero, takes ownership of that allocated browser and sets it up. */ private void RequestNativeBrowser(int newBrowserId = 0) { if (browserId != 0 || browserIdRequested) { return; } browserIdRequested = true; try { BrowserNative.LoadNative(); } catch { gameObject.SetActive(false); throw; } int newId; if (newBrowserId == 0) { var settings = new BrowserNative.ZFBSettings() { bgR = backgroundColor.r, bgG = backgroundColor.g, bgB = backgroundColor.b, bgA = backgroundColor.a, offscreen = 1, }; newId = BrowserNative.zfb_createBrowser(settings); } else { newId = newBrowserId; } unsafeBrowserId = newId; //Debug.Log("Requested browser for " + name + " " + newId); //We have a native browser, but it is invalid to do anything with it until it's ready. //Therefore, we don't set browserId until it's ready. //But we will put all our callbacks in place. //Don't let our remember list get destroyed until we are ready for that. lock (allThingsToRemember) allThingsToRemember[newId] = thingsToRemember; BrowserNative.ForwardJSCallFunc forwardCall = (bId, id, data, size) => { lock (thingsToDo) thingsToDo.Add(() => { if (id < 0 || id >= registeredCallbacks.Count) { Debug.LogWarning("Got a JS callback for event " + id + ", but no such event is registered."); return; } try { var node = JSONNode.Parse(data); registeredCallbacks[id](node); } catch (SerializationException) { Debug.LogWarning("Invalid JSON sent from browser: " + data); } }); }; thingsToRemember.Add(forwardCall); BrowserNative.zfb_registerJSCallback(newId, forwardCall); BrowserNative.ChangeFunc changeCall = (id, type, arg1) => { //(Note: we may have been Object.Destroy'd at this point, so guard against that.) if (type == BrowserNative.ChangeType.CHT_BROWSER_CLOSE) { //We can't continue if the browser is closed, so goodbye. //At this point, we may or may not be destroyed, but if not, become destroyed. //Debug.Log("Got close notification for " + unsafeBrowserId); if (this) { //Need to be destroyed. lock (thingsToDo) thingsToDo.Add(() => { Destroy(gameObject); }); } else { //If we are (Unity) destroyed, we won't get another update, so we can't rely on thingsToDo //That said, there's not anything else for us to do but step out of allThingsToRemember. } //The native side has acknowledged it's done, now we can finally let the native trampolines be GC'd lock (allThingsToRemember) { allThingsToRemember.Remove(unsafeBrowserId); } //Just in case someone tries to call something, make sure CheckSanity and such fail. browserId = 0; } else if (this) { lock (thingsToDo) thingsToDo.Add(() => OnItemChange(type, arg1)); } }; thingsToRemember.Add(changeCall); BrowserNative.zfb_registerChangeCallback(newId, changeCall); BrowserNative.DisplayDialogFunc dialogCall = (id, type, text, promptText, url) => { lock (thingsToDo) thingsToDo.Add(() => { CreateDialogHandler(); dialogHandler.HandleDialog(type, text, promptText); }); }; thingsToRemember.Add(dialogCall); BrowserNative.zfb_registerDialogCallback(newId, dialogCall); BrowserNative.ShowContextMenuFunc contextCall = (id, json, x, y, origin) => { if (json != null && (allowContextMenuOn & origin) == 0) { //ignore this BrowserNative.zfb_sendContextMenuResults(browserId, -1); return; } lock (thingsToDo) thingsToDo.Add(() => { if (json != null) { CreateDialogHandler(); } if (dialogHandler != null) { dialogHandler.HandleContextMenu(json, x, y); } }); }; thingsToRemember.Add(contextCall); BrowserNative.zfb_registerContextMenuCallback(newId, contextCall); BrowserNative.NewWindowFunc popupCall = (int id, IntPtr urlPtr, bool userInvoked, int possibleId, ref BrowserNative.ZFBSettings possibleSettings) => { if (!userInvoked) { return(BrowserNative.NewWindowAction.NWA_IGNORE); } switch (newWindowAction) { default: case NewWindowAction.Ignore: return(BrowserNative.NewWindowAction.NWA_IGNORE); case NewWindowAction.Redirect: return(BrowserNative.NewWindowAction.NWA_REDIRECT); case NewWindowAction.NewBrowser: if (NewWindowHandler != null) { possibleSettings.bgR = backgroundColor.r; possibleSettings.bgG = backgroundColor.g; possibleSettings.bgB = backgroundColor.b; possibleSettings.bgA = backgroundColor.a; lock (thingsToDo) { thingsToDo.Add(() => { var newBrowser = NewWindowHandler.CreateBrowser(this); newBrowser.RequestNativeBrowser(possibleId); }); return(BrowserNative.NewWindowAction.NWA_NEW_BROWSER); } } else { Debug.LogError("Missing NewWindowHandler, can't open new window", this); return(BrowserNative.NewWindowAction.NWA_IGNORE); } case NewWindowAction.NewWindow: return(BrowserNative.NewWindowAction.NWA_NEW_WINDOW); } }; thingsToRemember.Add(popupCall); BrowserNative.zfb_registerPopupCallback(newId, popupCall); BrowserNative.ConsoleFunc consoleCall = (id, message, source, line) => { lock (thingsToDo) thingsToDo.Add(() => { onConsoleMessage(message, source + ":" + line); }); }; thingsToRemember.Add(consoleCall); BrowserNative.zfb_registerConsoleCallback(newId, consoleCall); BrowserNative.ReadyFunc readyCall = id => { Assert.AreEqual(newId, id); //We could be on any thread at this time, so schedule the callbacks to fire during the next InputUpdate lock (thingsToDo) thingsToDo.Add(() => { browserId = newId; // ReSharper disable once PossibleNullReferenceException onNativeReady(browserId); }); }; thingsToRemember.Add(readyCall); BrowserNative.zfb_setReadyCallback(newId, readyCall); }