I am downloading Assetbundles using the UnitywebRequest method from HTTPS, however the UnityWebRequest.SendWebRequest seems to take its sweet time to actually start receiving any data.
public static IEnumerator DownloadMenuAssetBundle(string fileName)
{
string path = Path.Combine(Globals.Platform, fileName);
UnityWebRequest www = new UnityWebRequest(FileManager.RequestFile(path));//this returns the complete url to the bundle e.g https://mywebsite.com/unity/myBundle
www.downloadHandler = new DownloadHandlerBuffer();
www.SendWebRequest();
while (!www.isDone)
{
Debug.Log("response: " + www.responseCode);
if (www.isNetworkError)
{
Debug.Log(www.error);
}
Debug.Log("downloaded:" + www.downloadedBytes);
yield return null;
}
Debug.Log("downloaded bytes: " + www.downloadedBytes);
Debug.Log("final response:" + www.responseCode);
if (www.error != null)
{
Debug.LogError("Encountered error while downloading: <color=blue>" + fileName + "</color>: " + www.error);
}
else
{
//rest of the logic, this works
}
Debug.Log("response: " + www.downloadedBytes); will return 0 for a random amount of time (ranging from a few to up to a couple minutes at times). But www. isNetworkError is never hit, and once bytes do start to be received it'll download the entire thing in a couple of miliseconds.
Previously i was using the exact same script on a http server and it worked flawlessly without any delays, but once i switched over to https it started taking a while. The delay also does not happen in the editor (Unity version 2017.2.1f1 runtime version .net 3.5 with 2.0 subset api compability) but happens on all my mobile devices (Oneplus 3, samsung galaxy s8, samsung galaxy s6).
At first www.responseCode returned a 301 Moved Permanently, i resolved this by using the new https url instead of the http url hoping this would fix it. However it didn't and now i only get 200 OK.
It is also an inconsistent issue because the timing it takes isn't ever the same, neither does it even happen all the time (but does most of the time)
Can this be an issue by the security layer taking additional time or the server taking its time to respond? if this is the issue how would i be able to track this down (though i doubt this as it works well in the editor)?
EDIT: workaround
I got around the issue by using a WWW class instead of UnityWebRequest. the delay is completely gone now but no SSL certificate validation is being done as Unity seems to deny them by default. I wouldn't really call it a fix but works for now.
Always trouble with UnityWebRequest - sometimes nothing makes sense with UnityWebRequests...
You can try to replace
UnityWebRequest www = new UnityWebRequest(FileManager.RequestFile(path));
with
UnityWebRequest www = new UnityWebRequestAssetBundle(FileManager.RequestFile(path), 0);
Optional for testing:
Also I think your while loop is not "save" to catch the network error.
I would prefer the following like mentioned in the documentation
UnityWebRequest www = new UnityWebRequestAssetBundle(FileManager.RequestFile(path);
yield return www.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
Debug.Log(www.error.ToString());
}
else
{
// for testing only // if yield return www.SendWebRequest(); is working as expected www.isDone = true here!
while (!www.isDone)
{
Debug.Log("Something is wrong! " + www.responseCode);
yield return new WaitForSeconds(0.1f);
}
// do whatever you want
}
Hope this helps.
Related
My code used to work, it does not work anymore, I tried troubleshooting and can't figure out why.
I have this piece of code in my PHP:
$android_id_01 = $_GET['pmysql_room_id'];
$android_id_02 = "";
$f = fopen("00_android_id_01.txt", "w");
fwrite($f, print_r($android_id_01, true));
fclose($f);
$f = fopen("00_android_id_02.txt", "w");
fwrite($f, print_r($android_id_02, true));
fclose($f);
For troubleshooting I created two android IDs ($android_id_01 and $android_id_02) which are both empty (The first one is From Android and the second one I created directly from PHP).
Now when I launch my Android device, the PHP file is executed from server side and both the text files are created empty and identical. Now my code only works when I use $android_id_02 and not $android_id_01 from the code below:
if ($android_id == '')
{
//my code
}
(Yes when I use either one of the $android_id_01 OR $android_id_02 I rename it to $android_id and comment out the other one)
My question is, although this was working yesterday, why does it work with $android_id_02 = ""; and not $android_id_01 = $_GET['pmysql_room_id']; even though they are both empty????
I don't know what changed from yesterday to today.
Ok after a bit of troubleshooting I found a solution, strange though.
On the server side "display_errors" under PHP settings must be turned off. Somehow having this on interferes with the json_encode sent back to android client. (even though my code is not generating any errors)
For some reason, when I restart my PhoneGap app - it looses the localStorage vales that were stored before! I'm saving them in the normal way:
localStorage.setItem("foo","value");
This stores it just fine. However, when you restart the app (or leave the device off for a random amount of time), it seems to randomly loose the data. I've found a heck of a lot of posts about this - but no definative answer on how to get it to be persistent in a PhoneGap Build WebView app,
Any suggestions are much welcomed!
This seems to be quite a common problem with WebView apps:
Android 2.3.6 + Phonegap + localStorage
Android - Making Webview DomStorage persistant after app closed
I can't find a solution that works with PhoneGap Build apps though
An actual example I'm using, is:
var current_id = parseInt(currentId) + 1;
localStorage.setItem("entry_"+current_id,save_string);
localStorage.setItem("entryId",current_id);
..and then to extract it (not that this is important, as the problem is with the data going missing, and not with accessing it)
for (var i = 0; i < localStorage.length; i++){
if (localStorage.key(i).match("entry_")) {
outputString += "\n" + localStorage.getItem(localStorage.key(i));
}
}
I'm wondering if maybe upgrading from PhoneGap Build cli-5.2.0 to cli-6.0.0 may help. I will do this, and give it a whirl.
I guess another option, would be to use a SQL database to locally store the device (its just a bit trickier to setup, and means re-writing my code)
UPDATE: Not the ideal solution - but I have now moved the app over to use WebSQL for the app. It was a bit tricky to get the hang of (never used it before) - but seems to do the job, and shouldn't loose the data :)
EDIT
i tried it like this and it worked:
var current_id = parseInt(currentId) + 1;
localStorage.setItem("entry_"+current_id,save_string);
localStorage.setItem("entryId",current_id);
/*
//this is for checking, what is stored in localStorage
console.log("length: " + localStorage.length);
for(var i = 0; i < localStorage.length; i++) {
console.log(localStorage.key(i));
}
*/
var myEntryIdFromStorage = localStorage.getItem("entryId");
var myItem = localStorage.getItem("entry_" + myEntryIdFromStorage);
Old answer for clarification
How do you get your localstorage?
normally you should store items like you did:
var permanentStorage = window.localstorage;
permanentStorage.setItem("foo", "bar");
and get them back by initializing the permanentStorage the same way and:
//assuming you have permanentStorage in the same script file
//or else you have to initialize it again:
//var permanentStorage = window.localstorage;
var myItem = permanentStorage.getItem("foo");
console.log("myItem: " + myItem);
The method store item uses two parameters: the identifier and the data itself. Please check, that the identifier with which you store your data is the same as the one, with which you get it back.
Do you get any errors? Is the return (stored in my example in myItem) null or undefined or just an empty string? Does this fail in the browser or on the device?
You could clarify your question by providing more code or error messages!
I am facing a strange issue, and I am not able to debug it out. I have implemented a logic for uploading stream of data and am using Volley for the same, I have customized a logic little bit in HurlStack, addBodyIfExists api,so that body of type "application/octet-stream" can be handled.
My logic is to post progress to user, so that UI can be updated indicating user progress in upload, below my logic for same.
int toRead = length; // File length
byte[] data = new byte[4096];
connection.setDoOutput(true);
if(length != -1) {
connection.setFixedLengthStreamingMode(length);
} else {
connection.setChunkedStreamingMode(4096);
}
OutputStream os;
int i;
int count;
os = connection.getOutputStream();
int progress= 0;
try {
for(i = 0; (count= is.read(data)) > 0; ++i) { // is, is not null and contains a valid input stream
os.write(data, 0, count); // at this line am getting unexpected end of stream
progress+= count;
if(i % 20 == 0) {
rs.deliverProgress(progress, 0L);
progress= 0;
}
}
os.flush();
} finally {
if(is != null) {
is.close();
}
if(os != null) {
os.close();
}
}
on executing above code am getting this, although I have verified, output stream is not null, neither do input stream, it fails in first iteration of read loop itself, am seeing it has read 4096 bytes and then trying to write the same.
java.net.ProtocolException: unexpected end of stream
at com.android.okhttp.internal.http.HttpConnection$FixedLengthSink.close(HttpConnection.java:326)
at com.android.okio.RealBufferedSink.close(RealBufferedSink.java:174)
at com.android.okio.RealBufferedSink$1.close(RealBufferedSink.java:142)
any help in debugging above will he highly appreciated.
This may help you :
That exception is thrown by FixedLengthInputStream when the expected number of bytes (usually set in the content-length header of the response) is larger than the actual data in the response.
Check that the content-length header is correct. (If you're supplying your own value for the content length, make sure it is correct.)
It would help to see your code that sets up the input stream.
Already Fixed it, please add "Accept-Encoding", "identity" in header, then the server-side will get command that it will not modify the response, then send back to Clients.
If you have checked everywhere in your code and tried every solution in stackoverflow and github but the issue still occurs, and you have only tested your code on emulator, then, you should try to run your code on your real device instead. Maybe it will work, or maybe it won't, but if you feel desperate, just have a try, seriously. I was astonished when I happened to find that my code ran with bugs on emulator everytime but successfully on my mobile phone. Besides, the code also ran sucessfully on others' android emulators. So I guess there is something wrong in my android studio configuration that I can't find out. I have no idea why this happen, just like we don't know why "Clean Project/Invalidate caches" sometimes works better than any solution.
It is a little strange that your data length might be unknown.
Is it a media file? Or a live stream?
Anyway, I tried to upload my live stream data. And it happened in the same error.
I added this setting to the Connection and solved my problem.
Transfer-Encoding : chunked
("setChunkedStreamingMode" didn't work. I still don't know why.)
This happens for me on android emulator and doesn't happen on my physical android device.
I was doing GET request to flask server running on 0.0.0.0 on my laptop from the android app.
To fix it on the emulator, add the servers ip address in the emulators proxy.
see How to set up Android emulator proxy settings
The exact problem i had was unexpected end of stream retrofit
I have an HTML/JavaScript app that I'm trying to convert to an App using PhoneGap via the Phonegap Build app
Everything works fine through the browser, and the only problem the app is having is that the call to getJSON is returning a 404 error when trying to load my local resources.
Here is the culprit:
$.getJSON( "./shapes/json/" + abbr + '.json', gotJSON(abbr) );
I have whitelisted every domain, just to be sure:
<access origin="*" />
Is this something that is not possible from the phonegap environment? Or am I doing something wrong?
If needed, I can host the files elsewhere and do a cross-domain ajax call, but I'd rather have the files right there on the device.
This is currently happening on Android, which is the only system I can test at the moment.
UPDATE:
I'm now trying:
var xhrShapes = new XMLHttpRequest(), xhrSuccess = gotJSON(abbr);
xhrShapes.open('GET', config.path + "/shapes/json/" + abbr + ".json");
xhrShapes.onreadystatechange = function(e){
if( this.readyState === 4 ){
if( this.status === xhrSuccessCode ){
xhrSuccess(JSON.parse(this.responseText));
}
}
}
xhrShapes.send();
config.path is "file:///android_asset/www" and I'm getting 0 as a success code (which indicates success for 'file://' requests). but xhrShapes.responseText is blank and everything stops at the call to JSON.parse. I feel like I'm missing something simple...
The problem had nothing to do with the code, but rather with the file names being case-sensitive... my abbr variable was uppercase, but filenames are lowercase. $.getJSON works perfectly, now that I've corrected this (though now my pride needs some repairs).
In an attempt to bypass Box file/folder IDs and supporting a number of other services as well I decided to implement with WebDAV since I'm somewhat familiar with it on my linux box. I chose a library based on JackRabbit modified to work on Android which seemed to suit my needs. However, it wasn't long until I ran into a problem.
When attempting to list Box's root entries, multiStatus.getResponses() returns an empty array. When accessing another webdav server I get the responses as expected. Both servers return status code 207, as expected.
My code is below, any thoughts?
EDIT: I can move a file, though listing a directory's entries won't work :/
String host = "https://www.box.com/dav/";
//String host = "http://demo.sabredav.org/";
hostConfig = new HostConfiguration();
hostConfig.setHost(host);
HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams params = new HttpConnectionManagerParams();
int maxHostConnections = 20;
params.setMaxConnectionsPerHost(hostConfig, maxHostConnections);
connectionManager.setParams(params);
client = new HttpClient(connectionManager);
Credentials creds = new UsernamePasswordCredentials("BOXEMAILADDRESS", "MYBOXPASSWORD");
//Credentials creds = new UsernamePasswordCredentials("testuser", "test");
client.getState().setCredentials(AuthScope.ANY, creds);
client.setHostConfiguration(hostConfig);
try
{
String propfindUri = host;
DavMethod method = new PropFindMethod(propfindUri, DavConstants.PROPFIND_ALL_PROP, DavConstants.DEPTH_1);
client.executeMethod(method);
Log.i("Status: " + method.getStatusCode());
MultiStatus multiStatus = method.getResponseBodyAsMultiStatus();
MultiStatusResponse[] responses = multiStatus.getResponses();
Log.i("Length: " + responses.length);
for(MultiStatusResponse response : responses)
{
Log.i("File: " + response.getHref());
}
}
catch (Exception e)
{
Log.printStackTrace(e);
}
While Box has some support for WebDAV, we only officially support it for iOS at the moment. Our testing has shown that our implementation of DAV works pretty well with the Windows native DAV client, as well as the Panic-Transmit Mac-specific client. Though the interactions there are not completely perfect.
Box WebDAV does not work well with the native osX (Mac) webDAV client. Expect huge delays as it looks like that client tries to load the whole tree before it displays anything.
Linux users may be able to tell you here on StackTrace which of the various OS webDAV clients/libs they've tried and which ones have worked better than others.
We do have plans to turn the crank and 10x improve our webDAV support sometime later this year, but we do not have a specific date, and just the nature of webDAV clients is such that even when we fix many of the issues with it, some client experiences on webDAV may still suck. For that reason we may only officially endorse a couple webDAV clients/libs per platform.
Hope that helps.