iOS / Phonegap : using FileTransfer response - ios

first, sorry if my english is bad.
Then, here is my issue:
I try to make an app for iOS with PhoneGap 2.8.1 . Evrything is going well on Android, now I just want to move my code on Xcode to compile on iPad or iPhone.
The probleme I have is with FileTransfer, when I upload an image. The transfer itself has no problem, as it finishes with a response code 200, so it's a success.
Then, my serve is supposed to return back an XML file, handled by the javascript code. The server works fine, because I have absolutly no problem with Android devices.
So, I made a lot of tests, and it appears that the app has a problem with the success callback or the FileTransfer.upload(). When I just put a simple console.log('success') in this callback function, it's fine. But when I try to use the FileUploadResult object, nothing happens.
And the weirdest thing is, that when I press the main button of the iPad or iPhone, in order to close my app, I see all my logs displayed in the debug window, such as console.log("Code = " + r.responseCode);, like in the PhoneGap example. And here, I can finally see that I actually receive the server response, but it's like something blocks it until I close the app.
Here is that part of the code :
function onPhotoDataSuccess(imageURI) {
console.log("---> Image: "+imageURI);
// File Transfer
var options = new FileUploadOptions();
options.fileKey="file";
options.chunkedMode = false;
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
var ft = new FileTransfer();
ft.upload(imageURI, encodeURI(window.localStorage.getItem("wsURL")), win, fail, options);
// Transfer succeeded
function win(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
// Handle the XML response
}
else {
alert("No response. Please retry");
}
}
// Transfer failed
function fail(error) {
alert("An error has occurred: Code = " + error.code);
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}
}
Thanks for your help

Related

Ionic - Some functionnalities are not working while compiling on IOS

Context:
Hello, I am working on a Ionic application (made in Typescript). In this application, I control a wifi camera via HTTP Request to the IP (http://192.72.1.1/myCommand to be precise).
Main actions I do with the camera:
Start recording
Stop recording
Get videos list
Download a video
When I use the Ionic DevApp:
With the Ionic DevApp, everything works perfectly, I can do all mains actions without a problem.
When I compile the application on IOS:
I compile with the command ionic cordova build ios --prod, then I archive with Xcode and send it to the AppStore to test it with Test Flight.
I got no errors while compiling / archive the application. But when I try it on my iPhone, I can start / stop recording, but can't download the video.
Problem:
Some commands are not working, but I don't know if it is getting the list or downloading the video, I have no logs. I don't understand why some commands are working but others no.
IOS is blocking download requests? How to solve my problem?
Notes:
I already tried all basic things like delete the IOS platform, recompile, uninstall, ...
I tried different Ionic HTTP plugins, same problem with all of them.
Some code:
Start / Stop the camera: (it is the same command to start / stop).
startCamera(){
var url = "http://192.72.1.1/changeRecordStatus";
var result = this.http.get(url);
result.subscribe(data => {
console.log("Works");
},
err => {
console.log("Error" + err);
}
);
}
Getting the name of the last video:
getLastVideo(){
var url = "http://192.72.1.1/listVideos";
this.http.get(url, {}, {})
.then(data => {
var xml = data.data
var xmlDOM = new DOMParser().parseFromString(xml, 'text/xml');
var temp = this.xmlToJson(xmlDOM); // function that convert XML to JSON
var resultArray = Object.keys(temp).map(function(i){
let ite = temp[i];
return ite;
});
resultArray = resultArray[0]['file'].reverse();
this.lastVideo = resultArray[0]['name']; // lastVideo is a global variable
},
(error) =>{
console.log("Error while getting the name of the last video" + error);
});
}
Downloading the file from the camera:
downloadFileFromCamera() {
this.getLastVideo();
var basename_file = this.lastVideo;
var url = "http://192.72.1.1" + basename_file;
this.fileTransfer.download(encodeURI(url), this.file.dataDirectory + '/videos/' + basename_file, true).then((entry) => {
this.video[this.counterVideos] = entry; // video is a global array
this.counterVideos +=1;
}, (error) => {
console.log("Error while downloading the last video" + error);
});
}
If someone knows how to solve my problem, I would be so grateful! Thanks in advance.

ActionScript's File.upload does not work on Air SDK for iOS devices

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

ionic framework bad request when calling web service over 3G

I'm developing iOS app using ionic framework and I have one problem when I try to call web service by using 3G network.
here is my service in UserService:
function getUserStat(user_id){
var request = $http({ method: "get",
url: "http://www.example.com/user.php",
params: {
action: "stat",
user_id:user_id
},
data: {
}
});
return(request.then(handleSuccess, handleError));
}
function handleError( response ) {
// The API response from the server should be returned in a
// nomralized format. However, if the request was not handled by the
// server (or what not handles properly - ex. server error), then we
// may have to normalize it on our end, as best we can.
if (!angular.isObject( response.data ) || !response.data.message) {
return( $q.reject("An unknown error occurred.") );
}
// Otherwise, use expected error message.
return( $q.reject( response.data.message ) );
}
// I transform the successful response, unwrapping the application data
// from the API response payload.
function handleSuccess( response ) {
return( response.data );
}
the getUserStat() function will return json back.
here is my controller
UserService.getUserStat($scope.user_id).then(function(data){
alert("Result: " + JSON.stringify(data));
});
in my control I just show the json.
I build this code to my iPhone and test it over WIFI network, everything work fine. If i update the serverside, UserService.getUserStat in controller will show update. but the problem is when I test it on 3G network, iPhone always show the old json returned from the server (even I change server side data).
any idea to solve this problem?
Thank you
I had a similar problem when I tried to upload a camera photo to my data server.when i tested the app on my local WIFI it worked perfectly but when I tested it outside i noticed it fails to upload the file. eventualy the problem was that since the internet outside is much slower the app moved to another view without finish the upload action.
so for example if your controller looks something like this:
.controller('Ctrl1', function(webService, $scope, $state) {
UserService.getUserStat($scope.user_id).then(function(data){
alert("Result: " + JSON.stringify(data));
});
$state.go('app.posts');
});
it should be like this:
.controller('Ctrl1', function(webService, $scope, $state) {
UserService.getUserStat($scope.user_id).then(function(data){
alert("Result: " + JSON.stringify(data));
})
.finally(function() {
$state.go('app.posts');
});
});

Titanium Studio to Grails imge post

I am trying to POST an image to my grails application and I'm not having much luck.
My titanium code is:
function upload(){
var xhr = Titanium.Network.createHTTPClient();
xhr.onerror = function(e){
Ti.API.info(picMedia + " : " +message.value);
Ti.API.info('IN ERROR ' + e.error);
alert('Sorry, we could not upload your photo! Please try again.');
};
xhr.onload = function(){
Ti.API.info('IN ONLOAD ' + this.status + ' readyState ' + this.readyState);
};
xhr.onsendstream = function(e){
Ti.API.info('ONSENDSTREAM - PROGRESS: ' + e.progress);
};
// open the client
xhr.open('POST', 'http://localhost:8080/FYP/Profile/appUploader');
// send the data
xhr.send({
media: picMedia,
message: message.value,
});
}
My grails code is as follows:
def appUploader(){
println "MEDAI PARAMS: " + params.media
def f = request.getFile('media') ;
println "HERE: " + f
if (request.getFile(params.media).getOriginalFilename()) {
println "FROM APP: " + request.getFile('myFile').getOriginalFilename()
return
}
}
Im getting error from the mobile app and error on the "if" line in the web app.
What am i doing wrong?
we had the same problem in one of our apps. The difficulty is that titanium is not really able to handle binary files in that case.
We did the following:
create base64 encoded string of the image on client side
post this string to the backend
decode base64 to image again
We analyzed a lot of network traffic and in most cases titanium tries to send the file but due to javascript its alway converted into some kind of ascii and this is not usable by the server side.

Async web service call in custom list adapter

I have a problem when calling web service asynchronously in Monodroid. The call seems to work correctly, but the application crashes everytime when I process the response. Program behaves differently when I run it in emulator and when I run it on my phone (Samsung Galaxy S w 2.2.1 FROYO.XWJS8). I am thinking of creting the Threads by myself, but don't know if it solves the problem. The same code works fine when used in Windows Phone 7 application.
The code for Async method call is (note: in reality ShowMessage calls write to Android.Util.Log.Debug)
private void callws(string _input)
{
MessageBox.GetInstance().ShowMessage("Search async started, input: " + _input);
m_waitingrequest = new RequestStatus() { Waiting = true, NewestInput = _input, OriginalInput = _input };
connectormobile.UserInformation ui = new connectormobile.UserInformation()
{ UserName = m_appsettings.GetValue<string>(AppSettings.WS_USERNAME_NAME), Password = m_appsettings.GetValue<string>(AppSettings.WS_PASSWORD_NAME) };
MessageBox.GetInstance().ShowMessage("Username: " + ui.UserName + " Password: " + ui.Password);
m_client.SearchAsync(ui, _input);
MessageBox.GetInstance().ShowMessage("After search async call, input: " + _input);
}
Search Async result function starts with:
void m_client_SearchCompleted(object sender, connectormobile.SearchCompletedEventArgs e)
{
MessageBox.GetInstance().ShowMessage("Search async completed");
SearchCache.CacheElement element = new SearchCache.CacheElement();
element.SearchCriteria = m_waitingrequest.OriginalInput;
element.PartialResponse = e.Result.PartialResponse;
if (e.Result.CompanyNameInfoArray == null)
element.Rows = new List<connectormobile.CompanyNameInfo>();
else
element.Rows = e.Result.CompanyNameInfoArray.ToList();
MessageBox.GetInstance().ShowMessage("Search async returned, partial response: " + e.Result.PartialResponse
+ " row count: " + element.Rows.Count + " return value: " + e.Result.ReturnValue.ErrorDescriptionFi);
}
This is where the program behaves differently. In emulator the code never reaches the first line of SearchCompleted. But in my phone the SearchCompleted function seems goes through (at least all my debug lines are in trace), but after that the user interface freezes. (and after minute it says process not responding)
You are likely trying to modify the UI from the background thread instead of the UI thread. Use RunOnUIThread () to do your UI logic on the correct thread:
http://mono-android.net/Documentation/Guides/Writing_Responsive_Applications

Resources