At present, I was facing some sort of weird problem. I turn off my internet connection to put some handling code over their. I thought it will return me some error code but its just giving me blank response rather than showing exception. I got following debug output when I print more details on screen.
Basically I want to show dialog box when there is no internet connection. But how to handle this situation!!!
Because there is no json response from server side then also there is some bytes I am receiving from server. Here is my code:
Dictionary<string,string> headerDisc = new Dictionary<string, string> ();
headerDisc.Add ("Api-Key", "You API Key");
WWW www = new WWW (GameConstants.CONTESTANT_LIST_BASE_URL, new byte[] { (byte)0 }, headerDisc);
yield return www;
if (www.error == null) {
Debug.Log ("bytes: " + www.bytes.Length);
Debug.Log ("size: " + www.size);
Debug.Log ("length: " + www.text.Length);
Debug.Log ("Data: " + www.text);
if (www.text.Length <= 0) {
AppManager.Instance.DialogMessage = "No Server Response Found!";
Camera.main.SendMessage ("ActivateDialogBoxPanel", true, SendMessageOptions.DontRequireReceiver);
} else {
JSONObject jsonObj = new JSONObject (www.text);
JSONObject messageObj = jsonObj [TAG_MESSAGE];
string successValueStr = jsonObj [TAG_SUCCESS].ToString ();
if (successValueStr.Equals (VALUE_TRUE))
// success
else
// fail
}
} else {
Debug.Log ("Error: " + www.error);
AppManager.Instance.DialogMessage = "Error:" + www.error;
Camera.main.SendMessage ("ActivateDialogBoxPanel", true, SendMessageOptions.DontRequireReceiver);
}
Please give me some suggestion in this. If you want some more information then I am available.
As i understand you want to check if internet connection is disabled show a message to user . for example you can write something like this.
IEnumerator checkInternetConnection(Action<bool> action){
WWW www = new WWW("http://google.com");
yield return www;
if (www.error != null) {
action (false);
} else {
action (true);
}
}
then in your Start() function write this.
void Start(){
StartCoroutine(checkInternetConnection((isConnected)=>{
// handle connection status here
}));
}
Related
I'm new to Unity (and c#, along with PHP) and have been tasked with getting some old c# and PHP code working. The code below is supposed to send the dictionary (formData) to the PHP server that then converts it to json. The code is below:
...
//This code runs for each file that is uploaded, the file is a list of strings and integers.
Dictionary<string, string> formData = new Dictionary<string, string>();
using (StreamReader sr = file.OpenText())
{
string s = "";
while ((s = sr.ReadLine()) != null)
{
string[] data = s.Split(';');
uploadResultText.setText(file.Name + ":" + data[0] + " " + data[0]);
if (data[1] == "") data[1] = " ";
formData[data[0]] = data[1];
}
}
UnityWebRequest uploadRequest = UnityWebRequest.Post(serverBaseURL, formData);
currentUploadRequest = uploadRequest;
yield return uploadRequest.SendWebRequest();
...
If this code is working, how will I need to receive it server-side?
It turns out it was a server side error, the code above should work.
The server was returning http error 500 because it was requesting data that did not exist (caused by switching names on the app side, but not the server side).
The server side code uses $_POST to reference the incoming data, and a sample can be seen below.
if (isSet($_POST["App"])) {
$dataArray = array();
foreach($expectedFormInputCommon as $input) {
if (isSet($_POST[$input])) {
if (seralizeString($_POST[$input]) !== false) {
$dataArray[$input] = seralizeString($_POST[$input]);
} else {
http_response_code(400);
exit;
}
} else {
http_response_code(400);
$_POST[$input] = "empty";
exit;
}
}
}
After you Yield Return you can access the result:
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
// Error
}
else
{
var result = UnityWebRequest.Result;
}
I want to generate a shorten dynamic link from a long dynamic link
I followed the steps shown here: https://firebase.google.com/docs/dynamic-links/unity/create
yet I get the same long URL when shortening process is completed.
public void CreateInviteLink()
{
var components = new Firebase.DynamicLinks.DynamicLinkComponents(
// The base Link.
new System.Uri("https://myapp.com"),
// The dynamic link URI prefix.
"https://myapp.page.link")
{
IOSParameters = new Firebase.DynamicLinks.IOSParameters("com.myapp.myapp"),
AndroidParameters = new Firebase.DynamicLinks.AndroidParameters("com.myapp.myApp"),
};
Debug.Log("Long Dynamic Link: " + components.LongDynamicLink);
var options = new Firebase.DynamicLinks.DynamicLinkOptions
{
PathLength = DynamicLinkPathLength.Unguessable
};
Firebase.DynamicLinks.DynamicLinks.GetShortLinkAsync(components, options).ContinueWith(task => {
if (task.IsCanceled)
{
Debug.LogError("GetShortLinkAsync was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("GetShortLinkAsync encountered an error: " + task.Exception);
return;
}
// Short Link has been created.
Firebase.DynamicLinks.ShortDynamicLink link = task.Result;
Debug.LogFormat("Generated Short Dynamic Link: {0}", link.Url);
text.text = link.Url.ToString();
var warnings = new System.Collections.Generic.List<string>(link.Warnings);
if (warnings.Count > 0)
{
// Debug logging for warnings generating the short link.
}
});
}
result Logs
Long Dynamic Link: https://myapp.page.link/?afl=&amv=0&apn=com.myapp.myApp&ibi=com.myapp.myapp&ifl=&ipfl=&link=https://myapp.com
UnityEngine.Debug:Log(Object)
Generated Short Dynamic Link: https://myapp.page.link/?afl=&amv=0&apn=com.myapp.myApp&ibi=com.myapp.myapp&ifl=&ipfl=&link=https://myapp.com
UnityEngine.Debug:LogFormat(String, Object[])
EDIT:
How I did it:
You can't shorten dynamic links with Firebase SDK in the editor but I used REST API and UnityWebRequest for testing short links inside the editor and it worked
IEnumerator HTTPRequestShortLink(string longDynamicLink)
{
WWWForm form = new WWWForm();
form.AddField("longDynamicLink", longDynamicLink);
// trigger of function is HTTP request. this link is the trigger for that func
UnityWebRequest www = UnityWebRequest.Post("https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=[YOUR_API_KEY]", form);
//for getting response
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Form upload complete! " + www.GetResponseHeader("response"));
string responseText = www.downloadHandler.text;
// Parse returned json
parsedJsonObject obj = parsedJsonObject.CreateFromJSON(responseText);
Debug.Log("shortLink: " + obj.shortLink);
Debug.Log("HTTP Response text: " + responseText);
}
}
I'm pretty new to the concept of Coroutines. now I got this problem, when I call my Coroutine function it gives an empty object back when I DON'T use
System.Threading.Thread.Sleep();. But when I use System.Threading.Thread.Sleep(int); It waits until the sleep method is completed before continuing the code. I get that it probably has something to do with that they work on the same thread but even my debug functions before the sleep method won't print untill the sleep function is done. could really use some help here!
I tried it with synchronous calls but this just makes my layout freeze.
IEnumerator PostRequestBearerToken(string uri)
{
string authorization = APIHelpers.authenticate("user", "pass");
WWWForm form = new WWWForm();
form.AddField("grant_type", "client_credentials");
using (UnityWebRequest www = UnityWebRequest.Post(uri, form))
{
www.SetRequestHeader("AUTHORIZATION", authorization);
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Post request complete!" + " Response Code: " + www.responseCode);
string responseText = www.downloadHandler.text;
Debug.Log("Response Text:" + responseText);
Debug.Log("Form upload complete!");
//deserialize bearertoken
BearerObject myObject = JsonUtility.FromJson<BearerObject>(www.downloadHandler.text);
Debug.Log("json : " + myObject.ToString());
//BearerTokenSingleton.getInstance();
BearerTokenSingleton.getInstance().SetBearerToken(myObject);
Debug.Log(BearerTokenSingleton.getInstance().GetBearerToken().ToString());
}
}
}
void Update()
{
if (!loadFirstFrame)
{
loadFirstFrame = true;
}
else if (loadFirstFrame)
{
StartCoroutine(PostRequestBearerToken(APIHelpers.bearerString));
//go to next scene
System.Threading.Thread.Sleep(5000);
SceneManager.LoadScene(2);
}
}
It is because of the SceneManager.LoadScene method. Coroutines run in separate threads. Since you start the coroutine and immediately load a new scene, there is no time to run the coroutine before the current scene (and script object) is unloaded. The Thread.Sleep call introduces a delay that gives enough time for the coroutine to finish before the scene load.
To get around this, you can use a flag (actually I use two, so you don't kick off the coroutine multiple times):
private bool _postComplete = false;
private bool _startedPost = false;
IEnumerator PostRequestBearerToken(string uri)
{
string authorization = APIHelpers.authenticate("user", "pass");
WWWForm form = new WWWForm();
form.AddField("grant_type", "client_credentials");
using (UnityWebRequest www = UnityWebRequest.Post(uri, form))
{
www.SetRequestHeader("AUTHORIZATION", authorization);
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Post request complete!" + " Response Code: " + www.responseCode);
string responseText = www.downloadHandler.text;
Debug.Log("Response Text:" + responseText);
Debug.Log("Form upload complete!");
//deserialize bearertoken
BearerObject myObject = JsonUtility.FromJson<BearerObject>(www.downloadHandler.text);
Debug.Log("json : " + myObject.ToString());
//BearerTokenSingleton.getInstance();
BearerTokenSingleton.getInstance().SetBearerToken(myObject);
Debug.Log(BearerTokenSingleton.getInstance().GetBearerToken().ToString());
}
_postComplete = true;
}
}
And then use that in the Update method:
void Update()
{
if (!loadFirstFrame)
{
loadFirstFrame = true;
}
else if (loadFirstFrame)
{
if (!_startedPost)
{
StartCoroutine(PostRequestBearerToken(APIHelpers.bearerString));
_startedPost = true;
}
if (_postComplete)
SceneManager.LoadScene(2);
}
}
I'm trying to send a POST request in Unity, but I can't do that as the function that is supposed to do that is skipped, I'm not sure why.
I have added logs to have an idea of what happens and "(post json) called" never appears even though the text saying that has gone past the function ((send game played): after postjson) appears in the logs.
private static void SendGamePlayed() {
int incrementedGamePlayed = GetGamePlayed () + 1;
EventObject anEvent = CreateEvent(EVENT_GAME_PLAYED, incrementedGamePlayed, null, null);
AbcEvent aAbcEvent = new AbcEvent (bundleID, appToken, anEvent);
string json = JsonUtility.ToJson (aAbcEvent);
// test
Debug.Log("(send game played): " + json);
PostJSON (json, EVENT_ROUTE);
Debug.Log ("(send game played): after postjson");
SetGamePlayed (incrementedGamePlayed);
}
private static IEnumerator PostJSON(string jsonString, string route) {
// test
Debug.Log("(post json) called");
string url = SERVER_URL + route;
var request = new UnityWebRequest(url, "POST");
byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonString);
request.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
request.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
Debug.Log ("(post json) before sending");
yield return request.Send();
Debug.Log ("(post json) after sending");
if (request.error != null) {
Debug.Log("request error: " + request.error);
} else {
Debug.Log("request success: " + request.downloadHandler.text);
}
}
Thanks for your help!
You're using Unity's feature for asynchronous operations. To understand the concepts, read up on generators and Unity coroutines. To run your function, call the StartCoroutine function like this:
StartCoroutine(PostJSON (json, EVENT_ROUTE));
Edit:
More specifically: You're creating a coroutine (PostJson) that calls an asynchronous function (Send).
So I am trying to post to my web api and use a callback when the post finishes. This all works perfectly in the Unity editor and as a Desktop app, but does NOT work in the Web Player. I have narrowed it down to just the callback not actually getting called. How can I use callbacks? Here is my code:
void ui_login() {
if (uiBase == null)
return;
Debug.LogError(uiBase); clicks++; status = "(" + clicks + ")" + "working";
var username = uiBase.UIElements.FirstOrDefault(e => e.Name == "txt_username");
var password = uiBase.UIElements.FirstOrDefault(e => e.Name == "txt_password");
try
{
var request = new LoginRequest()
{
Email = username.Text,
Password = password.Text
};
StartCoroutine(WaitForRequest<LoginResponse>(request, loginCallback));
}
catch (Exception e)
{
status = "(" + clicks + ")" + e;
}
}
void loginCallback(LoginResponse response, WWW www)
{
if (www.error != null)
status = www.error;
if (response != null)
status = response.ErrorMessage;
}
IEnumerator WaitForRequest<TResponse>(
LoginRequest request, Action<TResponse, WWW> callback)
{
var json = JsonMapper.ToJson(request);
var www = new WWW("http://someurl.com", json.ToBytes());
yield return www;
TResponse response;
if (www.error == null && www.isDone)
{
var str = Encoding.UTF8.GetString(www.bytes);
print(str);
status = str;
response = JsonConvert.DeserializeObject<TResponse>(str);
}
else
response = default(TResponse);
print("somthif");
callback(response, www);
}
For security reasons, Unity Web Player works in a Sandbox and will block your HTTP requests.
To fix this issue, follow the process described in this link: http://docs.unity3d.com/Documentation/Manual/SecuritySandbox.html