ActionScript 的 File.upload 在 Air SDK for iOS 设备上不起作用



我正在尝试使用ActionScript的File.upload在iOS环境的Air SDK上上传文件,但File.uplod无法正常工作。调用file.upload后,不会执行任何有关文件上载的处理程序,也不会捕获任何异常。当我检查服务器端的网络流量时,我发现在执行File.upload后,甚至没有http请求击中服务器。代码如下。

<?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>

在空中模拟器上执行时,它可以正常工作,并且文件已成功上传到服务器但是当在iOS设备(在我的情况下是iPad)上执行时,正如我前面解释的,没有执行关于文件上传的处理程序,也没有http请求事件到达服务器所以我认为问题可能出在客户方面。

在我试图解决这个问题的过程中,我在iOS7上发现了一些棘手的问题。也就是说,如果在调用File.upload方法之前调用URLLoader.load方法(即使URLLoader.load指向不存在的地址),File.uplod将在iOS7上按预期工作。更具体地说,当上面的方法OnTrickyButtonPressed在方法OnUploadButtonPressed之前执行时,File.upload将在iOS7上成功。但这种情况只发生在iOS7上。在iOS8上,无论URLLoader.load之前是否执行过,File.upload总是拒绝工作。

我认为在我的情况下,问题不是下面两个链接中描述的Sandbox问题或Firefox会话问题,因为甚至没有任何http请求到达服务器端似乎是iOS版的Air SDK由于某种原因未能发送http请求

Firefox 的Flex 4文件参考问题

如何在firefox和safari上上传Flex文件?

为了让我的问题更清楚,我在下面列出了我的环境:

  • 开发环境:Windows7(64位)/Mac os 10.9.4(测试于两个操作系统平台。)
  • IDE:Flash Builder 4.7
  • Air SDK:3.8/16.0(在我更新到最新的Air SDK 16.0.0之后,问题仍然存在。)
  • 应用程序服务器:Tomcat7+Spring

最后,我想提到的是,在我的情况下,使用URLLoader.load上传文件不是一个选项,因为我想在未来上传大文件,这是URLLoader.load.无法处理的

我已经为此奋斗了好几天了。所以,如果有人知道这件事,我真的很感激。提前谢谢。

最后我发现真正的问题不是我提供的代码,而是http代理的自动配置,这个问题发生在iOS7和iOS8上。我在下面的链接中详细描述了这个问题和解决方法。希望这能帮助到你们中的一些人。

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

最新更新