URL Parameters for Unity WebGL Apps

How can I give Unity WebGL apps the equivalent of command line parameters?

TL;DR

For people who want to get directly to the answer and know the prerequisites, make a JavaScript plugin that sends back a member variable from window.location and parse it at the start of your program.

For everyone else who wants more of a deep-dive, enjoy the rest of the article.

Update 12/07/2021:
There’s a Unity API property, Application.absoluteURL that contains the URL of the web page it’s embedded in. This makes using a JavaScript plugin to get the link obsolete. The rest of the concepts should still apply – although the code samples may require a little adjustment.

Command Line Parameters

For traditional applications, parameters can be sent to the program when it’s started. If you navigate computers with a terminal interface, I’m sure you’re plenty familiar with this. If you’re ever double clicked a document and then your computer launched the program with the document opened, then you’ve seen your operating system secretly use this feature – your operating system simply opens the program with the filename set as the command line parameter. [wiki]

In Unity, you can access the command line parameters with System.Environment.GetCommandLineArgs(). [answers] That’s for traditional (desktop) applications. What about Unity WebGL apps? There are several ways a Unity WebGL app can receive parameters by writing some JavaScript to pipe in hardcoded values that the application can process when it’s starting. But, what about being able to change the parameters simply by changing the page visited? Without having to create multiple pages?

URL Query

An internet resource is addressed using a string in a format called a URI. When URIs are used to reference a web page, they are called a URL.

At the end of a webpage, you may often notice a question mark (?), and then a bunch of parameters, often mapped with an equal sign (=), with multiple parameters separated by an ampersand (&).

These are called query strings. They’re parameters for the webpage you’re currently on. It feeds the webpage parameters, and then anything interested in those parameters (PHP, JavaScript, your Unity app, etc.) can process those values.

A sample YouTube URL, with the query parameters of the video id being EpAyaAyWI-M, and the parameter of the start time is 2090 seconds into the video.

Implementation

The browser provides Javascript with a variable called window.location that can access different parts of the URL for the page the JavaScript is currently running on. While the query is accessible through the variable window.location.search, the entire path (everything that shows up in the address bar) can be accessed with window.location.href, which I find more useful to workaround.

The official name for that parameter section is called the ‘query’ section, but the official variable name is called ‘search’ instead of ‘query’. I feel like there’s a captivating story behind that mismatch. Or not...

Below is a Unity WebGL plugin sample of a function to get the value of window.location.href. I prefer to get href because it has all the information I’ll need on the URL, and I can parse it out myself in C# using .NET utilities.

mergeInto(LibraryManager.library, 
{
	BrowserGetLinkHREF : function()
	{
		// https://css-tricks.com/snippets/javascript/get-url-and-url-parts-in-javascript/
		var search = window.location.href;
		var searchLen = lengthBytesUTF8(search) + 1;
		var buffer = _malloc(searchLen);
		stringToUTF8(search, buffer, searchLen);
		return  buffer;
	},
});

That snippet should be saved into a *.jslib file, placed in a folder called Plugins in your project.

And here is code to declare the plugin function so the C# code knows about it – as well as a utility function to extract the query and parse it into a dictionary so that the individual parts can be iterated.

using System.Collections.Generic;

public class ParamParse
{
    [System.Runtime.InteropServices.DllImport("__Internal")]
    public static extern string BrowserGetLinkHREF();

    public static Dictionary<string,string> GetBrowserParameters()
    {

        Dictionary<string, string> ret = 
            new Dictionary<string, string>();

//#if UNITY_WEBGL && !UNITY_EDITOR

        // Use the .NET class Uri to parse the link and get the query portion for us
        System.Uri uri = new System.Uri(BrowserGetLinkHREF());
        string linkParams = uri.Query;

        if(linkParams.Length == 0)
            return ret;

        // If it contains the starting questionmark, strip it out
        if(linkParams[0] == '?')
            linkParams = linkParams.Substring(1);
        
        // Get the different parameters separated by '&''
        string [] sections = linkParams.Split(new char [] { '&' }, System.StringSplitOptions.RemoveEmptyEntries);
        foreach(string sec in sections)
        { 
            // Check to see if it's a variable assignment
            string [] split = sec.Split(new char[]{'=' }, System.StringSplitOptions.RemoveEmptyEntries);
            if(split.Length == 0)
                continue;

            // If it contains an '=' sign, assign its key-value in the dictionary
            if(split.Length == 2)
            {
                if(ret.ContainsKey(split[0]) == true)
                    ret[split[0]] = split[1];
                else
                    ret.Add(split[0], split[1]);
            }
            else
            {
                // If it doesn't contain a '=', just log it as a key, and an empty value
                if (ret.ContainsKey(sec) == true)
                    ret[sec] = "";
                else
                    ret.Add(sec, "");
            }

        }
//#endif
        return ret;
    }
}

It’s not too complicated, but the code could probably be drastically cut down with regular expressions.

And here’s a snippet of it being used in the WebHalt testbed.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Console : MonoBehaviour
{
   ...
   
    void Start()
    {
        this.ListHREFParameters();
    }
    
    ...
    
    void ListHREFParameters()
    { 
        Dictionary<string, string> prms = ParamParse.GetBrowserParameters();
        if(prms.Count == 0)
            return;

        string output = "Listing Link Parameters:\n";
        foreach(KeyValuePair<string, string> kvp in prms)
        { 
            if(string.IsNullOrEmpty(kvp.Value) == true)
                output += "\tKeyword " + kvp.Key + "\n";
            else
                output += "\tMapping " + kvp.Key + " with value " + kvp.Value + "\n";
        }
        this.log += output;
    }
}
WebHalt listing the individual query parameters of its URL.

Here are some test links with WebHalt:
Note how they’re all the same page, just with different query link data at the ends.

– Stay strong, code on. William Leu

Explore more articles here.
Explore more articles about Unity WebGL here.