diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 66732ec1e..a9280ea33 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -57,7 +57,7 @@ jobs: VALIDATE_ALL_CODEBASE: true DEFAULT_BRANCH: main GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - FILTER_REGEX_EXCLUDE: (.*src/Packages/Passport/Runtime/ThirdParty/.*|.*src/Packages/Passport/Runtime/Resources/.*|.*Plugins/.*|.*src/Packages/Passport/Runtime/Assets/ImmutableAndroid.androidlib/.*|.*src/Packages/Orderbook|.*sample) + FILTER_REGEX_EXCLUDE: (.*src/Packages/Passport/Runtime/ThirdParty/.*|.*src/Packages/Passport/Runtime/Resources/.*|.*Plugins/.*|.*src/Packages/Passport/Runtime/Assets/ImmutableAndroid.androidlib/.*|.*src/Packages/Orderbook|.*sample|.*src/Packages/Passport/WebGLTemplates) VALIDATE_MARKDOWN: false VALIDATE_GITLEAKS: false VALIDATE_JSCPD: false diff --git a/WebGL.md b/WebGL.md new file mode 100644 index 000000000..f2a6e01b2 --- /dev/null +++ b/WebGL.md @@ -0,0 +1,75 @@ +# Implementing Immutable Unity SDK for WebGL + +This guide provides focused instructions for implementing the Unity-Immutable-SDK in WebGL projects. + +For general information on the SDK, please refer to +the [Immutable Unity SDK documentation](https://docs.immutable.com/sdks/zkEVM/unity). + +Live example can be found at https://immutable.github.io/unity-immutable-sdk/sample/webgl + +## WebGL Template Setup + +WebGL template is a configuration setting that lets you control the appearance of the HTML page, so that you can: test, demonstrate, and preview your WebGL application in a browser. + +A WebGL Template is always needed for creating a WebGL application and it will always be stored within **Assets > WebGL Templates** to be used. You can refer to [Unity: WebGL Templates](https://docs.unity3d.com/Manual/webgl-templates.html) for more information. + +A Custom WebGL Template is required to implement the Immutable Unity SDK in WebGL projects. The easiest way to create a new custom WebGL template is to make a copy of the built-in Default or Minimal templates, which are stored in corresponding subfolders under > PlaybackEngines > WebGLSupport > BuildTools > WebGLTemplates. + +Every Unity Project includes these templates by default. Copy a template and place it in your own **Assets > WebGLTemplates** folder, and rename it to something meaningful so you can identify your template later. + +Once you have created your own template, copy the following files from Passport package into the **Assets > WebGLTemplates** folder: + - `Packages/Immutable Passport/WebGLTemplates~/unity-webview.js` + - `Packages/Immutable Passport/WebGLTemplates~/callback.html` + - `Packages/Immutable Passport/WebGLTemplates~/logout.html` + - `Packages/Immutable Passport/Runtime/Resources/index.html` > `Passport/index.html` + +3. Add the following script tag to the `index.html` in WebGL Templates: + ```html + + ``` + +## PKCE Login and Logout Implementation +> [!IMPORTANT] +> WebGL supports only PKCE flow. + +Follow these steps for implementation: +> [!NOTE] +> You can rename `callback.html` and `logout.html` to suit your project needs. +1. Define a deep link scheme for your game: + - Redirect URL: https://game.domain.com/callback.html + - Logout URL: https://game.domain.com/logout.html + +2. Configure Immutable Hub: + - Login to [Immutable Hub](https://hub.immutable.com) + - Add these deep links to your client's Redirect URLs and Logout URLs + +3. Update Passport initialisation: +```csharp +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using Immutable.Passport; + +public class InitPassport : MonoBehaviour +{ + private Passport passport; + + async void Start() + { + string clientId = "YOUR_IMMUTABLE_CLIENT_ID"; + string environment = Immutable.Passport.Model.Environment.SANDBOX; + string redirectUri = "https://game.domain.com/callback.html"; + string logoutRedirectUri = "https://game.domain.com/logout.html"; + passport = await Passport.Init(clientId, environment, redirectUri, logoutRedirectUri); + } +} +``` + +## Building for WebGL +1. Go to File > Build Settings +2. Select WebGL as the target platform +3. Click "Build And Run" +4. Choose a directory for the build output +Your WebGL application will open in your default web browser once the build is complete. + +For a complete working example, refer to the sample application in the SDK repository. \ No newline at end of file diff --git a/sample/Assets/WebGLTemplates.meta b/sample/Assets/WebGLTemplates.meta new file mode 100644 index 000000000..efbdd7a2e --- /dev/null +++ b/sample/Assets/WebGLTemplates.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0100bd16a6574f2e8b599c7182d8ca25 +timeCreated: 1728355396 \ No newline at end of file diff --git a/sample/Assets/WebGLTemplates/unity-webview.meta b/sample/Assets/WebGLTemplates/unity-webview.meta new file mode 100644 index 000000000..d05620a3b --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5c2fa0b2b414478aa1637dbaf42c9293 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/Passport.meta b/sample/Assets/WebGLTemplates/unity-webview/Passport.meta new file mode 100644 index 000000000..987495a07 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/Passport.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b12fa9a7cb74435e9874a4c05776a07b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/Passport/index.html.meta b/sample/Assets/WebGLTemplates/unity-webview/Passport/index.html.meta new file mode 100644 index 000000000..0000620e4 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/Passport/index.html.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ee9cb0148c3540ed9f4f8a27a92ee593 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData.meta new file mode 100644 index 000000000..164b862ff --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ee3278cacf624bd5b63cf0f917013d83 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/MemoryProfiler.png.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/MemoryProfiler.png.meta new file mode 100644 index 000000000..f6a5b8a7e --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/MemoryProfiler.png.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ab8e6237561e47dc949d779f0c640f56 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/favicon.ico.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/favicon.ico.meta new file mode 100644 index 000000000..85b173d23 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/favicon.ico.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4afbdcc98fcf402e9f90ab0d7ed72205 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/fullscreen-button.png.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/fullscreen-button.png.meta new file mode 100644 index 000000000..2819e74a7 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/fullscreen-button.png.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 34c19797f96b49d9919b9975dc15a4b2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-empty-dark.png.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-empty-dark.png.meta new file mode 100644 index 000000000..be6e990cf --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-empty-dark.png.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c1a103d5bd95486684389dc6e04491da +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-empty-light.png.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-empty-light.png.meta new file mode 100644 index 000000000..2b2965c9b --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-empty-light.png.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fef10b8baad54d6bb72bbe868561d5ed +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-full-dark.png.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-full-dark.png.meta new file mode 100644 index 000000000..cab100884 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-full-dark.png.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c5b037d8954d45acb3ec99b71cae30b2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-full-light.png.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-full-light.png.meta new file mode 100644 index 000000000..cd48eae95 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/progress-bar-full-light.png.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b2828eec5b6b4a938cadfc71b236e46f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/style.css.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/style.css.meta new file mode 100644 index 000000000..d32b23b62 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/style.css.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 55b657c73ff64857b7886fcbc82db7c6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/unity-logo-dark.png.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/unity-logo-dark.png.meta new file mode 100644 index 000000000..953096d05 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/unity-logo-dark.png.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 33721a4712084a6c8ae179cf9ecb4d76 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/unity-logo-light.png.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/unity-logo-light.png.meta new file mode 100644 index 000000000..970396b16 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/unity-logo-light.png.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6f2fa8e4af5e46ee9a6dd459765dfc9b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/webgl-logo.png.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/webgl-logo.png.meta new file mode 100644 index 000000000..961dd8548 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/webgl-logo.png.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5f566b12d1e941d997e6ae7c648983fb +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/TemplateData/webmemd-icon.png.meta b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/webmemd-icon.png.meta new file mode 100644 index 000000000..ab0ee3ac6 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/TemplateData/webmemd-icon.png.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8ad93116e71749f38b8e8d0077f00daf +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/callback.html.meta b/sample/Assets/WebGLTemplates/unity-webview/callback.html.meta new file mode 100644 index 000000000..cd01c43f5 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/callback.html.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1ba364b1c2a0453ebf4a8e1089c36128 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/index.html.meta b/sample/Assets/WebGLTemplates/unity-webview/index.html.meta new file mode 100644 index 000000000..32c4be0a4 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/index.html.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d4bd6a04987a4129a5553fb86e8a25a6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/logout.html.meta b/sample/Assets/WebGLTemplates/unity-webview/logout.html.meta new file mode 100644 index 000000000..beed82ea1 --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/logout.html.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6901f269a5aa498a81f673265cb2a8ca +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/sample/Assets/WebGLTemplates/unity-webview/unity-webview.js b/sample/Assets/WebGLTemplates/unity-webview/unity-webview.js index 8d8f0f2ee..b7cb43929 100644 --- a/sample/Assets/WebGLTemplates/unity-webview/unity-webview.js +++ b/sample/Assets/WebGLTemplates/unity-webview/unity-webview.js @@ -41,8 +41,6 @@ var unityWebView = loadURL: function(name, url) { var baseUrl = window.location.origin + window.location.pathname.replace(/\/[^\/]*$/, ""); - console.log(url, window.location.origin, window.location.pathname); - console.log(baseUrl); const host = window.location.origin.includes('localhost') ? window.location.origin : baseUrl; this.iframe(name).attr('loaded', 'false')[0].contentWindow.location.replace(host + url); }, diff --git a/sample/Assets/WebGLTemplates/unity-webview/unity-webview.js.meta b/sample/Assets/WebGLTemplates/unity-webview/unity-webview.js.meta new file mode 100644 index 000000000..9feceb0ee --- /dev/null +++ b/sample/Assets/WebGLTemplates/unity-webview/unity-webview.js.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fcf492a1e5d2401fb2da41a30dca1591 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Packages/Passport/WebGLTemplates~/callback.html b/src/Packages/Passport/WebGLTemplates~/callback.html new file mode 100644 index 000000000..12fc73f0d --- /dev/null +++ b/src/Packages/Passport/WebGLTemplates~/callback.html @@ -0,0 +1,24 @@ + + + + + + Unity WebGL Player | Immutable SDK Sample App + + + + + + +
+
Logging in
+
+ + + diff --git a/src/Packages/Passport/WebGLTemplates~/logout.html b/src/Packages/Passport/WebGLTemplates~/logout.html new file mode 100644 index 000000000..b31bc36da --- /dev/null +++ b/src/Packages/Passport/WebGLTemplates~/logout.html @@ -0,0 +1,24 @@ + + + + + + Unity WebGL Player | Immutable SDK Sample App + + + + + + +
+
Logging out
+
+ + + diff --git a/src/Packages/Passport/WebGLTemplates~/unity-webview.js b/src/Packages/Passport/WebGLTemplates~/unity-webview.js new file mode 100644 index 000000000..b7cb43929 --- /dev/null +++ b/src/Packages/Passport/WebGLTemplates~/unity-webview.js @@ -0,0 +1,70 @@ +var unityWebView = + { + loaded: [], + + init: function(name) { + $containers = $('.webviewContainer'); + if ($containers.length === 0) { + $('
') + .appendTo($('#unity-container')); + } + var $last = $('.webviewContainer:last'); + var clonedTop = parseInt($last.css('top')) - 100; + var $clone = $last.clone().insertAfter($last).css('top', clonedTop + '%'); + var $iframe = + $('') + .attr('id', 'webview_' + name) + .appendTo($last) + $iframe.on('load', function () { + $(this).attr('loaded', 'true'); + + var js = `window.Unity = { + call:function(msg) { + parent.unityWebView.sendMessage('${name}', msg); + } + };`; + + this.contentWindow.eval(js); + + window.addEventListener('message', function(event) { + if ((event.data.type === 'callback' || event.data.type === 'logout') && event.isTrusted) { + unityInstance.SendMessage(name, 'CallOnAuth', event.data.url); + } + }, false); + }); + return $iframe; + }, + + sendMessage: function (name, message) { + unityInstance.SendMessage(name, "CallFromJS", message); + }, + + loadURL: function(name, url) { + var baseUrl = window.location.origin + window.location.pathname.replace(/\/[^\/]*$/, ""); + const host = window.location.origin.includes('localhost') ? window.location.origin : baseUrl; + this.iframe(name).attr('loaded', 'false')[0].contentWindow.location.replace(host + url); + }, + + evaluateJS: function (name, js) { + $iframe = this.iframe(name); + if ($iframe.attr('loaded') === 'true') { + $iframe[0].contentWindow.eval(js); + } else { + $iframe.on('load', function(){ + $(this)[0].contentWindow.eval(js); + }); + } + }, + + destroy: function (name) { + this.iframe(name).parent().parent().remove(); + }, + + iframe: function (name) { + return $('#webview_' + name); + }, + + launchAuthURL: function(name, url) { + window.open(url, '_blank', 'width=460,height=660'); + }, + };