StandaloneWebView.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  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_STANDALONE_WIN || UNITY_EDITOR_WIN || UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
  17. using System;
  18. using System.Collections.Generic;
  19. using System.IO;
  20. using System.Runtime.InteropServices;
  21. using UnityEngine;
  22. #if NET_4_6 || NET_STANDARD_2_0
  23. using System.Threading.Tasks;
  24. #endif
  25. namespace Vuplex.WebView {
  26. /// <summary>
  27. /// The base `IWebView` implementation used by 3D WebView for Windows and macOS.
  28. /// This class also includes extra methods for Standalone-specific functionality.
  29. /// </summary>
  30. public abstract class StandaloneWebView : BaseWebView,
  31. IWithDownloads,
  32. IWithKeyDownAndUp,
  33. IWithKeyModifiers,
  34. IWithMovablePointer,
  35. IWithPointerDownAndUp,
  36. IWithPopups {
  37. /// <summary>
  38. /// Event raised if a server requests HTTP authentication.
  39. /// </summary>
  40. /// <remarks>
  41. /// If no handler is attached to this event, then the host's authentication request will be ignored
  42. /// and the page will not be paused. If a handler is attached to this event, then the page will
  43. /// be paused until `AuthRequestedEventArgs.Continue()` or `Cancel()` is called.
  44. ///
  45. /// You can test basic HTTP auth using [this page](https://jigsaw.w3.org/HTTP/Basic/)
  46. /// with the username "guest" and the password "guest".
  47. /// </remarks>
  48. public event EventHandler<AuthRequestedEventArgs> AuthRequested {
  49. add {
  50. if (_authRequestedHandler != null) {
  51. throw new InvalidOperationException("AuthRequested supports only one event handler. Please remove the existing handler before adding a new one.");
  52. }
  53. _authRequestedHandler = value;
  54. WebView_setAuthEnabled(_nativeWebViewPtr, true);
  55. }
  56. remove {
  57. if (_authRequestedHandler == value) {
  58. _authRequestedHandler = null;
  59. WebView_setAuthEnabled(_nativeWebViewPtr, false);
  60. }
  61. }
  62. }
  63. /// <see cref="IWithDownloads"/>
  64. public event EventHandler<DownloadChangedEventArgs> DownloadProgressChanged;
  65. /// <see cref="IWithPopups"/>
  66. public event EventHandler<PopupRequestedEventArgs> PopupRequested;
  67. public static new void ClearAllData() {
  68. var pluginIsInitialized = WebView_pluginIsInitialized();
  69. if (pluginIsInitialized) {
  70. _throwAlreadyInitializedException("clear the browser data", "ClearAllData");
  71. }
  72. var cachePath = _getCachePath();
  73. if (Directory.Exists(cachePath)) {
  74. Directory.Delete(cachePath, true);
  75. }
  76. }
  77. public override void Copy() {
  78. _assertValidState();
  79. WebView_copy(_nativeWebViewPtr);
  80. }
  81. public override void Cut() {
  82. _assertValidState();
  83. WebView_cut(_nativeWebViewPtr);
  84. }
  85. /// <summary>
  86. /// Enables remote debugging with Chrome DevTools on the given port.
  87. /// Note that this method can only be called prior to
  88. /// initializing any webviews.
  89. /// </summary>
  90. /// <remarks>
  91. /// - For example, if you provide 8080 as the `portNumber`, you can navigate to
  92. /// `http://localhost:8080 `in Chrome to see a list of webviews to inspect.
  93. /// - For more information on debugging, please see
  94. /// [this support article](https://support.vuplex.com/articles/how-to-debug-web-content#standalone).
  95. /// </remarks>
  96. /// <param name="portNumber">Port number in the range 1024 - 65535.</param>
  97. public static void EnableRemoteDebugging(int portNumber) {
  98. if (!(1024 <= portNumber && portNumber <= 65535)) {
  99. throw new ArgumentException(string.Format("The given port number ({0}) is not in the range from 1024 to 65535.", portNumber));
  100. }
  101. var success = WebView_enableRemoteDebugging(portNumber);
  102. if (!success) {
  103. _throwAlreadyInitializedException("enable remote debugging", "EnableRemoteDebugging");
  104. }
  105. }
  106. #if NET_4_6 || NET_STANDARD_2_0
  107. /// <summary>
  108. /// Gets the cookie that matches the given URL and cookie name, or
  109. /// null if no cookie matches.
  110. /// Note that if a cookie's domain includes a leading dot
  111. /// to denote it matches any subdomain (e.g. `\"https://.vuplex.com\"`),
  112. /// then the URL parameter must include the leading dot in order to match.
  113. /// </summary>
  114. /// <remarks>
  115. /// This method can only be called after
  116. /// one or more webviews have been initialized.
  117. /// </remarks>
  118. public static Task<Cookie> GetCookie(string url, string cookieName) {
  119. var task = new TaskCompletionSource<Cookie>();
  120. GetCookie(url, cookieName, task.SetResult);
  121. return task.Task;
  122. }
  123. #endif
  124. /// <summary>
  125. /// Like the other version of `GetCookie()`, except it uses a callback
  126. /// instead of a `Task` in order to be compatible with legacy .NET.
  127. /// </summary>
  128. public static void GetCookie(string url, string cookieName, Action<Cookie> callback) {
  129. var pluginIsInitialized = WebView_pluginIsInitialized();
  130. if (!pluginIsInitialized) {
  131. throw new InvalidOperationException("On Windows and macOS, GetCookie() can only be called when the Chromium process is running (i.e. after a webview is initialized).");
  132. }
  133. var resultCallbackId = Guid.NewGuid().ToString();
  134. _pendingGetCookieResultCallbacks[resultCallbackId] = callback;
  135. WebView_getCookie(url, cookieName, resultCallbackId);
  136. }
  137. #if NET_4_6 || NET_STANDARD_2_0
  138. /// <summary>
  139. /// Gets all of the cookies that match the given URL.
  140. /// Note that if a cookie's domain includes a leading dot
  141. /// to denote it matches any subdomain (e.g. `\"https://.vuplex.com\"`),
  142. /// then the URL parameter must include the leading dot in order to match.
  143. /// </summary>
  144. /// <remarks>
  145. /// This method can only be called after
  146. /// one or more webviews have been initialized.
  147. /// </remarks>
  148. public static Task<Cookie[]> GetCookies(string url) {
  149. var task = new TaskCompletionSource<Cookie[]>();
  150. GetCookies(url, task.SetResult);
  151. return task.Task;
  152. }
  153. #endif
  154. /// <summary>
  155. /// Like the other version of `GetCookies()`, except it uses a callback
  156. /// instead of a `Task` in order to be compatible with legacy .NET.
  157. /// </summary>
  158. public static void GetCookies(string url, Action<Cookie[]> callback) {
  159. var pluginIsInitialized = WebView_pluginIsInitialized();
  160. if (!pluginIsInitialized) {
  161. throw new InvalidOperationException("On Windows and macOS, GetCookies() can only be called when the Chromium process is running (i.e. after a webview is initialized).");
  162. }
  163. var resultCallbackId = Guid.NewGuid().ToString();
  164. _pendingGetCookiesResultCallbacks[resultCallbackId] = callback;
  165. WebView_getCookies(url, resultCallbackId);
  166. }
  167. [Obsolete("The IWithKeyModifiers interface is now deprecated. Please use the IWithKeyDownAndUp interface instead.")]
  168. public void HandleKeyboardInput(string key, KeyModifier modifiers) {
  169. KeyDown(key, modifiers);
  170. KeyUp(key, modifiers);
  171. }
  172. public override void Init(Texture2D viewportTexture, float width, float height, Texture2D videoTexture) {
  173. base.Init(viewportTexture, width, height, videoTexture);
  174. _nativeWebViewPtr = WebView_new(gameObject.name, _nativeWidth, _nativeHeight, null);
  175. if (_nativeWebViewPtr == IntPtr.Zero) {
  176. throw new WebViewUnavailableException("Failed to instantiate a new webview. This could indicate that you're using an expired trial version of 3D WebView.");
  177. }
  178. }
  179. /// <see cref="IWithKeyDownAndUp"/>
  180. public void KeyDown(string key, KeyModifier modifiers) {
  181. _assertValidState();
  182. WebView_keyDown(_nativeWebViewPtr, key, (int)modifiers);
  183. }
  184. /// <see cref="IWithKeyDownAndUp"/>
  185. public void KeyUp(string key, KeyModifier modifiers) {
  186. _assertValidState();
  187. WebView_keyUp(_nativeWebViewPtr, key, (int)modifiers);
  188. }
  189. /// <see cref="IWithMovablePointer"/>
  190. public void MovePointer(Vector2 point) {
  191. _assertValidState();
  192. int nativeX = (int) (point.x * _nativeWidth);
  193. int nativeY = (int) (point.y * _nativeHeight);
  194. WebView_movePointer(_nativeWebViewPtr, nativeX, nativeY);
  195. }
  196. public override void Paste() {
  197. _assertValidState();
  198. WebView_paste(_nativeWebViewPtr);
  199. }
  200. /// <see cref="IWithPointerDownAndUp"/>
  201. public void PointerDown(Vector2 point) {
  202. _pointerDown(point, MouseButton.Left, 1);
  203. }
  204. /// <see cref="IWithPointerDownAndUp"/>
  205. public void PointerDown(Vector2 point, PointerOptions options) {
  206. if (options == null) {
  207. options = new PointerOptions();
  208. }
  209. _pointerDown(point, options.Button, options.ClickCount);
  210. }
  211. /// <see cref="IWithPointerDownAndUp"/>
  212. public void PointerUp(Vector2 point) {
  213. _pointerUp(point, MouseButton.Left, 1);
  214. }
  215. /// <see cref="IWithPointerDownAndUp"/>
  216. public void PointerUp(Vector2 point, PointerOptions options) {
  217. if (options == null) {
  218. options = new PointerOptions();
  219. }
  220. _pointerUp(point, options.Button, options.ClickCount);
  221. }
  222. public override void SelectAll() {
  223. _assertValidState();
  224. WebView_selectAll(_nativeWebViewPtr);
  225. }
  226. /// <summary>
  227. /// By default, web pages cannot access the device's
  228. /// camera or microphone via JavaScript.
  229. /// Invoking `SetAudioAndVideoCaptureEnabled(true)` allows
  230. /// **all web pages** to access the camera and microphone.
  231. /// </summary>
  232. /// <remarks>
  233. /// This is useful, for example, to enable WebRTC support.
  234. /// This method can only be called prior to initializing any webviews.
  235. /// </remarks>
  236. public static void SetAudioAndVideoCaptureEnabled(bool enabled) {
  237. var success = WebView_setAudioAndVideoCaptureEnabled(enabled);
  238. if (!success) {
  239. _throwAlreadyInitializedException("enable audio and video capture", "SetAudioAndVideoCaptureEnabled");
  240. }
  241. }
  242. /// <summary>
  243. /// Sets additional command line arguments to pass to Chromium.
  244. /// <summary>
  245. /// <remarks>
  246. /// [Here's an unofficial list of Chromium command line arguments](https://peter.sh/experiments/chromium-command-line-switches/).
  247. /// This method can only be called prior to initializing any webviews.
  248. /// </remarks>
  249. /// <example>
  250. /// StandaloneWebView.SetCommandLineArguments("--ignore-certificate-errors --disable-web-security");
  251. /// </example>
  252. public static void SetCommandLineArguments(string args) {
  253. var success = WebView_setCommandLineArguments(args);
  254. if (!success) {
  255. _throwAlreadyInitializedException("set command line arguments", "SetCommandLineArguments");
  256. }
  257. }
  258. #if NET_4_6 || NET_STANDARD_2_0
  259. /// <summary>
  260. /// Sets the given cookie and returns a `Task&gt;bool>` indicating
  261. /// whether the cookie was set successfully.
  262. /// </summary>
  263. /// <remarks>
  264. /// If setting the cookie fails, it could be because the data in the provided Cookie
  265. /// was malformed. For more info regarding the failure, check the logs.
  266. /// This method can only be called after one or more webviews have been initialized.
  267. /// </remarks>
  268. /// <example>
  269. /// var success = await StandaloneWebView.SetCookie(new Cookie {
  270. /// Domain = "vuplex.com",
  271. /// Path = "/",
  272. /// Name = "example_name",
  273. /// Value = "example_value"
  274. /// });
  275. /// </example>
  276. public static Task<bool> SetCookie(Cookie cookie) {
  277. var task = new TaskCompletionSource<bool>();
  278. SetCookie(cookie, task.SetResult);
  279. return task.Task;
  280. }
  281. #endif
  282. /// <summary>
  283. /// Like the other version of `SetCookie()`, except it uses a callback
  284. /// instead of a `Task` in order to be compatible with legacy .NET.
  285. /// </summary>
  286. public static void SetCookie(Cookie cookie, Action<bool> callback) {
  287. var pluginIsInitialized = WebView_pluginIsInitialized();
  288. if (!pluginIsInitialized) {
  289. throw new InvalidOperationException("On Windows and macOS, SetCookie() can only be called when the Chromium process is running (i.e. after a webview is initialized).");
  290. }
  291. if (cookie == null) {
  292. throw new ArgumentException("Cookie cannot be null.");
  293. }
  294. if (!cookie.IsValid) {
  295. throw new ArgumentException("Cannot set invalid cookie: " + cookie);
  296. }
  297. var resultCallbackId = Guid.NewGuid().ToString();
  298. _pendingSetCookieResultCallbacks[resultCallbackId] = callback;
  299. WebView_setCookie(cookie.ToJson(), resultCallbackId);
  300. }
  301. /// <see cref="IWithDownloads"/>
  302. public void SetDownloadsEnabled(bool enabled) {
  303. _assertValidState();
  304. var downloadsDirectoryPath = enabled ? Path.Combine(Application.temporaryCachePath, Path.Combine("Vuplex.WebView", "downloads")) : "";
  305. WebView_setDownloadsEnabled(_nativeWebViewPtr, downloadsDirectoryPath);
  306. }
  307. public static void SetIgnoreCertificateErrors(bool ignore) {
  308. var success = WebView_setIgnoreCertificateErrors(ignore);
  309. if (!success) {
  310. _throwAlreadyInitializedException("ignore certificate errors", "SetIgnoreCertificateErrors");
  311. }
  312. }
  313. /// <summary>
  314. /// By default, the native file picker for file input elements is disabled,
  315. /// but it can be enabled with this method.
  316. /// </summary>
  317. public void SetNativeFileDialogEnabled(bool enabled) {
  318. _assertValidState();
  319. WebView_setNativeFileDialogEnabled(_nativeWebViewPtr, enabled);
  320. }
  321. public void SetPopupMode(PopupMode popupMode) {
  322. WebView_setPopupMode(_nativeWebViewPtr, (int)popupMode);
  323. }
  324. /// <summary>
  325. /// By default, web pages cannot share the device's screen
  326. /// via JavaScript. Invoking `SetScreenSharingEnabled(true)` allows
  327. /// **all web pages** to share the screen.
  328. /// </summary>
  329. /// <remarks>
  330. /// The screen that is shared is the default screen, and there isn't currently
  331. /// support for sharing a different screen or a specific application window.
  332. /// This is a limitation of Chromium Embedded Framework (CEF), which 3D WebView
  333. /// uses to embed Chromium. Also, this method can only be called prior to
  334. /// initializing any webviews.
  335. /// </remarks>
  336. public static void SetScreenSharingEnabled(bool enabled) {
  337. var success = WebView_setScreenSharingEnabled(enabled);
  338. if (!success) {
  339. _throwAlreadyInitializedException("enable or disable screen sharing", "SetScreenSharingEnabled");
  340. }
  341. }
  342. public static new void SetStorageEnabled(bool enabled) {
  343. var cachePath = enabled ? _getCachePath() : "";
  344. var success = WebView_setCachePath(cachePath);
  345. if (!success) {
  346. _throwAlreadyInitializedException("enable or disable storage", "SetStorageEnabled");
  347. }
  348. }
  349. /// <summary>
  350. /// Sets the target web frame rate. The default is `60`, which is also the maximum value.
  351. /// Specifying a target frame rate of `0` disables the frame rate limit. This method can only be called prior
  352. /// to initializing any webviews.
  353. /// </summary>
  354. public static void SetTargetFrameRate(uint targetFrameRate) {
  355. var success = WebView_setTargetFrameRate(targetFrameRate);
  356. if (!success) {
  357. _throwAlreadyInitializedException("set the target frame rate", "SetTargetFrameRate");
  358. }
  359. }
  360. /// <summary>
  361. /// Sets the zoom level to the specified value. Specify `0.0` to reset the zoom level.
  362. /// </summary>
  363. public void SetZoomLevel(float zoomLevel) {
  364. _assertValidState();
  365. WebView_setZoomLevel(_nativeWebViewPtr, zoomLevel);
  366. }
  367. public static void TerminatePlugin() {
  368. WebView_terminatePlugin();
  369. }
  370. delegate void GetCookieCallback(string requestId, string serializedCookies);
  371. delegate void SetCookieCallback(string requestId, bool success);
  372. delegate void UnitySendMessageFunction(string gameObjectName, string methodName, string message);
  373. EventHandler<AuthRequestedEventArgs> _authRequestedHandler;
  374. static Dictionary<string, Action<Cookie>> _pendingGetCookieResultCallbacks = new Dictionary<string, Action<Cookie>>();
  375. static Dictionary<string, Action<Cookie[]>> _pendingGetCookiesResultCallbacks = new Dictionary<string, Action<Cookie[]>>();
  376. static Dictionary<string, Action<bool>> _pendingSetCookieResultCallbacks = new Dictionary<string, Action<bool>>();
  377. protected static string _getCachePath() {
  378. // Only `Path.Combine(string, string)` is available in .NET 2.0.
  379. return Path.Combine(Application.persistentDataPath, Path.Combine("Vuplex.WebView", "chromium-cache"));
  380. }
  381. /// <summary>
  382. /// The native plugin invokes this method.
  383. /// </summary>
  384. void HandleAuthRequested(string host) {
  385. var handler = _authRequestedHandler;
  386. if (handler == null) {
  387. // This shouldn't happen.
  388. WebViewLogger.LogWarning("The native webview sent an auth request, but no event handler is attached to AuthRequested.");
  389. WebView_cancelAuth(_nativeWebViewPtr);
  390. return;
  391. }
  392. var eventArgs = new AuthRequestedEventArgs(
  393. host,
  394. (username, password) => WebView_continueAuth(_nativeWebViewPtr, username, password),
  395. () => WebView_cancelAuth(_nativeWebViewPtr)
  396. );
  397. handler(this, eventArgs);
  398. }
  399. /// <summary>
  400. /// The native plugin invokes this method.
  401. /// </summary>
  402. void HandleDownloadProgressChanged(string serializedMessage) {
  403. var handler = DownloadProgressChanged;
  404. if (handler != null) {
  405. var message = DownloadMessage.FromJson(serializedMessage);
  406. handler(this, message.ToEventArgs());
  407. }
  408. }
  409. [AOT.MonoPInvokeCallback(typeof(GetCookieCallback))]
  410. static void _handleGetCookieResult(string resultCallbackId, string serializedCookie) {
  411. var callback = _pendingGetCookieResultCallbacks[resultCallbackId];
  412. _pendingGetCookieResultCallbacks.Remove(resultCallbackId);
  413. if (callback != null) {
  414. var cookie = Cookie.FromJson(serializedCookie);
  415. callback(cookie);
  416. }
  417. }
  418. [AOT.MonoPInvokeCallback(typeof(GetCookieCallback))]
  419. static void _handleGetCookiesResult(string resultCallbackId, string serializedCookies) {
  420. var callback = _pendingGetCookiesResultCallbacks[resultCallbackId];
  421. _pendingGetCookiesResultCallbacks.Remove(resultCallbackId);
  422. var cookies = Cookie.ArrayFromJson(serializedCookies);
  423. callback(cookies);
  424. }
  425. /// <summary>
  426. /// The native plugin invokes this method.
  427. /// </summary>
  428. void HandlePopup(string message) {
  429. var handler = PopupRequested;
  430. if (handler == null) {
  431. return;
  432. }
  433. var components = message.Split(new char[] { ',' }, 2);
  434. var url = components[0];
  435. var popupBrowserId = components[1];
  436. if (popupBrowserId.Length == 0) {
  437. handler(this, new PopupRequestedEventArgs(url, null));
  438. return;
  439. }
  440. var popupWebView = _instantiate();
  441. Dispatcher.RunOnMainThread(() => {
  442. Web.CreateTexture(1, 1, texture => {
  443. // Use the same resolution and dimensions as the current webview.
  444. popupWebView.SetResolution(_numberOfPixelsPerUnityUnit);
  445. popupWebView._initPopup(texture, _width, _height, popupBrowserId);
  446. handler(this, new PopupRequestedEventArgs(url, popupWebView as IWebView));
  447. });
  448. });
  449. }
  450. [AOT.MonoPInvokeCallback(typeof(SetCookieCallback))]
  451. static void _handleSetCookieResult(string resultCallbackId, bool success) {
  452. var callback = _pendingSetCookieResultCallbacks[resultCallbackId];
  453. _pendingSetCookieResultCallbacks.Remove(resultCallbackId);
  454. if (callback != null) {
  455. callback(success);
  456. }
  457. }
  458. void _initPopup(Texture2D viewportTexture, float width, float height, string popupId) {
  459. base.Init(viewportTexture, width, height, null);
  460. _nativeWebViewPtr = WebView_new(gameObject.name, _nativeWidth, _nativeHeight, popupId);
  461. }
  462. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
  463. static void _initializePlugin() {
  464. // The generic `GetFunctionPointerForDelegate<T>` is unavailable in .NET 2.0.
  465. var sendMessageFunction = Marshal.GetFunctionPointerForDelegate((UnitySendMessageFunction)_unitySendMessage);
  466. WebView_setSendMessageFunction(sendMessageFunction);
  467. WebView_setCookieCallbacks(
  468. Marshal.GetFunctionPointerForDelegate((GetCookieCallback)_handleGetCookieResult),
  469. Marshal.GetFunctionPointerForDelegate((GetCookieCallback)_handleGetCookiesResult),
  470. Marshal.GetFunctionPointerForDelegate((SetCookieCallback)_handleSetCookieResult)
  471. );
  472. SetStorageEnabled(true); // cache, cookies, and storage are enabled by default
  473. }
  474. protected abstract StandaloneWebView _instantiate();
  475. static void _throwAlreadyInitializedException(string action, string methodName) {
  476. var message = String.Format("Unable to {0} because a webview has already been created. On Windows and macOS, {1}() can only be called prior to initializing any webviews.", action, methodName);
  477. throw new InvalidOperationException(message);
  478. }
  479. void _pointerDown(Vector2 point, MouseButton mouseButton, int clickCount) {
  480. _assertValidState();
  481. int nativeX = (int) (point.x * _nativeWidth);
  482. int nativeY = (int) (point.y * _nativeHeight);
  483. WebView_pointerDown(_nativeWebViewPtr, nativeX, nativeY, (int)mouseButton, clickCount);
  484. }
  485. void _pointerUp(Vector2 point, MouseButton mouseButton, int clickCount) {
  486. _assertValidState();
  487. int nativeX = (int) (point.x * _nativeWidth);
  488. int nativeY = (int) (point.y * _nativeHeight);
  489. WebView_pointerUp(_nativeWebViewPtr, nativeX, nativeY, (int)mouseButton, clickCount);
  490. }
  491. [AOT.MonoPInvokeCallback(typeof(UnitySendMessageFunction))]
  492. static void _unitySendMessage(string gameObjectName, string methodName, string message) {
  493. Dispatcher.RunOnMainThread(() => {
  494. var gameObj = GameObject.Find(gameObjectName);
  495. if (gameObj == null) {
  496. WebViewLogger.LogErrorFormat("Unable to send the message, because there is no GameObject named '{0}'", gameObjectName);
  497. return;
  498. }
  499. gameObj.SendMessage(methodName, message);
  500. });
  501. }
  502. [DllImport(_dllName)]
  503. static extern void WebView_cancelAuth(IntPtr webViewPtr);
  504. [DllImport(_dllName)]
  505. static extern void WebView_continueAuth(IntPtr webViewPtr, string username, string password);
  506. [DllImport(_dllName)]
  507. static extern void WebView_copy(IntPtr webViewPtr);
  508. [DllImport(_dllName)]
  509. static extern void WebView_cut(IntPtr webViewPtr);
  510. [DllImport(_dllName)]
  511. static extern bool WebView_enableRemoteDebugging(int portNumber);
  512. [DllImport(_dllName)]
  513. static extern void WebView_getCookie(string url, string name, string resultCallbackId);
  514. [DllImport(_dllName)]
  515. static extern void WebView_getCookies(string url, string resultCallbackId);
  516. [DllImport(_dllName)]
  517. static extern void WebView_keyDown(IntPtr webViewPtr, string key, int modifiers);
  518. [DllImport(_dllName)]
  519. static extern void WebView_keyUp(IntPtr webViewPtr, string key, int modifiers);
  520. [DllImport (_dllName)]
  521. static extern void WebView_movePointer(IntPtr webViewPtr, int x, int y);
  522. [DllImport(_dllName)]
  523. static extern IntPtr WebView_new(string gameObjectName, int width, int height, string popupBrowserId);
  524. [DllImport(_dllName)]
  525. static extern void WebView_paste(IntPtr webViewPtr);
  526. [DllImport(_dllName)]
  527. static extern bool WebView_pluginIsInitialized();
  528. [DllImport (_dllName)]
  529. static extern void WebView_pointerDown(IntPtr webViewPtr, int x, int y, int mouseButton, int clickCount);
  530. [DllImport (_dllName)]
  531. static extern void WebView_pointerUp(IntPtr webViewPtr, int x, int y, int mouseButton, int clickCount);
  532. [DllImport(_dllName)]
  533. static extern void WebView_selectAll(IntPtr webViewPtr);
  534. [DllImport(_dllName)]
  535. static extern bool WebView_setAudioAndVideoCaptureEnabled(bool enabled);
  536. [DllImport (_dllName)]
  537. static extern void WebView_setAuthEnabled(IntPtr webViewPtr, bool enabled);
  538. [DllImport(_dllName)]
  539. static extern bool WebView_setCachePath(string cachePath);
  540. [DllImport(_dllName)]
  541. static extern bool WebView_setCommandLineArguments(string args);
  542. [DllImport(_dllName)]
  543. static extern void WebView_setCookie(string serializedCookie, string resultCallbackId);
  544. [DllImport(_dllName)]
  545. static extern int WebView_setCookieCallbacks(IntPtr getCookieCallback, IntPtr getCookiesCallback, IntPtr setCookieCallback);
  546. [DllImport (_dllName)]
  547. static extern void WebView_setDownloadsEnabled(IntPtr webViewPtr, string downloadsDirectoryPath);
  548. [DllImport(_dllName)]
  549. static extern bool WebView_setIgnoreCertificateErrors(bool ignore);
  550. [DllImport(_dllName)]
  551. static extern void WebView_setNativeFileDialogEnabled(IntPtr webViewPtr, bool enabled);
  552. [DllImport(_dllName)]
  553. static extern void WebView_setPopupMode(IntPtr webViewPtr, int popupMode);
  554. [DllImport(_dllName)]
  555. static extern bool WebView_setScreenSharingEnabled(bool enabled);
  556. [DllImport(_dllName)]
  557. static extern int WebView_setSendMessageFunction(IntPtr sendMessageFunction);
  558. [DllImport(_dllName)]
  559. static extern bool WebView_setTargetFrameRate(uint targetFrameRate);
  560. [DllImport(_dllName)]
  561. static extern void WebView_setZoomLevel(IntPtr webViewPtr, float zoomLevel);
  562. [DllImport(_dllName)]
  563. static extern void WebView_terminatePlugin();
  564. }
  565. }
  566. #endif