Webservices in unity3d: Post, JSON and wait

Webservices in unity3d: Post JSON tutorial.

Working with webservices in mobile apps is quite a common task,  but what if you are developing in Unity3d and need to send a Post request with JSON data? Well, there’s a quick and painless way of dealing with it, in less than 40 lines of code, complete of “wait…” screen management, from call to loggable answer.

First of all we’ll need a little coroutine and a JSON script you can get here.

The coroutine

It’s actually a very small one:

    IEnumerator afterConditionExecutor<T>(System.Action<T> del, T param, bool cond)
    {
        while (!cond)
        { yield return new WaitForEndOfFrame(); }
        del(param);
    }

This will just wait for our condition to be true, then execute the delegatedelgiving it the parameter it needs. We could just put here our wait screen control code, but you may want to customize it so we’ll handle that later (plus, this coroutine is so generally useful, you may want to put it in a library).

Sending the Post request

Let’s get to the meat of the issue, where the POST request is sent along with all our JSON data:

    public void sendMessage(JSONObject data, string url, bool addCookie, MonoBehaviour reqSource, System.Action<WWW> callBack)
    {
        Dictionary<string, string> headers = null;
        if (addCookie)
        {
            headers = new Dictionary<string, string>();
            headers.Add("Cookie", "SomeHeaderContent");
        }

        byte[] pData = Encoding.ASCII.GetBytes(data.ToString().ToCharArray());

        WWW www = new WWW(url,pData, headers);
        reqSource.StartCoroutine(afterConditionExecutor<T>(delegate (WWW mmm)
        {
            Debug.Log("sendMessage to: " + mmm.url + " returned: " + mmm.text);
            callBack(mmm);
        }, www, www.isDone);
    }

In the first part we prepare the request headers. Those are tipically the same across all webservice requests (eg.: login tokens) so it can be convenient to just generate them there and have a bool to control if they are added or not. Otherwise just add a parameter and pass it along from the source.

After that we encode ourJSONObjectin a byte array, so that is in the right format for theWWWobject constructor to pick up. When this constructor is called the webservice request will be sent as a POST http request, but we cannot just parse the reply right away because it won’t be ready. Even for whole seconds. Since it would be too long of a time to freeze our game/app, this call is conveniently Asynchronous. When is done,WWWclass will tell us by turning true thewww.isDoneflag (see reference docs here).

This is the reason why we start a coroutine on behalf of the message-sending class that will use our coroutine to wait until the proper moment and then call our callBack function.

Since there may be some standard error handling to do (eg: no internet connection) we do this inside a dedicated delegate that is passed as argument to the coroutine. Notice that theWWWargument of the delegate is named differently from the object we are just creating so that it links to the one being passed from the coroutine as an argument, this avoids a compilation error.

Let’s see a usage example:

    public void executeLogin(string username, string password)
    {
        JSONObject loginReqJS = new JSONObject();
        loginReqJS.AddField("username", username);
        loginReqJS.AddField("password", password);

        waitLayer.SetActive(true);
        sendMessage(loginReqJS, "http://your url/request/url", false, this, delegate (WWW www)
        {
            waitLayer.SetActive(false);
            Debug.Log("executeLogin to: " + www.url + " returned: " + www.text);
        });
    }

The first thing we do here is to prepare aJSONObjectwith the appropriate parameters for the situation, then we activate our “wait” UI element and finally call oursendMessagefunction.

Inside the delegate that will handle the server reply we also make our “wait” screen go away (non-standard error handling goes here, eg: wrong password), in this case we just log what’s been returned, but in real-life cases you’d transition from a login to your main menu.

This will produce the following http request:

POST /request/url HTTP/1.1
Cookie: "SomeHeaderContent"

{"username":"username","password":"password"}

And here you go. Hope you’ll find this tutorial useful. For more unity3d tutorials join my newsletter 😉

Here’s everything in a more copy-pastable format:

    IEnumerator afterConditionExecutor<T>(System.Action<T> del, T param, bool cond)
    {
        while (!cond)
        { yield return new WaitForEndOfFrame(); }
        del(param);
    }

    public void executeLogin(string username, string password)
    {
        JSONObject loginReqJS = new JSONObject();
        loginReqJS.AddField("username", username);
        loginReqJS.AddField("password", password);

        waitLayer.SetActive(true);
        sendMessage(loginReqJS, "http://your url/request/url", false, this, delegate (WWW www)
        {
            waitLayer.SetActive(false);
            Debug.Log("executeLogin to: " + www.url + " returned: " + www.text);
        });
    }

    public void sendMessage(JSONObject data, string url, bool addCookie, MonoBehaviour reqSource, System.Action<WWW> callBack)
    {
        Dictionary<string, string> headers = null;
        if (addCookie)
        {
            headers = new Dictionary<string, string>();
            headers.Add("Cookie", "SomeHeaderContent");
        }

        byte[] pData = Encoding.ASCII.GetBytes(data.ToString().ToCharArray());

        WWW www = new WWW(url, pData, headers);
        reqSource.StartCoroutine(afterConditionExecutor<T>(delegate (WWW mmm)
        {
            Debug.Log("sendMessage to: " + mmm.url + " returned: " + mmm.text);
            callBack(mmm);
        }, www, www.isDone);
    }

 

Share
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

Leave a Reply

Your email address will not be published.