Friday, May 8, 2015

Integrate Android Volley with Unity3d game

Standard
Hello All:

Volley is a very robust framework to make network calls. It provides out of the box support for caching, retry etc. In this post I will show how to integrate Volley with in a unity game.

This post assumes you have idea of writing plugins for Unity3d. You can see these posts to get an idea for the same
  1. Tutorial 1
  2. Tutorial 2

Integrating Volley with Unity game will involve two steps:
  1. We will create a plugin which will act as an bridge between Unity and Android
  2. In unity game we will invoke this plugin

Let us start with step 1:

Create an android application using Android Studio.

  1. Add Volley library to libs folder. You can get the Volley.jar from here.
  2. Add classes.jar from {Unity Installation Directory}\Editor\Data\PlaybackEngines\androidplayer\release\bin
Now create a new class HttpRequest.java

public class HttpRequest {

    ProgressDialog progressDialog;
    int responseCode;
    IAsyncCallback callback;
    Response.Listener<JSONObject> jsonResponseListener;
    Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            dismissProgressDialog();
            callback.onError(new ErrorDetail(error));
        }
    };
    private HashMap<String, String> params;
    private HashMap<String, String> headers;
    private String url;
    private Activity context;
    private String gameObject;

    public HttpRequest(Activity localActivity,
                       String url, String gameObjectName) {

        context = localActivity;
        this.url = url;
        gameObject = gameObjectName;
        headers = new HashMap<>();
        params = new HashMap<>();
        addJSONHeaders();
        setListeners();
    }


    public IAsyncCallback getCallback() {
        return callback;
    }

    public Context getContext() {
        return context;
    }

    private void addJSONHeaders() {
        AddHeader("Accept", "application/json");
        AddHeader("Content-type", "application/json");
    }

    private void setListeners() {
        jsonResponseListener = new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                dismissProgressDialog();
                WebResponse backendResponse;
                try {
                    String responseString = response.toString();
                    backendResponse = new WebResponse(responseCode,
                            responseString);
                    if (responseString == null) {
                        callback.onError(new ErrorDetail(new Exception("Empty response returned")));
                    } else {
                        callback.onComplete(backendResponse);
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                    callback.onError(new ErrorDetail(exception));
                }
            }
        };
    }

    public void AddParam(String name, String value) {
        params.put(name, value);
    }

    public void AddHeader(String name, String value) {
        headers.put(name, value);
    }

    public void dismissProgressDialog() {
        context.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (progressDialog != null && progressDialog.isShowing()) {
                    progressDialog.dismiss();
                }
            }
        });
    }

    public void execute() {
        this.callback = new IAsyncCallback() {
            @Override
            public void onComplete(WebResponse responseContent) {
                UnityPlayer.UnitySendMessage(gameObject, "OnComplete", responseContent.getResponse());
            }

            @Override
            public void onError(ErrorDetail errorData) {
                UnityPlayer.UnitySendMessage(gameObject, "OnError", errorData.toString());
            }
        };
        context.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                progressDialog = new ProgressDialog(getContext());
                progressDialog.setCancelable(false);
                progressDialog.setMessage("Please wait...");
                dismissProgressDialog();
                progressDialog.show();
            }
        });
        addToRequestQueue(VolleyManager.getInstance(context).getRequestQueue(), getJsonRequest());
    }

    public <X> void addToRequestQueue(RequestQueue requestQueue, Request<X> req) {
        requestQueue.add(req);
    }

    Request<JSONObject> getJsonRequest() {
        try {
            getUrl();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return new JsonObjectRequest(Request.Method.GET, url, jsonResponseListener, errorListener) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                return headers;
            }

            @Override
            protected Map<String, String> getParams() {
                return params;
            }
        };
    }

    void getUrl() throws UnsupportedEncodingException {
        String combinedParams = "";
        if (!params.isEmpty()) {
            combinedParams += "?";
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String paramString = entry.getKey() + "="
                        + URLEncoder.encode(entry.getValue(), "UTF-8");
                if (combinedParams.length() > 1) {
                    combinedParams += "&" + paramString;
                } else {
                    combinedParams += paramString;
                }
            }
        }
        url = url + combinedParams;
    }

}

VolleyManager.Java
public class VolleyManager {

    private static VolleyManager instance;
    private RequestQueue mRequestQueue;

    public RequestQueue getRequestQueue() {
        return mRequestQueue;
    }


    public synchronized static VolleyManager getInstance(Activity activity) {
        if (instance == null) {
            instance = new VolleyManager();
            instance.mRequestQueue = Volley.newRequestQueue(activity);
        }
        return instance;
    }
}

Generate jar using build.gradle

Now create a unity game. Add the above generate jar to Plugins/Android/ and Volley.jar to Plugins/Android/libs

Create following scripts

VolleyManager.cs

public class VolleyManager
{
    private AndroidJavaObject unityActivity;

    private VolleyManager()
    {
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        unityActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    }

    public static VolleyManager Instance
    {
        get
        {
            return Inner.instance;
        }

    }

    private class Inner
    {
        static Inner() { }
        internal static readonly VolleyManager instance = new VolleyManager();
    }

    public void AddRequest(Request request)
    {
        GameObject gameObject = new GameObject(DateTime.Now.Ticks.ToString());
        VolleyBindings volleyBindings = gameObject.AddComponent<VolleyBindings>();
        volleyBindings.OnCompleteHandler = request.OnComplete;
        volleyBindings.OnErrorHandler = request.OnError;
        AndroidJavaObject httpRequest = new AndroidJavaObject("in.ashwanik.volleyandoid.HttpRequest", unityActivity, request.URL, gameObject.name);

        foreach (var param in request.Params)
        {
            httpRequest.Call("AddParam", param.Key, param.Value);
        }
        foreach (var header in request.Headers)
        {
            httpRequest.Call("AddHeader", header.Key, header.Value);
        }
        httpRequest.Call("execute");
    }
}

public class Request
{
    public string URL { get; set; }
    public Action<string> OnComplete { get; set; }
    public Action<string> OnError { get; set; }
    public Dictionary<string, string> Params { get; private set; }
    public Dictionary<string, string> Headers { get; private set; }

    public Request()
    {
        Params = new Dictionary<string, string>();
        Headers = new Dictionary<string, string>();
    }
}

VolleyBindings.cs
public class VolleyBindings : MonoBehaviour {

 public Action<string> OnCompleteHandler { get; set; }
 public Action<string> OnErrorHandler { get; set; }
 // Use this for initialization
 void Start () {
 
 }
 
 // Update is called once per frame
 void Update () {
 
 }

 public void OnComplete(String response)
 {
  OnCompleteHandler(response);
  DestroyObject(this.gameObject);
 }

 public void OnError(string error)
 {
  OnErrorHandler(error);
  DestroyObject(this.gameObject);
 }
}

RequestTester.cs
public class RequestTester : MonoBehaviour
{
    public Text logger;
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }

    public void Request1()
    {
        Request request = new Request();
        request.URL = "http://www.ashwanik.in/blog/blogpost";
        request.Params.Add("data", "test data");
        request.OnComplete = (data) =>
        {
            logger.text += "data: " + data + "\n";
            Debug.Log("data: " + data);
        };
        request.OnError = (error) =>
        {
            Debug.Log("error: " + error);
        };

        VolleyManager.Instance.AddRequest(request);
    }
}

Hope this helps. You can get fully working code from here.
Happy coding


Thanks for printing this post. Hope you liked it.
Keep visiting and sharing.
Thanks,
Ashwani.

0 comments :

Post a Comment