Download Text Files From a Unity WebGL App

How do I have a Unity WebGL app generate content, and then let the user download that data?

This post focuses on text file data. For downloading binary files, see this post.

If you have a Unity app that’s a tool or something that’s creative, you can have the WebGL app generate a file that the browser can download.

One example can be found in the WebKey‘s app. The wiring for an instrument that a user creates can be downloaded an saved.

The Wiring pane of the WebKey app, with the download button highlighted.

The JavaScript Plugin

This is going to involve making a Unity WebGL plugin that performs some JavaScript. The documentation for that can be found here in the Unity documentation.

I searched around the web real quick on how save data as a file from JavaScript, and found this article. From that, I generated this *.jslib plugin file for the user to download a text file that was put into a Plugins folder in the Unity project.

mergeInto(LibraryManager.library, 
{
    BrowserTextDownload: function(filename, textContent)
    {
        // https://ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-without-a-server
        
        // Convert paramters to the correct form. See Unity WebGL Plugins page
        // for more information. It's not too important to realize why you need 
        // to do this, as long as you know THAT you need to.
        var strFilename = Pointer_stringify(filename);
        var strContent = Pointer_stringify(textContent);

        // Create the hyperlink for a user to click
        var element = document.createElement('a');
        
        // Set the link destination as hard-coded file data.
        element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(strContent));
        element.setAttribute('download', strFilename);
        
        // Make sure it's not visible when added to the HTML body
        element.style.display = 'none'; 
        
        // Activate it by adding it to the HTML body
        document.body.appendChild(element);
        // Don't wait for the user to click it, activate it ourselves!
        element.click();
        // Clean up our mess, now that the anchor's purpose is finished.
        document.body.removeChild(element);
    },
}

Basically, we create a link (anchor) object who’s hypertext reference is the hard-coded content instead of a web link. We add it to the main HTML body in order to make it official and immediately simulate clicking it.

Note that to keep this simple I’m limiting this to only handle saving text data.

Calling The Plugin From Unity

And then the Unity code we need to declare the function.

public class Application : MonoBehaviour
{
    [DllImport("__Internal")]
    public static extern void BrowserTextDownload(string filename, string textContent);
}

And that’s it! Here’s a snippet of how the call was used in the WebKeys app, where SaveDocumentString() creates the XMLDocument and then gets the string version of it.

public class PaneWiring: 
    PaneBase,   // Derives from MonoBehaviour
    IGNParamUICreator
{
    public void OnButton_DownloadDocument()
    {
        string docString = SaveDocumentString();
        Application.BrowserTextDownload("PhonicWiring.phon", docString);
    }
}

– Stay strong, code on. William Leu

Explore more articles here.
Explore more articles on Unity WebGL here.