iOSWebView.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /**
  2. * Copyright (c) 2021 Vuplex Inc. All rights reserved.
  3. *
  4. * Licensed under the Vuplex Commercial Software Library License, you may
  5. * not use this file except in compliance with the License. You may obtain
  6. * a copy of the License at
  7. *
  8. * https://vuplex.com/commercial-library-license
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #if UNITY_IOS && !UNITY_EDITOR
  17. using System;
  18. using System.Collections;
  19. using System.Collections.Generic;
  20. using System.Linq;
  21. using System.Runtime.InteropServices;
  22. using UnityEngine;
  23. using UnityEngine.Rendering;
  24. namespace Vuplex.WebView {
  25. /// <summary>
  26. /// The `IWebView` implementation used by 3D WebView for iOS.
  27. /// This class also includes extra methods for iOS-specific functionality.
  28. /// </summary>
  29. public class iOSWebView : BaseWebView, IWebView {
  30. public WebPluginType PluginType {
  31. get {
  32. return WebPluginType.iOS;
  33. }
  34. }
  35. public static iOSWebView Instantiate() {
  36. return (iOSWebView) new GameObject().AddComponent<iOSWebView>();
  37. }
  38. public override void Init(Texture2D viewportTexture, float width, float height, Texture2D videoTexture) {
  39. base.Init(viewportTexture, width, height, videoTexture);
  40. _nativeWebViewPtr = WebView_new(
  41. gameObject.name,
  42. _nativeWidth,
  43. _nativeHeight,
  44. videoTexture != null,
  45. SystemInfo.graphicsDeviceType != GraphicsDeviceType.Metal
  46. );
  47. }
  48. public override void Click(Vector2 point, bool preventStealingFocus) {
  49. _assertValidState();
  50. if (preventStealingFocus) {
  51. int nativeX = (int) (point.x * _nativeWidth);
  52. int nativeY = (int) (point.y * _nativeHeight);
  53. WebView_clickWithoutStealingFocus(_nativeWebViewPtr, nativeX, nativeY);
  54. } else {
  55. Click(point);
  56. }
  57. }
  58. /// <summary>
  59. /// Overrides `BaseWebView.CaptureScreenshot()` because it uses too much
  60. /// memory on iOS.
  61. /// </summary>
  62. public override void CaptureScreenshot(Action<byte[]> callback) {
  63. _assertValidState();
  64. IntPtr unmanagedBytes = IntPtr.Zero;
  65. int unmanagedBytesLength = 0;
  66. WebView_captureScreenshot(_nativeWebViewPtr, ref unmanagedBytes, ref unmanagedBytesLength);
  67. // Load the results into a managed array.
  68. var managedBytes = new byte[unmanagedBytesLength];
  69. Marshal.Copy(unmanagedBytes, managedBytes, 0, unmanagedBytesLength);
  70. WebView_freeMemory(unmanagedBytes);
  71. callback(managedBytes);
  72. }
  73. public override void EnableViewUpdates() {
  74. if (_currentVideoNativeTexture != IntPtr.Zero) {
  75. _videoTexture.UpdateExternalTexture(_currentVideoNativeTexture);
  76. }
  77. base.EnableViewUpdates();
  78. }
  79. /// <summary>
  80. /// Returns a file URL for resource included in the iOS app bundle.
  81. /// </summary>
  82. /// <remarks>
  83. /// This is useful for getting a file URL to a local file so that it
  84. /// can be loaded via `IWebView.LoadUrl()`.
  85. /// </remarks>
  86. /// <example>
  87. /// var fileUrl = iOSWebView.GetFileUrlForBundleResource("my-static-files/my-webpage.html");
  88. /// </example>
  89. [Obsolete("iOSWebView.GetFileUrlForBundleResource is now deprecated. You can now use LoadUrl(\"streaming-assets://{path}\") to load a file from StreamingAssets instead.")]
  90. public static string GetFileUrlForBundleResource(string fileName) {
  91. var fileNameSegments = fileName.Split(new char[] {'.'});
  92. if (fileNameSegments.Length < 2) {
  93. throw new ArgumentException(String.Format("The file name must include an extension, but the name provided ({0}) does not.", fileName));
  94. }
  95. var fileExtension = fileNameSegments[fileNameSegments.Length - 1];
  96. var fileNameWithoutExtension = String.Join(".", fileNameSegments.ToList().GetRange(0, fileNameSegments.Length - 1).ToArray());
  97. var stringPtr = WebView_getFileUrlForBundleResource(fileNameWithoutExtension, fileExtension);
  98. var fileUrl = Marshal.PtrToStringAnsi(stringPtr);
  99. return fileUrl;
  100. }
  101. /// <summary>
  102. /// Overrides `BaseWebView.GetRawTextureData()` because it uses too much
  103. /// memory on iOS.
  104. /// </summary>
  105. public override void GetRawTextureData(Action<byte[]> callback) {
  106. _assertValidState();
  107. IntPtr unmanagedBytes = IntPtr.Zero;
  108. int unmanagedBytesLength = 0;
  109. WebView_getRawTextureData(_nativeWebViewPtr, ref unmanagedBytes, ref unmanagedBytesLength);
  110. // Load the results into a managed array.
  111. var managedBytes = new byte[unmanagedBytesLength];
  112. Marshal.Copy(unmanagedBytes, managedBytes, 0, unmanagedBytesLength);
  113. WebView_freeMemory(unmanagedBytes);
  114. callback(managedBytes);
  115. }
  116. [Obsolete("iOSWebView.SetCustomUriSchemesEnabled() has been removed. Now when a page redirects to a URI with a custom scheme, 3D WebView will automatically emit the UrlChanged and LoadProgressChanged events for the navigation, but a deep link (i.e. to an external application) won't occur.", true)]
  117. public static void SetCustomUriSchemesEnabled(bool enabled) {}
  118. public static void SetIgnoreCertificateErrors(bool ignore) {
  119. WebView_setIgnoreCertificateErrors(ignore);
  120. }
  121. [Obsolete("iOSWebView.SetNativeKeyboardEnabled() is now deprecated. Please use Web.SetTouchScreenKeyboardEnabled() instead.")]
  122. public static void SetNativeKeyboardEnabled(bool enabled) {
  123. SetTouchScreenKeyboardEnabled(enabled);
  124. }
  125. public static void SetTouchScreenKeyboardEnabled(bool enabled) {
  126. WebView_setTouchScreenKeyboardEnabled(enabled);
  127. }
  128. /// <summary>
  129. /// Like `Web.SetUserAgent(bool mobile)`, except it sets the user-agent
  130. /// for a single webview instance instead of setting it globally.
  131. /// </summary>
  132. /// <remarks>
  133. /// If you globally set a default user-agent using `Web.SetUserAgent()`,
  134. /// you can still use this method to override the user-agent for a
  135. /// single webview instance.
  136. /// </remarks>
  137. public void SetUserAgent(bool mobile) {
  138. _assertValidState();
  139. WebView_setUserAgentToMobile(_nativeWebViewPtr, mobile);
  140. }
  141. /// <summary>
  142. /// Like `Web.SetUserAgent(string userAgent)`, except it sets the user-agent
  143. /// for a single webview instance instead of setting it globally.
  144. /// </summary>
  145. /// <remarks>
  146. /// If you globally set a default user-agent using `Web.SetUserAgent()`,
  147. /// you can still use this method to override the user-agent for a
  148. /// single webview instance.
  149. /// </remarks>
  150. public void SetUserAgent(string userAgent) {
  151. _assertValidState();
  152. WebView_setUserAgent(_nativeWebViewPtr, userAgent);
  153. }
  154. IntPtr _currentVideoNativeTexture;
  155. readonly WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame();
  156. void _applyVideoTexture() {
  157. if (_currentVideoNativeTexture == IntPtr.Zero) {
  158. return;
  159. }
  160. var previousNativeTexturePtr = _videoTexture.GetNativeTexturePtr();
  161. _videoTexture.UpdateExternalTexture(_currentVideoNativeTexture);
  162. _videoTexture.Apply();
  163. var newNativeTexturePtr = _videoTexture.GetNativeTexturePtr();
  164. if (!(previousNativeTexturePtr == IntPtr.Zero || previousNativeTexturePtr == newNativeTexturePtr)) {
  165. WebView_destroyTexture(previousNativeTexturePtr, SystemInfo.graphicsDeviceType.ToString());
  166. }
  167. }
  168. /// <summary>
  169. /// The native plugin invokes this method.
  170. /// </summary>
  171. void HandleVideoTextureChanged(string textureString) {
  172. var nativeTexture = new IntPtr(Int64.Parse(textureString));
  173. if (nativeTexture == _currentVideoNativeTexture) {
  174. return;
  175. }
  176. var previousNativeTexture = _currentVideoNativeTexture;
  177. _currentVideoNativeTexture = nativeTexture;
  178. if (_viewUpdatesAreEnabled) {
  179. _videoTexture.UpdateExternalTexture(_currentVideoNativeTexture);
  180. }
  181. if (previousNativeTexture != IntPtr.Zero && previousNativeTexture != _currentVideoNativeTexture) {
  182. WebView_destroyTexture(previousNativeTexture, SystemInfo.graphicsDeviceType.ToString());
  183. }
  184. }
  185. void OnEnable() {
  186. // Start the coroutine from OnEnable so that the coroutine
  187. // is restarted if the object is deactivated and then reactivated.
  188. StartCoroutine(_renderPluginOncePerFrame());
  189. }
  190. IEnumerator _renderPluginOncePerFrame() {
  191. while (true) {
  192. yield return _waitForEndOfFrame;
  193. if (!_viewUpdatesAreEnabled || IsDisposed) {
  194. continue;
  195. }
  196. int pointerId = WebView_depositPointer(_nativeWebViewPtr);
  197. GL.IssuePluginEvent(WebView_getRenderFunction(), pointerId);
  198. }
  199. }
  200. [DllImport(_dllName)]
  201. private static extern void WebView_captureScreenshot(IntPtr webViewPtr, ref IntPtr bytes, ref int length);
  202. [DllImport(_dllName)]
  203. static extern void WebView_clickWithoutStealingFocus(IntPtr webViewPtr, int x, int y);
  204. [DllImport(_dllName)]
  205. static extern int WebView_depositPointer(IntPtr pointer);
  206. [DllImport(_dllName)]
  207. static extern void WebView_freeMemory(IntPtr bytes);
  208. [DllImport(_dllName)]
  209. static extern IntPtr WebView_getFileUrlForBundleResource(string fileNameWithoutExtension, string fileExtension);
  210. [DllImport(_dllName)]
  211. static extern void WebView_getRawTextureData(IntPtr webViewPtr, ref IntPtr bytes, ref int length);
  212. [DllImport(_dllName)]
  213. static extern IntPtr WebView_getRenderFunction();
  214. [DllImport(_dllName)]
  215. static extern IntPtr WebView_new(string gameObjectName, int width, int height, bool enableVideoSupport, bool useOpenGL);
  216. [DllImport(_dllName)]
  217. static extern void WebView_setIgnoreCertificateErrors(bool ignore);
  218. [DllImport(_dllName)]
  219. static extern void WebView_setTouchScreenKeyboardEnabled(bool enabled);
  220. [DllImport(_dllName)]
  221. static extern void WebView_setUserAgentToMobile(IntPtr webViewPtr, bool mobile);
  222. [DllImport(_dllName)]
  223. static extern void WebView_setUserAgent(IntPtr webViewPtr, string userAgent);
  224. }
  225. }
  226. #endif