// Copyright (c) 2025 Vuplex Inc. All rights reserved.
//
// Licensed under the Vuplex Commercial Software Library License, you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// https://vuplex.com/commercial-library-license
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Threading.Tasks;
using UnityEngine;
using Vuplex.WebView;
namespace Vuplex.Demos {
///
/// Sets up the AdvancedWebViewDemo scene, which displays web content in a main
/// world-space WebViewPrefab and renders a UI in a second webview to display the current URL
/// and provide back / forward navigation controls.
///
/// Note: The address bar currently only displays the current URL and is not an input.
/// I plan to add a dedicated browser prefab in the future that will include
/// a functional address bar. In the meantime, you can edit the CONTROLS_HTML field
/// below to implement a URL input.
///
///
/// This scene demonstrates the following:
/// - Programmatically instantiating WebViewPrefabs at runtime
/// - Programmatically instantiating an on-screen Keyboard prefab
/// - Using IWebView methods like LoadUrl(), LoadHtml(), GoBack(), and GoForward()
/// - Attaching handlers to the IWebView.UrlChanged and MessageEmitted events
/// - Sending messages from JavaScript to C# and vice versa
/// - Creating a transparent webview using the transparent meta tag
///
/// Links:
/// - WebViewPrefab docs: https://developer.vuplex.com/webview/WebViewPrefab
/// - Sending messages from JavaScript to C# and vice versa: https://support.vuplex.com/articles/how-to-send-messages-from-javascript-to-c-sharp
/// - How to make a transparent webview: https://support.vuplex.com/articles/how-to-make-a-webview-transparent
/// - How clicking works: https://support.vuplex.com/articles/clicking
/// - Other examples: https://developer.vuplex.com/webview/overview#examples
///
class AdvancedWebViewDemo : MonoBehaviour {
WebViewPrefab controlsWebViewPrefab;
WebViewPrefab mainWebViewPrefab;
async void Start() {
Debug.Log("[AdvancedWebViewDemo] Just a heads-up: this scene's address bar currently only displays the current URL and is not an input. For more info, please see the comments in AdvancedWebViewDemo.cs.");
// Use a desktop User-Agent to request the desktop versions of websites.
// https://developer.vuplex.com/webview/Web#SetUserAgent
Web.SetUserAgent(false);
// Instantiate a 0.6 x 0.3 webview for the main web content.
// https://developer.vuplex.com/webview/WebViewPrefab#Instantiate
mainWebViewPrefab = WebViewPrefab.Instantiate(0.6f, 0.3f);
mainWebViewPrefab.PixelDensity = 2;
mainWebViewPrefab.transform.parent = transform;
mainWebViewPrefab.transform.localPosition = new Vector3(0, -0.05f, 0.4f);
mainWebViewPrefab.transform.localEulerAngles = new Vector3(0, 180, 0);
// Instantiate a second webview above the first to show a UI that
// displays the current URL and provides back / forward navigation buttons.
controlsWebViewPrefab = WebViewPrefab.Instantiate(0.6f, 0.05f);
controlsWebViewPrefab.KeyboardEnabled = false;
controlsWebViewPrefab.transform.parent = mainWebViewPrefab.transform;
controlsWebViewPrefab.transform.localPosition = new Vector3(0, 0.06f, 0);
controlsWebViewPrefab.transform.localEulerAngles = Vector3.zero;
// Add an on-screen keyboard under the main webview.
// https://developer.vuplex.com/webview/Keyboard
var keyboard = Keyboard.Instantiate();
keyboard.transform.SetParent(mainWebViewPrefab.transform, false);
keyboard.transform.localPosition = new Vector3(0, -0.31f, 0);
keyboard.transform.localEulerAngles = Vector3.zero;
// Wait for the prefabs to initialize because the WebView property of each is null until then.
// https://developer.vuplex.com/webview/WebViewPrefab#WaitUntilInitialized
await Task.WhenAll(new Task[] {
mainWebViewPrefab.WaitUntilInitialized(),
controlsWebViewPrefab.WaitUntilInitialized()
});
// Now that the WebViewPrefabs are initialized, we can use the IWebView APIs via its WebView property.
// https://developer.vuplex.com/webview/IWebView
mainWebViewPrefab.WebView.UrlChanged += (sender, eventArgs) => {
_setDisplayedUrl(eventArgs.Url);
// Refresh the back / forward button state after 1 second.
Invoke("_refreshBackForwardState", 1);
};
mainWebViewPrefab.WebView.LoadUrl("https://www.google.com");
controlsWebViewPrefab.WebView.MessageEmitted += Controls_MessageEmitted;
controlsWebViewPrefab.WebView.LoadHtml(CONTROLS_HTML);
await controlsWebViewPrefab.WebView.WaitForNextPageLoadToFinish();
_setDisplayedUrl(mainWebViewPrefab.WebView.Url);
// Android Gecko and UWP w/ XR enabled don't support transparent webviews, so as a workaround,
// configure the shader to turn black pixels transparent.
var pluginType = controlsWebViewPrefab.WebView.PluginType;
if (pluginType == WebPluginType.AndroidGecko || pluginType == WebPluginType.UniversalWindowsPlatform) {
controlsWebViewPrefab.SetRenderBlackAsTransparent(true);
}
}
async void _refreshBackForwardState() {
// Get the main webview's back / forward state and then post a message
// to the controls UI to update its buttons' state.
var canGoBack = await mainWebViewPrefab.WebView.CanGoBack();
var canGoForward = await mainWebViewPrefab.WebView.CanGoForward();
var serializedMessage = $"{{ \"type\": \"SET_BUTTONS\", \"canGoBack\": {canGoBack.ToString().ToLowerInvariant()}, \"canGoForward\": {canGoForward.ToString().ToLowerInvariant()} }}";
controlsWebViewPrefab.WebView.PostMessage(serializedMessage);
}
void Controls_MessageEmitted(object sender, EventArgs eventArgs) {
var message = eventArgs.Value;
if (message == "GO_BACK") {
mainWebViewPrefab.WebView.GoBack();
} else if (message == "GO_FORWARD") {
mainWebViewPrefab.WebView.GoForward();
}
}
void _setDisplayedUrl(string url) {
if (controlsWebViewPrefab.WebView != null) {
var serializedMessage = $"{{ \"type\": \"SET_URL\", \"url\": \"{url}\" }}";
controlsWebViewPrefab.WebView.PostMessage(serializedMessage);
}
}
const string CONTROLS_HTML = @"
";
}
}