Copy link to clipboard
Copied
I am trying to use ActionScript's File.upload to upload a file on Air SDK for iOS environment, but the File.upload does not work properly. No handler about the file upload is executed after File.upload is invoked, and no exception is caught. When I check the network traffic of the server side, I found that no http request even hit the server after executing File.upload. The code is below.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
private var file:File;
private var dir:File;
//This method is executed to create a file and upload it when the Upload Button is pressed.
protected function OnUploadButtonPressed(event:MouseEvent):void{
trace("upload button clicked");
var urlReq:URLRequest = new URLRequest("http://10.60.99.31/MyPath/fileUploadTest.do");
urlReq.method = URLRequestMethod.POST;
var str:String = 'This is test';
var imageBytes:ByteArray = new ByteArray();
for ( var i:int = 0; i < str.length; i++ ) {
imageBytes.writeByte( str.charCodeAt(i) );
}
trace("size = " + imageBytes.length);
try{
dir = File.applicationStorageDirectory
//I also tested in several different directories
//dir = File.createTempDirectory();
//dir = File.documentsDirectory;
var now:Date = new Date();
var filename:String = "IMG" + now.fullYear + now.month + now.day + now.hours + now.minutes + now.seconds + now.milliseconds + ".txt";
file = dir.resolvePath( filename );
var stream:FileStream = new FileStream();
stream.open( file, FileMode.WRITE );
stream.writeBytes( imageBytes );
stream.close();
//Read back the file contents to check whether the file is written successfully.
var readStream:FileStream = new FileStream();
readStream.open(file, FileMode.READ);
var result:String = readStream.readUTFBytes(readStream.bytesAvailable);
trace("read back result = " + result);//The result is shown here as expected.
file.addEventListener( Event.COMPLETE, uploadComplete );
file.addEventListener( IOErrorEvent.IO_ERROR, ioError );
file.addEventListener( SecurityErrorEvent.SECURITY_ERROR, securityError );
file.addEventListener(ErrorEvent.ERROR, someError);
file.addEventListener(ProgressEvent.PROGRESS, onProgress);
file.upload( urlReq );//This line does not work. No handler is executed. No http request hit the server side.
trace("after file upload test");
} catch( e:Error ) {
trace( e );
}
}
//Complete Handler
private function uploadComplete( event:Event ):void
{
trace( "Upload successful." );
}
//IOError handler
private function ioError( error:IOErrorEvent ):void
{
trace( "Upload failed: " + error.text );
}
//SecurityError handler
private function securityError(error:SecurityErrorEvent):void{
trace( "Security error:" + error.text );
}
//Other handler
private function someError(error:ErrorEvent):void{
trace("some error" + error.text);
}
//Progress handler
private function onProgress(event:ProgressEvent):void{
trace("progressHandler");
}
//This method is executed to invoke the URLLoader.load when the Tricky Button is pressed.
protected function OnTrickyButtonPressed(event:MouseEvent):void{
var urlReq:URLRequest = new URLRequest("http://200.60.99.31/");//This points to a non-existed server
urlReq.method = URLRequestMethod.POST;
urlReq.data = new ByteArray();
var loader:URLLoader = new URLLoader();
try{
loader.load(urlReq);//This line seems very important in iOS7. It decides whether the latter file.upload can work.
//But in iOS8, file.upload does not work even if this line is executed.
trace("after urlloader load");
}catch(e:Error){
trace(e);
}
}
]]>
</fx:Script>
<s:Button x="200" y="200" width="400" height="200" label="Upload" click="OnUploadButtonPressed(event)" />
<s:Button x="200" y="500" width="400" height="200" label="Tricky" click="OnTrickyButtonPressed(event)" />
</s:View>
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
When executed on Air Simulator, it works fine as expected, and the file is successfully uploaded to the server. But When executed on iOS devices(in my case, iPad), as I explain early, no handler about the file upload is executed, and no the http request even hit the server. So I think the problem may be in the client side.
During my try to solve the problem, I found something tricky about this problem on iOS7. That is, if you invoke the URLLoader.load method (even if the URLLoader.load points to a non-existed address) before invoking the File.upload method, the File.upload will work as expected on iOS7. More specifically, when method OnTrickyButtonPressed above is executed before method OnUploadButtonPressed, File.upload will succeed on iOS7. But this only happens on iOS7. On iOS8, File.upload always refuses to work, regardless of whether the URLLoader.load is executed before.
I think in my case the problem is not the Sandbox problem or Firefox session problem described in the two links below, because not even any http request hit the server side. It seems that the Air SDK for iOS just failed to send the http request for some reason.
http://stackoverflow.com/questions/5967382/flex-4-filereference-issues-with-firefox
http://stackoverflow.com/questions/351258/how-do-i-make-flex-file-upload-work-on-firefox-and-safari
To make my problem more clear, I list my environment below:
Finally, I would like to mention that uploading file using URLLoader.load is not an option in my case because I want to upload large files in the future, which can not be handled with the URLLoader.load.
I have been struggling for this for days. So I really appreciate it if anyone has any idea about this.
Thanks in advance.
Hi KA RYU,
We have successfully reproduced the issue, our team would be working on this.
-Tushar
Copy link to clipboard
Copied
Moved to the development forum
Copy link to clipboard
Copied
Chris.campbell, thank you very much to move this article to the right place. Hope someone will help me about this.
Recently I tried the same code on iOS6, and it works good. So probably this is a bug of the SDK, or a incompatibility issue with iOS8 .
I will also report it to Adobe as a bug report.
Copy link to clipboard
Copied
Hi KA RYU,
We tried to reproduce the issue at our end. We tested with both AIRSDK 16 & 17, but it was found to be working fine for both iOS7 & iOS8, without using the above mentioned work-around (OnTrickyButtonPressed) . We could successfully upload the files to the web server. I am sharing the sample app that we made on the basis of code provided by you. Can you try reproducing the issue with the latest AIRSDK build?
Thanks,
Tushar
Copy link to clipboard
Copied
Hi, tdwivedi. Thank you very much for your reply.
After I checked the issue thoroughly, I found the that the real problem is not about my code,
it is about the http proxy Auto configuration, and this problem happened on iOS7 and iOS8,
not on iOS6. That is to say, the issue only happens on on iOS7 and iOS8 when you set your
[http proxy] in the wifi connection you use to [Auto],and input a URL that points to a *.pac file in your internal network.
To make it more clear, I listed below conditions under which the problem happens or not.
1. Http Proxy [Off]
2. Http Proxy [Auto] with a URL that points to a *.pac file in your internal network.
Firstly, I had thought that iOS7 and iOS8 does not process the proxy Auto configuration file correctly,
but then I found that doesn't make sense considered the following questions.
1. Why URLLoader.load works, while File.upload does not? (Just like File.upload, URLLoader.load also needs to get the *.pac file when the application tries to access network for the first time. )
2. And why my browsers(Safari and Chrome) work fine with the same pac file.
So I thing the problem is in File.upload instead of iOS.
Then I tried to capture packets from iOS7 and iOS8, and found that URLLoader.load did send a http request to
the server in the internal network that hosts the pac file (Let us call it pac server). On the other hand,
File.upload's communication with the pac server failed in the TCP layer , so no http request was sent.
(I am sure that there is no firewall in the pac server that is trying to block the request.)
But on iOS6, both URLLoader.load and File.upload successfully sent the http request to the pac server,
and as a result, everything works as expected.
So, in a word, I think that File.upload and URLLoader.load maybe use the different iOS APIs when trying to access the pac file, and the API which File.upload is using is no longer working after the iOS is updated to 7 or 8. Maybe File.upload should be modified to use the same ios API with whichever API URLLoader.load is using.
I uploaded my latest project file in the following link. Will you please check it. I think the same problem will also happen to you if you set [http proxy] to [Auto].
https://github.com/bluewindjava8/upload
Thank you very much.
Copy link to clipboard
Copied
Hi KA RYU,
Thank you for the information provided.
It's always great to work with someone who is ready to provide such details of the issue.
I will try to simulate such scenario. Will use your sample project as well for the investigation.
-Tushar
Copy link to clipboard
Copied
Hi, Tushar
Thank you very much for your reply. So I look forward to your next message.
Just for you to reproduce the issue easily, I list below the precise versions of iOS and devices I used.
Thanks, again.
Copy link to clipboard
Copied
Hi KA RYU,
We have successfully reproduced the issue, our team would be working on this.
-Tushar
Copy link to clipboard
Copied
Hello Tushar,
This problem looks a lot like a bug I submitted here "Bug#3997814 - flash.filesystem.File.Upload does not use the system proxy on iOS and Android"
Is it the same thing ? If yes, could you please give the info to your team ? Or give me a link to a bug that I could upvote ?
And do you have any idea when this bug will be fixed ?
Many Thanks,
Sebastien
Copy link to clipboard
Copied
Hi sebastienn1596843 ,
Please vote on the same bug that you have raised as there isn't any bug filed for this issue. We could reproduce the issue, but due to many other higher priority tasks at hand our team will be picks up the bug for fixing if there are substantial votes on the bug.
-Tushar,
Adobe AIR team
Copy link to clipboard
Copied
Thanks Tushar,
I can not vote for my own bug ... let's just say that this bug probably won't be fixed, so that people reading this thread don't get their hopes to high when they read "our team would be working on this".
People if you want this bug fixed, vote for the bug here : Bug#3997814 - flash.filesystem.File.Upload does not use the system proxy on iOS and Android"
Thanks anyways
Sebastien
Copy link to clipboard
Copied
It looks like the bug has been marked "Closed/NeverFix". People were reporting it as late as AIR 18 I believe. Is there anyone who has made this work successfully on iOS or Mac? I am thinking about trying upload via FileReference (along the lines of here: https://discuss.as3lang.org/t/send-a-file-to-a-server-as-an-attachment-in-an-urlrequest-urlloader/32...), rather than File.upload(), but I don't know if that will make any difference.
Copy link to clipboard
Copied
this is working for me
var file:File = selectedFile;
var multi:String = "-----------------------------" + nonce;
var pre:String = multi + "\r\nContent-Disposition: form-data; name=\"fname\"; filename=\""
+ text + "\"\r\nContent-Type: application/octet-stream\r\n\r\n";
var post:String = "\r\n" + multi + "\r\nContent-Disposition: form-data; name=\"nonce\"\r\n\r\n"
+ nonce + "\r\n" + multi + "--\r\n\r\n";
var urlRequest:URLRequest = new URLRequest(uploadURL);
urlRequest.method = "POST";
var header:URLRequestHeader = new URLRequestHeader("Content-Type",
"multipart/form-data; boundary=" + multi.substr(2));
urlRequest.requestHeaders.push(header);
var readStream:FileStream = new FileStream();
readStream.open(file, FileMode.READ);
var data:String = readStream.readUTFBytes(readStream.bytesAvailable);
urlRequest.data = pre + data + post;
var loader:URLLoader = new URLLoader();
loader.load(urlRequest);