Skip to main content

Custom Windows WebView

The default Unity Web Browser (UWB) doesn’t support IL2CPP. For IL2CPP builds or more control, integrate a third-party WebView.

Vuplex Integration

Vuplex is a commercial WebView that supports IL2CPP.

1. Install Vuplex

  1. Purchase Vuplex Windows WebView
  2. Import the .unitypackage from your Vuplex dashboard
  3. Include Core/ and Standalone/ directories (skip Mac/)

2. Implement the Interface

Create a class implementing IWindowsWebBrowserClient:
#if UNITY_STANDALONE_WIN

using Cysharp.Threading.Tasks;
using Immutable.Browser.Core;
using Vuplex.WebView;

public class VuplexWebView : IWindowsWebBrowserClient
{
    public event OnUnityPostMessageDelegate OnUnityPostMessage;
    private IWebView webView;

    public VuplexWebView()
    {
        webView = Web.CreateWebView();
    }

    public async UniTask Init()
    {
        await webView.Init(1, 1);

        webView.MessageEmitted += (sender, eventArgs) =>
        {
            OnUnityPostMessage?.Invoke(eventArgs.Value);
        };
    }

    public void LoadUrl(string url)
    {
        webView.LoadUrl(url);
    }

    public async void ExecuteJavaScript(string js)
    {
        await webView.ExecuteJavaScript(js);
    }

    public string GetPostMessageApiCall()
    {
        return "window.vuplex.postMessage";
    }

    public void Dispose()
    {
        webView.Dispose();
    }
}

#endif

3. Initialize with Custom WebView

passport = await Passport.Init(clientId, environment
#if UNITY_STANDALONE_WIN || (UNITY_EDITOR_WIN && UNITY_STANDALONE_WIN)
    , windowsWebBrowserClient: new VuplexWebView()
#endif
);

4. Configure Scripting Defines

  1. Go to FileBuild SettingsPlayer Settings
  2. Navigate to PlayerOther Settings
  3. Add IMMUTABLE_CUSTOM_BROWSER to Scripting Define Symbols
  4. Click Apply
This excludes the default WebView from your build.

5. Exclude Vuplex from Non-Windows Builds

Follow Vuplex’s platform exclusion guide to prevent Vuplex from being included in iOS/Android builds.

Custom Timeout Configuration

Override default timeouts for SDK operations:
// Set custom timeout (default is 60 seconds)
passport.SetCallTimeout(TimeSpan.FromMinutes(2));

If you need custom deep link handling:
// iOS/Android - handle incoming deep link
void OnDeepLinkActivated(string url)
{
    if (url.Contains("callback"))
    {
        passport.HandleDeepLink(url);
    }
}

Session Persistence

The SDK automatically persists sessions. To manually control:
// Check for existing session
bool hasSession = await passport.HasCredentialsSaved();

if (hasSession)
{
    // Silent login (no UI)
    await passport.LoginSilent();
}
else
{
    // Full login flow
    await passport.Login();
}

// Clear stored session
await passport.Logout();

Custom HTTP Client

For advanced networking requirements:
using UnityEngine.Networking;

// The SDK uses Unity's networking internally
// For custom headers or proxy configuration, modify at the system level

Debugging

Enable Verbose Logging

// Enable debug logs
Debug.unityLogger.logEnabled = true;

// SDK logs are tagged with [Immutable]

WebView Debugging

For WebView issues:
  1. Build a Development Build
  2. Connect Chrome DevTools (for Android/Windows)
  3. Inspect the WebView console for JavaScript errors

Network Inspection

Use a proxy tool (Charles, Fiddler) to inspect SDK network calls:
  • Auth endpoints: auth.immutable.com
  • API endpoints: api.sandbox.immutable.com (testnet) or api.immutable.com (mainnet)

Memory Management

Cleanup

Dispose of passport when no longer needed:
void OnDestroy()
{
    passport?.Dispose();
}

Asset Loading

NFT images are loaded via URL. For large inventories, implement lazy loading:
async void LoadNFTImage(string imageUrl, RawImage targetImage)
{
    using (var request = UnityWebRequestTexture.GetTexture(imageUrl))
    {
        await request.SendWebRequest();
        
        if (request.result == UnityWebRequest.Result.Success)
        {
            var texture = DownloadHandlerTexture.GetContent(request);
            targetImage.texture = texture;
        }
    }
}

Async/Await Patterns

The SDK uses UniTask for async operations:
using Cysharp.Threading.Tasks;

// Correct async pattern
public async UniTaskVoid Login()
{
    try
    {
        await passport.Login();
    }
    catch (Exception e)
    {
        Debug.LogError($"Login failed: {e.Message}");
    }
}

// Handle cancellation
public async UniTask LoginWithCancellation(CancellationToken ct)
{
    await passport.Login().AttachExternalCancellation(ct);
}

Multi-Scene Architecture

For games with multiple scenes:
// GameManager.cs - DontDestroyOnLoad singleton
public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }
    public Passport Passport { get; private set; }

    async void Awake()
    {
        if (Instance != null)
        {
            Destroy(gameObject);
            return;
        }
        
        Instance = this;
        DontDestroyOnLoad(gameObject);
        
        Passport = await Passport.Init(...);
    }
}

// Access from other scripts
var address = await GameManager.Instance.Passport.GetAddress();

Next Steps