ActionScript's File.upload does not work on Ai

2019-03-06 10:49发布

问题:

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 event 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.

Flex 4 FileReference Issues With Firefox

How do I make Flex file upload work on firefox and safari?

To make my problem more clear, I list my environment below:

  • Develoment Environment: Windows7 (64bit) / Mac os 10.9.4 (Tested on two OS platforms.)
  • IDE: Flash Builder 4.7
  • Air SDK: 3.8 / 16.0.0 (After I updated to the lastest Air SDK 16.0.0 , the problem still exists.)
  • Application Server: Tomcat7 + Spring

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.

回答1:

Finally I found that the real problem is not about the code I provided, it is about the http proxy Auto configuration, and this problem happened on iOS7 and iOS8. I described the problem and a workaround in detail in the following link. Hope this will help some of you.

https://forums.adobe.com/thread/1716036