rn-fetch-blob on real iPhone failing to upload image (localhost testing) - ios

I'm using react-native-image-picker (^0.28.0) along with rn-fetch-blob (^0.10.15).
It works so far when using a Simulator, but when I use it on real iPhone, the image isn't uploading, it fails to upload with the following error that is being catched by the promise.
"Error: Could not connect to the server."
(Yes, server is up and running)
If you see this, you might think it's a backend issue but other requests work fine on real device, this one is the only having problems. The image request being sent is this one:
{
data: "RNFetchBlob-file:///var/mobile/Containers/Data/Application/843A96A1-0000-40D3-B50F-95D69B94B87A/tmp/5D22283B-2014-4E9E-AC3E-AE677D91A366.jpg"
filename: "IMG_6834.jpg"
name: "pictures"
type: "image/jpeg"
}
The only difference with the simulator device and my iPhone is the data path. Where on simulator is like "RNFetchBlob-file:///Users/marian-mac/Library/Developer/CoreSimulator/Devices/....etc"
Any idea why should be different from the simulator on this? It seems to be sending the same request.
Some extra info, when I preview the image in an Image component, it shows well too. So it seems the path is correct on the real iPhone.
This is the method to upload image
uploadPicture: function(data, token) {
return RNFetchBlob.fetch('POST', Constants.baseUrl + '/picture', {
Authorization: "Bearer " + token,
'Content-Type': 'multipart/form-data;boundary=***BOUNDARY***'
}, data);
},
And this is how I build the picture request array, this.state.images contains the image-picker data.
this.state.images.forEach((image) => {
reqData.push({
data: image.imageFile,
filename: image.fileName.split('.')[0] + '.jpg',
name: 'pictures',
type: image.type
})
});

The problem could be that you are uploading to a non-https url. Had this same issue and the nsAllowArbitraryLoads made it work on simulator and gave error when using it on a real device.
Had to wait until it became https

It does not seem to be the problem with http or https. (mine is http)
I'm having a file on this path:
filepath =/var/mobile/Containers/Data/Application/F8F06A2A-C04D-4B6D-A316-F879E144366B/Documents/test.wav
I tried RNFetchBlob.wrap(filePath) but no use.
So I tried to add this file to the asset of ios project and using RNFetchBlob.wrap(RNFetchBlob.fs.asset('test.wav')). Voila, it works.
As a result, it seems to be the problem with filepath

Related

IOS iPhone browsers does not accept video files via upload dialog

We are using IOS file upload dialog in order to use video files with our service using react.
All video files are working in android platforms and all browsers in linux and MacOS. However, when we use video files with upload dialog in IOS IPhones such as Iphone 14 Pro Max, then the compress process starts and following that the dialog rejects the video file.
We have been debugging with browserstack using a real phone in a simulator, however no luck until this point.
When we select the file, it firstly runs a compression activity then changes the name of the file to an intermediate file name (as below, the original file name is different), and then upload procedure fails.
Below is the react part which triggers upload mechanism which works with every platform and operating system with exception of IOS.
export const UploadVideo = async (file, signedurl, uploading) =>
{
let resultState = { state: '', data: {} };
if (SERVER_STATUS !== 'localhost')
{
await axios({
method: 'put',
url: signedurl,
data: file,
headers: { 'Content-Type': 'application/octet-stream', },
onUploadProgress: uploading
}).then(function (response)
{
resultState.state = 'success';
}).catch(function (error)
{
resultState.state = 'error';
resultState.data.message = error.message;
window.toastr.error(error.message);
})
} else resultState.state = 'success';
return resultState;
}
The error message I notice here, OS Status error -9806 refers to, according to osstatus.com a secure transport result code. More specifically this one, on Apple's documentation
My take here is that the system is not trusting this URL, I would suggest adding your URL to trusted domains under NSAppTransportSecurity in the Info.plist file. More info on how to do that here.
This is not a solution I would go for for a production app tho, you might want to have a valid certificate for your production URL and app.
Hope this helps.

React native version 63 image uploading issue

Missing request token for request: <NSURLRequest: 0x282528c80> { URL: file:///var/mobile/Containers/Data/Application/0EFA47FC-4E6B-45B2-98CF-8F43676E6AB4/Documents/signature.png }
Screenshot attached
Replace "file://" to "/private"
dataForm.append('file', { uri: Platform.OS=='ios'?photo.uri.replace("file://", "/private"):photo.uri, name: 'photo.jpg', type: 'image/jpg' });
IOS : photo.uri.replace("file://", "/private")
It only works for the real device, on simulator still give the error but at least you can deploy your app until this issue is patched

Video is uploaded as an image from iOS device, how to upload properly

I have an app that gets the images/videos from the mobile gallery, then uploads one of them to a server,
here are the steps i take, which works fine on Android:
1-get data from mobile storage:
MediaLibrary.getAssetsAsync({
first: 20,
mediaType: [MediaLibrary.MediaType.video, MediaLibrary.MediaType.photo]
})
2-upload to server:
formData.append('images[]', {
uri: localUri,
name: isVideo ? 'untitled.mp4' : 'untitled',//for testing
type: isVideo ? 'video/mp4' : 'image/jpeg'
})
axios.post(`url`, formData, {headers: headers,timeout:999999})
The problem is videos are uploaded as an image (only the first frame of the video), while it gets uploaded successfully on Android, the problem is only present on iOS.
The uri of the retrieved files is as follows:
assets-library://asset/asset.MP4?id=xxx&ext=MP4
Quick notes:
1 - the video is played fine locally using the <Video> component from Expo
2 - i tried using the CameraRoll API, but it gives the same results, and is a little buggy
any help would be appreciated
You can update to expo SDK 36 and you will be able to solve this problem by using localUri returned by MediaLibrary.getAssetInfoAsync
ex.
// get asset id like B84E8479-475C-4727-A4A4-B77AA9980897/L0/001
const info = await MediaLibrary.getAssetInfoAsync(asset.id)
const uri = info.localUri // use this for upload
Reffer this comment on github.
https://github.com/expo/expo/issues/3177#issuecomment-510096711

multipart/form-data not working on ionic iOS

I have an ionic 3 project that allows for file upload to the server. The following code is working fine from Android. But on iOS it appears to get blocked (i.e. the server code at /upload.php is obviously the same in both cases, but coming from iOS it does not receive any of the posted data).
this.http.setDataSerializer('urlencoded');
this.http.post("http://example.com/upload.php", {
name: this.filename,
data: this.datafile
}, {"Content-Type":"multipart/form-data"})
.then(res => {
console.log('success response: ' + res.data);
}, error => {
console.log(error: ' + error);
});
Any ideas?
Is there some setting in xCode that needs to be configured to allow multipart/form-data posts to work? Or perhaps somewhere to white list the domain to allow it?
Turned out to be on the server side. Apparently PHP receives the post differently from Android as it does iOS. $_REQUEST["xxxx"] works fine for Android but in order to work for both it required this:
$postdata = file_get_contents("php://input");
parse_str($postdata, $param);
// then available as $param["xxxx"]
Thought I'd update the answer here in case anyone else bumps into this. Awfully obscure and took me days to figure out!

Sending files from iOS app to server running on google app engine

My iOS app interacts with a google app engine backend. I have the option for user to report an issue. When user enters the text describing the problem and presses the Submit button, I want to start a background upload of the issue description plus logs being collected in the app using CocoaLumberjack.
My current approach (almost working) is as follows. iOS sends a multipart/form-data POST request that contains a String with bug description and log file content (NSData) with each part separated by a boundary. The GAE server is able to successfully decode each part and I am able to see the file content when I print it out using logging.info(). However, when I try to store the file to GCS, I get an error. The code used to store to GCS and error are below.
I have one storage bucket configured and this has class = Durable Reduced Availability.
Can someone point me to what I'm doing wrong (I suspect it is something about how I set up the authorization lists in the GCS container)?
Alternatively, I am all ears if someone has an easier way to solve this problem.
Code used to store into GCS is:
logging.info('Creating file %s\n' % (filename))
write_retry_params = gcs.RetryParams(initial_delay=0.2,
max_delay=5.0,
backoff_factor=1.2,
max_retry_period=15)
gcs_file = gcs.open(filename,
'w',
content_type='text/plain',
retry_params=write_retry_params)
gcs_file.write(filename=getattr(request, 'fileAttached'))
gcs_file.close()
Error seen in GAE:
ForbiddenError: Expect status [201] from Google Storage. But got status 403.
Path: '/var/mobile/Containers/Data/Application/4FB6C1D7-9504-4215-BC25-FC490298EEF6/Library/Caches/Logs/com.apm.smartiothome.chatime%202016-01-20%2008-01.log'.
Request headers: {'x-goog-resumable': 'start', 'x-goog-api-version': '2', 'content-type': 'text/plain', 'accept-encoding': 'gzip, *'}.
Response headers: {'content-type': 'application/xml; charset=UTF-8', 'content-length': '195', 'vary': 'Origin', 'x-guploader-uploadid': 'AEnB2Uo1b-z2VGlHOnurusG2F9bgKcBVwmYWZrQFG4d4NBrHA_tk9wTPoa4kB1Aici7XP7Z6fNtuSJlGDokUmxtCFAl8aMnXGA'}.
Body: "AccessDeniedAccess denied.Caller does not have storage.objects.create access to bucket var.".
Extra info: None.
I opened the menu "IAM & Admin" > Service accounts and copied the "Service account ID" from the row "App Engine default service account". The name was my app followed by "#appspot.gserviceaccount.com".
Next, I opened Storage and click the "..." next to the default bucket > Edit bucket permissions. I added the service account as a user with Writer access.

Resources