123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- // Copyright (c) 2024 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.
- #if UNITY_WEBGL && !UNITY_EDITOR
- using System;
- using System.Collections.Generic;
- using System.Runtime.InteropServices;
- using System.Threading.Tasks;
- using UnityEngine;
- using Vuplex.WebView.Internal;
- namespace Vuplex.WebView {
- /// <summary>
- /// WebGLWebView is the IWebView implementation used by 2D WebView for WebGL.
- /// It also includes additional APIs for WebGL-specific functionality.
- /// </summary>
- public class WebGLWebView : BaseWebView,
- IWebView,
- IWithNative2DMode {
- /// <summary>
- /// Gets the unique `id` attribute of the webview's <iframe> element.
- /// </summary>
- /// <example>
- /// <code>
- /// await canvasWebViewPrefab.WaitUntilInitialized();
- /// #if UNITY_WEBGL && !UNITY_EDITOR
- /// var webGLWebView = canvasWebViewPrefab.WebView as WebGLWebView;
- /// Debug.Log("IFrame ID: " + webGLWebView.IFrameElementID);
- /// #endif
- /// </code>
- /// </example>
- public string IFrameElementID { get; private set; }
- /// <see cref="IWithNative2DMode"/>
- public bool Native2DModeEnabled { get => _native2DModeEnabled; }
- public WebPluginType PluginType { get; } = WebPluginType.WebGL;
- /// <see cref="IWithNative2DMode"/>
- public Rect Rect { get => _rect; }
- /// <see cref="IWithNative2DMode"/>
- public bool Visible { get => _visible; }
- /// <seealso cref="IWithNative2DMode"/>
- public void BringToFront() {
- _assertValidState();
- _assertNative2DModeEnabled();
- WebView_bringToFront(_nativeWebViewPtr);
- }
- /// <summary>
- /// Indicates whether 2D WebView can access the content in the
- /// webview's iframe. If the iframe's content can't be accessed,
- /// then most of the IWebView APIs become disabled. For more
- /// information, please see [this article](https://support.vuplex.com/articles/webgl-limitations#cross-origin-limitation).
- /// </summary>
- /// <example>
- /// <code>
- /// await canvasWebViewPrefab.WaitUntilInitialized();
- /// #if UNITY_WEBGL && !UNITY_EDITOR
- /// var webGLWebView = canvasWebViewPrefab.WebView as WebGLWebView;
- /// if (webGLWebView.CanAccessIFrameContent()) {
- /// Debug.Log("The iframe content can be accessed 👍");
- /// }
- /// #endif
- /// </code>
- /// </example>
- public bool CanAccessIFrameContent() {
- _assertValidState();
- return WebView_canAccessIFrameContent(_nativeWebViewPtr);
- }
- public override Task<bool> CanGoBack() => _canGoBackOrForward("CanGoBack");
- public override Task<bool> CanGoForward() => _canGoBackOrForward("CanGoForward");
- public override Task<byte[]> CaptureScreenshot() {
- WebGLWarnings.LogCaptureScreenshotError();
- return Task.FromResult(new byte[0]);
- }
- public override void Click(int xInPixels, int yInPixels, bool preventStealingFocus = false) {
- if (_verifyIFrameCanBeAccessed("Click")) {
- base.Click(xInPixels, yInPixels, preventStealingFocus);
- }
- }
- public override void Copy() => WebGLWarnings.LogCopyError();
- public override void Cut() => WebGLWarnings.LogCutError();
- public override void ExecuteJavaScript(string javaScript, Action<string> callback) {
- _assertValidState();
- if (_verifyIFrameCanBeAccessed("ExecuteJavaScript")) {
- var result = WebView_executeJavaScriptSync(_nativeWebViewPtr, javaScript);
- callback?.Invoke(result);
- }
- }
- /// <summary>
- /// Executes the given JavaScript locally in the Unity app's window and returns the result.
- /// </summary>
- /// <example>
- /// <code>
- /// #if UNITY_WEBGL && !UNITY_EDITOR
- /// // Gets the Unity app's web page title.
- /// var title = WebGLWebView.ExecuteJavaScriptLocally("document.title");
- /// Debug.Log("Title: " + title);
- /// #endif
- /// </code>
- /// </example>
- public static string ExecuteJavaScriptLocally(string javaScript) => WebView_executeJavaScriptLocally(javaScript);
- /// <summary>
- /// Focuses the Unity game view, which enables Unity to detect keyboard input. When a webview
- /// is focused, Unity is unable to detect keyboard input (i.e. its APIs like Input.GetKey() don't work).
- /// To re-enable Unity's ability to detect keyboard input, the application can use this method to programmatically
- /// shift focus from the webview to the Unity game view.
- /// For more details, see <see href="https://support.vuplex.com/articles/webgl-limitations#input-focus">this article</see>.
- /// </summary>
- /// <example>
- /// <code>
- /// #if UNITY_WEBGL && !UNITY_EDITOR
- /// WebGLWebView.FocusUnity();
- /// #endif
- /// </code>
- /// </example>
- public static void FocusUnity() => WebView_focusUnity();
- public override Task<byte[]> GetRawTextureData() {
- WebGLWarnings.LogGetRawTextureDataError();
- return Task.FromResult(new byte[0]);
- }
- public override void GoBack() {
- if (_verifyIFrameCanBeAccessed("GoBack")) {
- base.GoBack();
- }
- }
- public override void GoForward() {
- if (_verifyIFrameCanBeAccessed("GoForward")) {
- base.GoForward();
- }
- }
- public Task Init(int width, int height) {
- var message = "2D WebView for WebGL only supports 2D, so Native 2D Mode must be enabled." + WebGLWarnings.GetArticleLinkText(false);
- WebViewLogger.LogError(message);
- throw new NotImplementedException(message);
- }
- /// <see cref="IWithNative2DMode"/>
- public async Task InitInNative2DMode(Rect rect) {
- await _initInNative2DModeBase(rect);
- // Set IFrameElementID *after* base.Init() because it sets gameObject.name.
- IFrameElementID = gameObject.name;
- // Prior to Unity 2019.3, Unity's UI used a pixel density of
- // 1 instead of using window.devicePixelRatio.
- #if UNITY_2019_3_OR_NEWER
- var ignoreDevicePixelRatio = false;
- #else
- var ignoreDevicePixelRatio = true;
- #endif
- _nativeWebViewPtr = WebView_newInNative2DMode(
- gameObject.name,
- (int)rect.x,
- (int)rect.y,
- (int)rect.width,
- (int)rect.height,
- ignoreDevicePixelRatio
- );
- if (_nativeWebViewPtr == IntPtr.Zero) {
- throw new TrialExpiredException("Your trial of 2D WebView for WebGL has expired. Please purchase a license to continue using it.");
- }
- }
- public static WebGLWebView Instantiate() => new GameObject().AddComponent<WebGLWebView>();
- public override void LoadHtml(string html) {
- WebGLWarnings.LogLoadHtmlWarning();
- base.LoadHtml(html);
- }
- public override void LoadUrl(string url, Dictionary<string, string> additionalHttpHeaders) {
- WebViewLogger.LogWarning("LoadUrl(url, headers) was called, but 2D WebView for WebGL is unable to send additional headers when loading a URL due to browser limitations. So, the URL will be loaded without additional headers using LoadUrl(url) instead.");
- LoadUrl(url);
- }
- public override void Paste() => WebGLWarnings.LogPasteError();
- public override void PostMessage(string message) {
- _assertValidState();
- WebView_postMessage(_nativeWebViewPtr, message);
- }
- public override void Scroll(int scrollDeltaXInPixels, int scrollDeltaYInPixels) {
- if (_verifyIFrameCanBeAccessed("Scroll")) {
- base.Scroll(scrollDeltaXInPixels, scrollDeltaYInPixels);
- }
- }
- public override void Scroll(Vector2 normalizedScrollDelta, Vector2 normalizedPoint) {
- if (_verifyIFrameCanBeAccessed("Scroll")) {
- base.Scroll(normalizedScrollDelta, normalizedPoint);
- }
- }
- public override void SendKey(string key) {
- if (_verifyIFrameCanBeAccessed("SendKey")) {
- base.SendKey(key);
- }
- }
- /// <summary>
- /// Overrides the value of `devicePixelRatio` that 2D WebView uses to determine the correct
- /// size and coordinates of webviews.
- /// </summary>
- /// <summary>
- /// Starting in Unity 2019.3, Unity scales the UI by default based on the browser's window.devicePixelRatio
- /// value. However, it's possible for an application to override the `devicePixelRatio` value
- /// by passing a value for `config.devicePixelRatio` to Unity's `createUnityInstance()` JavaScript function. In some
- /// versions of Unity, the default index.html template sets `config.devicePixelRatio = 1` on mobile.
- /// In order for 2D WebView to size and position webviews correctly, it must determine the value of `devicePixelRatio`
- /// to use. Since there's no API to get a reference to the Unity instance that the application created with `createUnityInstance()`,
- /// 2D WebView tries to detect if `config.devicePixelRatio` was passed to `createUnityInstance()` by checking for the presence of a
- /// global `config` JavaScript variable. If there is a global variable named `config` with a `devicePixelRatio` property, then 2D WebView
- /// uses that value, otherwise it defaults to using `window.devicePixelRatio`. This approach works for Unity's default
- /// index.html templates, but it may not work if the application uses a custom HTML template or changes the name of the `config`
- /// variable in the default template. In those cases, the application can use this method to pass the overridden value of `devicePixelRatio` to
- /// 2D WebView.
- /// </summary>
- /// <example>
- /// <code>
- /// void Awake() {
- /// #if UNITY_WEBGL && !UNITY_EDITOR
- /// WebGLWebView.SetDevicePixelRatio(1);
- /// #endif
- /// }
- /// </code>
- /// </example>
- public static void SetDevicePixelRatio(float devicePixelRatio) {
- #if UNITY_2019_3_OR_NEWER
- WebView_setDevicePixelRatio(devicePixelRatio);
- #else
- WebViewLogger.LogWarning("The call to WebGLWebView.SetDevicePixelRatio() will be ignored because a version of Unity older than 2019.3 is being used, which always uses a devicePixelRatio of 1.");
- #endif
- }
- /// <summary>
- /// Sets whether the JavaScript Fullscreen API is enabled for webviews. The default is `false`.
- /// </summary>
- /// <example>
- /// <code>
- /// void Awake() {
- /// #if UNITY_WEBGL && !UNITY_EDITOR
- /// WebGLWebView.SetFullscreenEnabled(true);
- /// #endif
- /// }
- /// </code>
- /// </example>
- public static void SetFullscreenEnabled(bool enabled) => WebView_setFullscreenEnabled(enabled);
- /// <summary>
- /// Sets whether the JavaScript Geolocation API is enabled for webviews. The default is `false`.
- /// </summary>
- /// <example>
- /// <code>
- /// void Awake() {
- /// #if UNITY_WEBGL && !UNITY_EDITOR
- /// WebGLWebView.SetGeolocationEnabled(true);
- /// #endif
- /// }
- /// </code>
- /// </example>
- public static void SetGeolocationEnabled(bool enabled) => WebView_setGeolocationEnabled(enabled);
- public void SetNativeZoomEnabled(bool enabled) {
- WebViewLogger.LogWarning("2D WebView for WebGL doesn't support native zooming, so the call to IWithNative2DMode.SetNativeZoomEnabled() will be ignored.");
- }
- /// <see cref="IWithNative2DMode"/>
- public void SetRect(Rect rect) {
- _assertValidState();
- _assertNative2DModeEnabled();
- _rect = rect;
- WebView_setRect(_nativeWebViewPtr, (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
- }
- /// <summary>
- /// Explicitly sets the HTML element that 2D WebView should use as the Unity app container.
- /// 2D WebView automatically detects the Unity app container element if its ID is set to one of the default values of
- /// "unityContainer" or "unity-container". However, if your app uses a custom WebGL template that
- /// uses a different ID for the container element, you must call this method to set the container element ID.
- /// 2D WebView for WebGL works by adding <iframe> elements to the app container, so it's unable to function correctly
- /// if it's unable to find the Unity app container element.
- /// </summary>
- /// <example>
- /// <code>
- /// void Awake() {
- /// #if UNITY_WEBGL && !UNITY_EDITOR
- /// WebGLWebView.SetUnityContainerElementId("your-custom-id");
- /// #endif
- /// }
- /// </code>
- /// </example>
- public static void SetUnityContainerElementId(string containerId) => WebView_setUnityContainerElementId(containerId);
- /// <summary>
- /// Sets whether screen sharing is enabled for webviews. The default is `false`.
- /// </summary>
- /// <example>
- /// <code>
- /// void Awake() {
- /// #if UNITY_WEBGL && !UNITY_EDITOR
- /// WebGLWebView.SetScreenSharingEnabled(true);
- /// #endif
- /// }
- /// </code>
- /// </example>
- public static void SetScreenSharingEnabled(bool enabled) => WebView_setScreenSharingEnabled(enabled);
- /// <see cref="IWithNative2DMode"/>
- public void SetVisible(bool visible) {
- _assertValidState();
- _assertNative2DModeEnabled();
- _visible = visible;
- WebView_setVisible(_nativeWebViewPtr, visible);
- }
- public override void ZoomIn() => WebGLWarnings.LogZoomInError();
- public override void ZoomOut() => WebGLWarnings.LogZoomOutError();
- #region Non-public members
- readonly WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame();
- Task<bool> _canGoBackOrForward(string methodName) {
- _assertValidState();
- if (_verifyIFrameCanBeAccessed(methodName)) {
- WebGLWarnings.LogCanGoBackOrForwardWarning();
- return Task.FromResult(WebView_canGoBackOrForward(_nativeWebViewPtr));
- }
- return Task.FromResult(false);
- }
- bool _verifyIFrameCanBeAccessed(string methodName) {
- if (CanAccessIFrameContent()) {
- return true;
- }
- // Log an error instead of throwing an exception because
- // exceptions are disabled by default for WebGL.
- WebGLWarnings.LogIFrameContentAccessWarning(methodName);
- return false;
- }
- [DllImport(_dllName)]
- static extern void WebView_bringToFront(IntPtr webViewPtr);
- [DllImport(_dllName)]
- static extern bool WebView_canAccessIFrameContent(IntPtr webViewPtr);
- [DllImport(_dllName)]
- static extern bool WebView_canGoBackOrForward(IntPtr webViewPtr);
- [DllImport(_dllName)]
- static extern string WebView_executeJavaScriptSync(IntPtr webViewPtr, string javaScript);
- [DllImport(_dllName)]
- static extern string WebView_executeJavaScriptLocally(string javaScript);
- [DllImport(_dllName)]
- static extern string WebView_focusUnity();
- [DllImport(_dllName)]
- static extern IntPtr WebView_newInNative2DMode(string gameObjectName, int x, int y, int width, int height, bool ignoreDevicePixelRatio);
- [DllImport (_dllName)]
- static extern void WebView_postMessage(IntPtr webViewPtr, string message);
- [DllImport (_dllName)]
- static extern void WebView_setDevicePixelRatio(float devicePixelRatio);
- [DllImport (_dllName)]
- static extern void WebView_setFullscreenEnabled(bool enabled);
- [DllImport (_dllName)]
- static extern void WebView_setGeolocationEnabled(bool enabled);
- [DllImport (_dllName)]
- static extern void WebView_setRect(IntPtr webViewPtr, int x, int y, int width, int height);
- [DllImport (_dllName)]
- static extern void WebView_setScreenSharingEnabled(bool enabled);
- [DllImport (_dllName)]
- static extern void WebView_setUnityContainerElementId(string containerId);
- [DllImport (_dllName)]
- static extern void WebView_setVisible(IntPtr webViewPtr, bool visible);
- #endregion
- }
- }
- #else
- namespace Vuplex.WebView {
- [System.Obsolete("To use the WebGLWebView class, you must use the directive `#if UNITY_WEBGL && !UNITY_EDITOR` like described here: https://support.vuplex.com/articles/how-to-call-platform-specific-apis#webgl . Note: WebGLWebView isn't actually obsolete. This compiler error just reports it's obsolete because 3D WebView generated the error with System.ObsoleteAttribute.", true)]
- public class WebGLWebView {}
- }
- #endif
|