I'm trying to download images from a website and my code is working fine in most cases, but I can't download from this URL http://www.liveandlocal.org.uk/images/ShowPics/Steiny’s%20Blues%20-%20Such%20Sweet%20Thunder.jpg
The difference between this and the other URLs is that this one has a dash. I'm fairly certain this is the problem. Is there a way around this?
My error is java.io.filenotfoundexception
My initial code was:
imgLink = "http://www.liveandlocal.org.uk/images/ShowPics/" + Show + ".jpg";
imgLink = imgLink.replace(" ", "%20");
This gave me links like: http://www.liveandlocal.org.uk/images/ShowPics/The%20Atlantics.jpg
which works, but this didn't work for the link I posted at the top.
So now I've tried:
try {
Show = URLEncoder.encode(Show, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
imgLink = "http://www.liveandlocal.org.uk/images/ShowPics/" + Show + ".jpg";
Which doesnt work for any of my links, such as http://www.liveandlocal.org.uk/images/ShowPics/The+Atlantics.jpg
If you copy and paste the link at the start of this post into your browser it will work, so it is just not working on Android.
imgLink = "http://www.liveandlocal.org.uk/images/ShowPics/Steiny%E2%80%99s%20Blues%20-%20Such%20Sweet%20Thunder.jpg"
working fine for me, tested it, replace the characters thus accordingly and '.
- is fine.
Your url contains letters which are not suited for urls (' in this case).
You can encode your url as the following:
String encodedUrl = URLEncoder.encode(normalUrl, "UTF-8");
URLEncoder
Related
I am new to Unity and Android development, but please do not mark this as a duplicate - I've looked all over the stacks for an answer to this, but similar topics and questions haven't yielded any working solutions, or are wanting on details, or outdated, or seem not to fit my specific need.
Ok, I have a quiz app built from following part 1 & 2 of this tutorial. That link contains all the source files anyone might need for reference, and everything works fine on ios and in the unity editor, fyi.
The trouble is with the loadGameData function from the DataController script in Android. Again, everything works fine in iOS and the unity editor, but when I make an Android sdk, the quiz is blank and the console says the data couldn't be loaded.
Here is how the function is currently written (full file in tutorial link):
private void LoadGameData ()
{
string filePath = Path.Combine (Application.streamingAssetsPath, gameDataFileName);
if (File.Exists (result))
{
string dataAsJson = File.ReadAllText (result);
GameData loadedData = JsonUtility.FromJson<GameData> (dataAsJson);
allRoundData = loadedData.allRoundData;
} // #if(File.Exists...
else
{
Debug.LogError ("Cannot load game data!");
} // #else
} // #LoadGameData
If you check the same tutorial on youtube, you'll see lots of people have noted the same problem with the Android build and have been left unanswered. Same goes with unity forums - that's one reason why I don't think this question is a duplicate and could be helpful to others in a similar situation.
I've found that Android has always been sorta tricky with this and that there used to different ways of accessing a file based on platform, but these days "Application.streamingAssetsPath" should find the streaming assets directory on any platform, even Android.
What I've also learned is that in android, even if the path is correct, the file is compressed and will only return a url. So the url needs to be converted using unity's WWW class. I get that, but as of yet, I haven't been able to re-write my loadGameData function to work properly and load the allRoundData array.
Here's an example of some things I've tried:
IEnumerator androidData()
{
string filePath = Path.Combine (Application.streamingAssetsPath, gameDataFileName);
if (filePath.Contains("://"))
{
WWW www = new WWW(filePath);
yield return www;
result = www.text;
} // #if(filePath.Contains
} // #androidData
private void LoadGameData ()
{
androidData();
if (File.Exists (result))
{
string dataAsJson = File.ReadAllText (result);
GameData loadedData = JsonUtility.FromJson<GameData> (dataAsJson);
allRoundData = loadedData.allRoundData;
} // #if(File.Exists...
else
{
Debug.LogError ("Cannot load game data!");
} // #else
} // #LoadGameData
I know I'm close, and this is probably simple -- but I just can't seem to get to the finish line on this. Can some one help me figure out how to write the loadGameData function so it will load this allRoundData array on android?
An example code would be awesome and much appreciated, not just by me, but I'm sure many others would appreciate it also - Thank you!
UPDATE:
Based on the first answer, I've tested some code that works on the unity editor, but crashes in Android. In the Unity editor, I get the "file already exists" message. Here is the code I've tested:
Already had: private string gameDataFileName = "data.json";
I added the copyFile call above loadGameDate in Start() and wrote the copy file and loadGameData functions like so ..
int copyFileToPersistentDataPath(string gameDataFileName)
{
string persistentPath = Application.persistentDataPath + "/" + gameDataFileName;
try
{
//Copy only if gameDataFileName does not exist
if (!System.IO.File.Exists(persistentPath))
{
string path = System.IO.Path.Combine(Application.streamingAssetsPath, gameDataFileName);
WWW www = new WWW(path);
while (!www.isDone) { }
System.IO.File.WriteAllBytes(persistentPath, www.bytes);
Debug.Log(gameDataFileName + " Successfully Copied File to " + persistentPath);
return 1;
}
else
{
Debug.Log(gameDataFileName + " File already exist here. There is no need to copy it again");
return 0;
}
}
catch (Exception e)
{
Debug.Log(gameDataFileName + " Failed To Copy File. Reason: " + e.Message);
return -1;
}
}
private void LoadGameData ()
{
string tempPath = Path.Combine(Application.persistentDataPath, gameDataFileName);
string dataAsJson = File.ReadAllText(tempPath);
GameData loadedData = JsonUtility.FromJson<GameData>(dataAsJson);
allRoundData = loadedData.allRoundData;
} // #LoadGameData
This works with or without the call to copy the file in the editor, but crashes either way in Android.
I ended up putting the files in a Resources folder and going the resources.load a json file into a text asset and throw that into a string to parse route. I now have two different load functions, one that works in ios etc. and one that works in android. Here is the android function (the resourcesGameDataFile does not have the .json extension):
public void LoadDataForAndroid()
{
TextAsset dataFile = Resources.Load(resourcesGameDataFile) as TextAsset;
string dataAsJson = dataFile.ToString();
GameData loadedData = JsonUtility.FromJson<GameData>(dataAsJson);
allRoundData = loadedData.allRoundData;
Debug.Log ("Android data loaded with" + resourcesGameDataFile);
} // #LoadDataForAndroid
And this works in the unity editor and in Bluestacks (android simulator).
As for loading and saving games, this is a duplicate. I marked and remove this as a duplicate because the answer in the duplicated questions did not explain how to read from the StreamingAssets folder. It only talked about saving and loading data.
Make sure that Write Permission is set to External (SDCard).
The first thing to do is to copy the file from StreamingAssets to the persistentDataPath location.
I've found reading data from Application.streamingAssetsPath problematic but I use two methods to solve this.
int copyFileToPersistentDataPath(string fileNameWithExtensionName)
{
string persistentPath = Application.persistentDataPath + "/" + fileNameWithExtensionName;
try
{
//Copy only if fileNameWithExtensionName does not exist
if (!System.IO.File.Exists(persistentPath))
{
string path = System.IO.Path.Combine(Application.streamingAssetsPath, fileNameWithExtensionName);
WWW www = new WWW(path);
while (!www.isDone) { }
System.IO.File.WriteAllBytes(persistentPath, www.bytes);
Debug.Log(fileNameWithExtensionName + " Successfully Copied File to " + persistentPath);
return 1;
}
else
{
Debug.Log(fileNameWithExtensionName + " File already exist here. There is no need to copy it again");
return 0;
}
}
catch (Exception e)
{
Debug.Log(fileNameWithExtensionName + " Failed To Copy File. Reason: " + e.Message);
return -1;
}
}
If that does not work for you, use the method with WebClient below:
void copyFileToPersistentDataPath(string fileNameWithExtensionName)
{
string path = System.IO.Path.Combine(Application.streamingAssetsPath, fileNameWithExtensionName);
string persistentPath = Application.persistentDataPath + "/" + fileNameWithExtensionName;
Debug.Log("Dir: " + persistentPath);
WebClient webClient = new WebClient();
webClient.Proxy = null;
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(OnDownloadComplete);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnUpdateDownloadProgress);
Uri uri = new Uri(path);
webClient.DownloadFileAsync(uri, persistentPath);
}
void OnDownloadComplete(object sender, AsyncCompletedEventArgs e)
{
Debug.Log("Finished Downloading: " + e.Error.Message);
}
void OnUpdateDownloadProgress(object sender, DownloadProgressChangedEventArgs e)
{
Debug.Log("Uploading Progreess: " + e.ProgressPercentage);
}
File Copy Usage:
copyFileToPersistentDataPath("yourFileName.txt");
After copying the file, you can then read and convert it to Json like this:
string fileNameWithExtensionName = "questionfile.txt";
string tempPath = Path.Combine(Application.persistentDataPath, fileNameWithExtensionName);
string dataAsJson = File.ReadAllText(fileNameWithExtensionName);
GameData loadedData = JsonUtility.FromJson<GameData>(dataAsJson);
I work on android browser project
Many sites use GIF animation an ad. How i can disable GIF animation in android webview ?
Just inject a javascript to freeze the gifs recursively once your web page finishes loading. Heres how you do it,
First copy this javascript to your assets folder(If folder not available
then create folder in res directory) - gif_freezer.js
Add this method inside your class,
private void injectScriptFile(WebView view, String scriptFile) {
InputStream input;
try {
input = getAssets().open(scriptFile);
byte[] buffer = new byte[input.available()];
input.read(buffer);
input.close();
String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
view.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var script = document.createElement('script');" +
"script.type = 'text/javascript';" +
// Tell the browser to BASE64-decode the string into your script !!!
"script.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(script)" +
"})()");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Inside onPageFinished method put below code,
injectScriptFile(view, "gif_freezer.js");
view.loadUrl("javascript:freezeAllGifs();");
Thats all...
I created an android application and I'm using Google Translate Rest service.
I used this URL to send a request in order to translate a source text.
"https://www.googleapis.com/language/translate/v2?key=" + apiKey + "&target=en&q=" + text"
As you can see the source language was not set in order to enable the service to detect
the language of the given text.
When I put something in Hebrew the result I get is question mark.
For example if I enter "שלום עולם" which need to be translated into "hello world" in English,
I get the result "???? ????".
I tried with other languages like Russian or Spanish. It worked fine with Spanish, but
with the Russian language it worked like Hebrew.
Is there any bug with the API or am I doing something wrong?
Update:
encoded = URLEncoder.encode(textToTranslate,"UTF-8");
url = new URL("https://www.googleapis.com/language/translate/v2?key=" + apiKey + "&target=en&q=" + encoded);
Thanks,
Elior
You need to encode the text before pass as q parameter.
For example for the string שלום עולם:
String original = "שלום עולם";
String encoded = null;
try {
encoded = URLEncoder.encode(original, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
The value of the encoded variable will be %D7%A9%D7%9C%D7%95%D7%9D+%D7%A2%D7%95%D7%9C%D7%9D and the URL became:
"https://www.googleapis.com/language/translate/v2?key=" + apiKey + "&target=en&q=%D7%A9%D7%9C%D7%95%D7%9D+%D7%A2%D7%95%D7%9C%D7%9D"
When another application is sending a file to my app, I get a Uri via the intent.getExtras().get(EXTRA_STREAM) property. I can then get the bytes of the file using an inputstream : new BufferedInputStream(activity.getContentResolver().openInputStream(uri));
Everything's OK and working so far. Now I'd like to show some kind of progress to my user, but I'm not sure of how to get the total number of bytes of the file without reading the stream completely beforehand (which would defeat the whole purpose of the progress bar) ...
I tried ParcelFileDescriptor fileDesc = activity.getContentResolver().openFileDescriptor(uri, "r"); but this only works with uris of type file://....
For example If I receive a file from Skydrive I get a content://.. Uri, as in : content://com.microsoft.skydrive.content.external/external_property/10C32CC94ECB90C4!155/Sunset.480p.mp4
On such Uri I get (unsurprisingly) a "FileNotFoundException : Not a whole file" exception.
Any sure fire way to get the total size of the stream of data I will get ?
Even though InputStream.available() is (almost) never a recommended way of getting file size, it might be a viable solution in your case.
The content is already available locally. A server is not involved. So, the following should return the exact file size:
try {
InputStream inputStream = getContentResolver().openInputStream(uri);
Log.i("TEST", "File Size: " + inputStream.available());
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
I tested this with SkyDrive and Dropbox. The file sizes returned were correct.
There is no general solution for getting the size of a stream, other than reading the entire stream. This is easily proven: One could create a web server that, for some URL, generates a random stream of text that is terminated at a random time. (In fact, I'm sure such URLs exist, whether by design or not :-) In such a case, the size of the stream isn't known until the last byte has been generated, never mind received.
So, the stream size, if it is sent by the server at all, has to be sent in an application-specific manner.
I've never worked with SkyDrive, but a google search for its API turned up this link, which has the following example for Android Java apps:
public void readFile() {
String fileId = "file.a6b2a7e8f2515e5e.A6B2A7E8F2515E5E!141";
client.getAsync(fileId, new LiveOperationListener() {
public void onError(LiveOperationException exception, LiveOperation operation) {
resultTextView.setText("Error reading file: " + exception.getMessage());
}
public void onComplete(LiveOperation operation) {
JSONObject result = operation.getResult();
String text = "File info:" +
"\nID = " + result.optString("id") +
"\nName = " + result.optString("name");
resultTextView.setText(text);
}
});
}
Based on other examples on that page, I would guess that something like result.optString("size") (or maybe result.optInt("size") ?) would give you the size of the file.
I am trying to decode a name string which contains apostrophe. This name string is being parsed in an XML parser, so what I want to do is that the apostrophe should be displayed normally, rather than being displayed as '. I tried using the URLDecoder.decode(myString, "UTF-*"); to decode it but to no avail. From one solution posted on StackOverflow I found that we need to use the URLDecoder.decode() twice. However, even that is not working. The code that I am using is:
try {
temp = URLDecoder.decode("Wing's", "UTF-8");
nameOrg = URLDecoder.decode(temp, "UTF-8");
}
catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
At the end it should display Wing's as Wing's, but it is displaying the same string. Any help would be great. Thanks in advance.
Why don't you just decode it using Html.fromHtml(String source),
Spanned temp = Html.fromHtml("Wing's");
Log.d("decoded", temp.toString());
Output - Wing's