8

The Code below is used to get Temperature Value from Thingworx server that is hosted in one of our own systems. This works perfectly well in unity. But not in andoird, once apk is generated, it won't fetch any data from the server and there will be connection established. But, it just wont fetch the data and put that into the text mesh.

I'm using unity 5.4.1 32bit . Check in both Android - 5.0.2 and 6.

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using System.Text.RegularExpressions;
using System;
using UnityEngine.UI;

public class  GETTempValue : MonoBehaviour {


public GameObject TempText;
static string TempValue;

void Start() 
{
    StartCoroutine(GetText());
}

IEnumerator GetText() 
{
    Debug.Log("Inside Coroutine");
    while (true) 
    {
        yield return new WaitForSeconds(5f);
        string url = "http://Administrator:ZZh7y6dn@*IP Address*:8080/Thingworx/Things/SimulationData/Properties/OvenTemperature/";

        Debug.Log("Before UnityWebRequest");
        UnityWebRequest www = UnityWebRequest.Get (url);
        yield return www.Send();
        Debug.Log("After UnityWebRequest");
        if (www.isError) {
            Debug.Log ("Error while Receiving: "+www.error);
        } else {
            Debug.Log("Success. Received: "+www.downloadHandler.text);
            string result = www.downloadHandler.text;
            Char delimiter = '>';

            String[] substrings = result.Split(delimiter);
            foreach (var substring in substrings) 
            {
                if (substring.Contains ("</TD")) 
                {
                    String[] Substrings1 = substring.Split ('<');
                    Debug.Log (Substrings1[0].ToString()+"Temp Value");
                    TempValue = Substrings1 [0].ToString ();
                    TempText.GetComponent<TextMesh> ().text = TempValue+"'C";
                }   
            }
        }

    }

}

}

this is the android manifest permission

uses-permission android:name="android.permission.INTERNET" 
uses-permission android:name="android.permission.CAMERA"
uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"
uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
santhosh.r
  • 186
  • 1
  • 1
  • 11
  • You do not need to include permission to a Manifest in order to use `UnityWebRequest`. Please remove that permission. Unity will generate it for you. As for your question, the information provided is not enough to help you. You need to put Debug.Log after and before `yield return www.Send()` and inside the `if (www.isError)` statement. This will help us know where you are failing. Edit and include this in your question. Also, is this a local server? – Programmer Sep 14 '16 at 05:31
  • @Programmer Yes it is a local server and it's made public. I got the above code from this answer to my [question] (http://stackoverflow.com/questions/39031641/retrieving-data-from-rest-api-in-unity-without-lag-or-jitter-using-c-sharp/39031840?noredirect=1#comment65749849_39031840) . What do you want in the debug log so that it helps to answer the issue?? I would be happy to provide you with more info. – santhosh.r Sep 14 '16 at 06:10
  • I updated the question with the `Debug.Log`. Run that then edit the question and put the Log under it. If you can make your server public and provide the url, I can try it as well and see what's wrong. – Programmer Sep 14 '16 at 06:18
  • @Programmer I updated the Question as asked with the url , But what is use of the Debug log ?? This program works fine in unity editor when i hit play !! But not on android after generating the app, How can Debug.log help once the apk is generated and run on android ? – santhosh.r Sep 14 '16 at 06:24
  • 1
    `Debug log` will show you what is going on in your app. I can use it to figure out what's happening and where your code is failing. It works in the Editor(Console Tab) and Android(Android Monitor). I sugest you google Debug.Log. I will give this try with the server url and let your know if I find anything – Programmer Sep 14 '16 at 06:30
  • So What do you mean that it doesn't work? What do you expect on the Android and what is happening now? – Programmer Sep 14 '16 at 06:40
  • The text mesh will not render anything. It's just blank on android!! but in the editor, the value that is given will be displayed in the textmesh of the gameobject. This I have experienced with OnGUI and 2D text also. It just won't fetch data after the apk is generated and the app is run on android. – santhosh.r Sep 14 '16 at 06:58
  • this is from the editor when i hit play http://imgur.com/a/5LtdN this is after generating the apk and running it on android http://imgur.com/a/o2wIz. – santhosh.r Sep 14 '16 at 07:27

1 Answers1

16

Embedding username and password(http://username:password@example.com) in a url is no longer supported in some Applications and OS for security reasons.That's because this is not the standard way to perform HTTP Authentication. It very likely that Unity or Android did not implement this on the their side.

I tested this on the built-in Android Browser with http://Administrator:ZZh7y6dn@*IP Address*:8080/Thingworx/Things/SimulationData/Properties/OvenTemperature/ and it failed to function. So, I guess this problem is from Android.

I tested again without username and password http://*IP Address**:8080/Thingworx/Things/SimulationData/Properties/OvenTemperature/ then the login window appeared. When I entered the username and password, it worked.

You can still use UnityWebRequest to solve this problem by providing the AUTHORIZATION header to the UnityWebRequest with the SetRequestHeader function. This will only work if the authorization type is Basic instead of Digest. In your case, it is HTTP Basic.

For general solution:

string authenticate(string username, string password)
{
    string auth = username + ":" + password;
    auth = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(auth));
    auth = "Basic " + auth;
    return auth;
}

IEnumerator makeRequest()
{
    string authorization = authenticate("YourUserName", "YourPassWord");
    string url = "yourUrlWithoutUsernameAndPassword";


    UnityWebRequest www = UnityWebRequest.Get(url);
    www.SetRequestHeader("AUTHORIZATION", authorization);

    yield return www.Send();
    .......
}

For solution in your question:

public GameObject TempText;
static string TempValue;

void Start()
{
    StartCoroutine(GetText());
}

string authenticate(string username, string password)
{
    string auth = username + ":" + password;
    auth = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(auth));
    auth = "Basic " + auth;
    return auth;
}

IEnumerator GetText()
{
    WaitForSeconds waitTime = new WaitForSeconds(2f); //Do the memory allocation once

    string authorization = authenticate("Administrator", "ZZh7y6dn");
    while (true)
    {
        yield return waitTime;
        string url = "http://*IP Address*:8080/Thingworx/Things/SimulationData/Properties/OvenTemperature/";


        UnityWebRequest www = UnityWebRequest.Get(url);
        www.SetRequestHeader("AUTHORIZATION", authorization);
        yield return www.Send();

        if (www.isError)
        {
            Debug.Log("Error while Receiving: " + www.error);
        }
        else
        {
            string result = www.downloadHandler.text;
            Char delimiter = '>';

            String[] substrings = result.Split(delimiter);
            foreach (var substring in substrings)
            {
                if (substring.Contains("</TD"))
                {
                    String[] Substrings1 = substring.Split('<');
                    Debug.Log(Substrings1[0].ToString() + "Temp Value");
                    TempValue = Substrings1[0].ToString();
                    TempText.GetComponent<TextMesh>().text = TempValue + "'C";
                }
            }
        }
    }
}
santhosh.r
  • 186
  • 1
  • 1
  • 11
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • Instead of doing all those string operation, please look into Json in Unity. That is more robust than string all the string operation in your code. [Json doc](https://docs.unity3d.com/ScriptReference/JsonUtility.html) and [Json derialization example](http://stackoverflow.com/questions/36239705/deserialization-of-json-using-minijson-in-unity-c-sharp/36244111#36244111) – Programmer Sep 14 '16 at 11:30
  • 3
    Hi as you said this will only work if the authorization type is Basic instead of Digest. In case if the authorization is Digest what changes do we make? – leelavinodh Apr 12 '18 at 14:00