Uploading images in React Native using FormData on Android - android

I have been working on a mobile app for the past year, and are preparing to deploy to production. Our app is used for sending applications for a certain license, and some users may be required to upload images in their application.
This feature has been implemented and working for many months, and given us no issues. However, now the Android version of the app is causing problems. When we submit the application, the fetch request to the endpoint is initiated, but never actually hits (only if images are included in the application).
Here is the code where the images are handled:
const xhr = new XMLHttpRequest()
xhr.responseType = 'blob'
xhr.onload = () => {
const file = xhr.response
const extension = file.type.split('image/').pop()
const fileName = `${field.identifier}-${docCounter}.${extension}`
if (Platform.OS === 'web') {
formData.append('filesToUpload', file, fileName)
} else {
formData.append('filesToUpload', {
uri: fileInfo.uri,
type: `image/${extension}`,
name: fileName,
})
}
//Other unrelated code
}
xhr.open('GET', url)
xhr.send()
Then the request:
const task = await fetch(
new Request(`${Constants?.manifest?.extra?.hostname}/ext/tasks`, {
method: 'POST',
}),
{
body: formData,
headers,
}
)
The headers just includes an authorisation token related to the user submitting the application.
So yeah, on web and iOS, this processes with no issue, but on Android, it starts the request, but never hits the endpoint.
Any help would be appreciated.
EDIT
I have been doing some debugging, and I think the issue is that the the file is not giving me a type from the blob, so in my formData type: 'image/${extension}', the extension does not exist.
So I logged the file object on both Android and iOS, and this is what I got.
iOS
{"_data": {"__collector": {}, "blobId": "1B56DE00-DDE9-494A-B57A-343040B6D12B", "name": "users_zw3GBtId4O0m0FAtpc94AUgBchPU_mutable_b293b904-6711-4384-a1c2-e540f5d6c1f8.png", "offset": 0, "size": 455495, "type": "image/png"}}
Android
{"_data": {"__collector": {}, "blobId": "11a2875e-903c-4f87-a997-7e31c7013cfb", "offset": 0, "size": 179757}}
So as yo can see, the iOS app is giving me more data, and also the extension of the file.
I still don't know why this is the case.

Related

On android app built with Capacitor, error ERR_CONNECTION_REFUSED after redirect on local url

I'am developping a Vuejs project (vue 2.6.11) and I want to build an android app from it.
For that, I'am using capacitor : "#capacitor/android": "^3.4.0" and "#capacitor/core": "^3.4.0".
The app is OK, I can run it with android studio but I've got an error in my login flow because of a web redirection : Following is the user journey :
app open web content on https://localhost/home
user click on Login button, that send a request to my distant server
this request respond a 302 code and try to redirect to a local web url : https://localhost/login
The app cannot load https://localhost/login and I've got a net: ERR_CONNECTION_REFUSED
I expect my app to load the webpage that my vue rooter render at this URL '/login'.
This is my capacitor.config.json :
{
"appId": "com.XXX",
"appName": "XXXX",
"bundledWebRuntime": false,
"server": {
"allowNavigation": [
"SERVERURL"
],
"androidScheme": "https"
},
"webDir": "dist"
}
There are plenty topics on the web about ERR_CONNECTION_REFUSED error with capacitor but nothing seems relevant to my prolem.
Thanking you,
Jonath
I have achieved a workaround.
I have used https://github.com/apache/cordova-plugin-inappbrowser
let ref = cordova.InAppBrowser.open('https://google.com', '_blank', 'location=yes');
let myCallback = function (event: any) {
console.log('Updated URL: ', event.url);
// separate host form url
let host = event.url.split('/')[2];
// get pathName after host
let pathName = event.url.split(host)[1];
console.log('Path: ', pathName);
if (host === 'yourdomain.com') {
console.log('InAppBrowser closed');
ref.close();
setTimeout(() => {
this.$router.push(pathName);
}, 500);
}
}
ref.addEventListener('loadstart', myCallback);
Try to change localhost to your [local-ip-address]:[port] or 10.0.2.2:[port].
I'm not familiar in capacitor, but I've built my android app via flutter, and I found out that in android I need to use the ip 10.0.2.2 in my url.

"TypeError: Network request failed" (React Native) Android fetch fails to work with local backend

I am trying to fetch from my react native app using my local backend, and it keeps failing. The fetch doesn't even hit my backend, I made debug messages and tested on my browser to make sure the rest api worked. It works on iOS. I am also able to access other websites, so the internet works on the emulator.
UPDATE: After further debugging and trying other fetch requests, I have found a different error, maybe they are related?
error Could not open fetch.umd.js in the editor.
info When running on Windows, file names are checked against a whitelist to protect against remote code execution attacks. File names may consist only of alphanumeric characters (all languages), periods, dashes, slashes, and underscores.
I've already added "android:usesCleartextTraffic="true" in my AndroidManifest.xml. I have also tried upgrading my react native to version 63.4 but the problem persists.
It prints to console "[GET] http://127.0.0.1:8090/api/v1/user/check/email/test#gmail.com" but then the app gets
"TypeError: Network request failed"
immediately after.
When I try that URL in my browser, it properly prints
{"transok":"0","errno":"001003","errmsg":"","timestamp":"1612157175224","data":{}}
I've spent days in frustration on this, if anyone could lead me in the right direction I would be unimaginably greatful. Please let me know if any more information is needed, I will edit this question to provide the details
This is the code for the fetch which doesnt work:
const APP_SERVER_HOST = 'http://127.0.0.1:8090';
const API_BASE = APP_SERVER_HOST + '/api';
const API_VERSION = '/v1';
const API_HOST = API_BASE + API_VERSION;
isEmailExist(callback) {
var url = API_HOST + '/user/check/email/'+this.state.email;
var options = {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
};
console.log('[GET] ' + url);
//url is http://127.0.0.1:8090/api/v1/user/check/email/test#gmail.com
//url should post {"transok":"0","errno":"001003","errmsg":"","timestamp":"1612157175224","data":{}}
fetch(url, options).then((response) => response.json())
.then((responseData) => {
var retCode = responseData.errno;
console.log('[RTN] ' + responseData);
console.log('[RTN] ' + JSON.stringify(responseData));
if(retCode == Env.dic.ERROR_EMAIL_NOT_REG) {
console.log('[RTN] error email not reg');
return callback(false);
} else if(retCode == Env.dic.ERROR_EMAIL_EXIST){
console.log('[RTN] error email exist');
return callback(true);
}
}).done();
}
127.0.0.1 represents the emulator's localhost address. If you want to hit your machine's localhost you'll have to replace it with 10.0.2.2.
See Android docs for more information on why this is the case.

react-native fetch throws "Network request failed" error on Android Devices with backend in http remote server

i used node js as a backend in a remote server(not localhost) with "188.226.146.190:3000/api/meetups", but i got network error in android 5.1 physical devise and return undefined as output of api,what should i do? i used a simple get requset to my api. i test an example api "https://jsonplaceholder.typicode.com/users" and it works properly with this test api.
i have an api file:
export const fetchMeetups = () =>
fetch('http://188.226.146.190:3000/api/meetups')
.then(res => res.json()).catch((e) =>e);
and in the app.js:
static defaultProps = {
fetchMeetups
}
state = {
loading: false,
meetups: []
}
async componentDidMount() {
this.setState({
loading: true
});
const data = await this.props.fetchMeetups();
setTimeout( () => this.setState({loading: false, meetups:
data.meetups}),2000);
}
and in the android i got this error:
Network request failed
Network request failed normally means the the server was not reachable.
To get more information about failures like this you can add Stetho to your project. It allows you to see failures in the network tab of your browsers and examine them like you would do in the tests.
The React Native docs have a detailed section about this at debugging#debugging-with-stetog.
In your case I would assume that the IP of your service is not up-to-date anymore, you might want to check this.

Parse open source server cloud code not working the same as old

I went from using the old parse cloud code to open source parse server on AWS and this part of the main.js does not work.
var Stripe = require('stripe');
Stripe.initialize('sk_live_mylivekey');
var Mailgun = require('mailgun');
Mailgun.initialize("mydomain.mailgun.org");
Native Cloud code modules like Stripe, Mailgun, Sendgrid, Twilio etc. are not available in the open sourced Parse server.
Use official npm modules for the same:
Stripe npm module
Mailgun npm module
Reference: Migrate an existing Parse app - Github
Note:
Because the Parse hosted Cloud Code isn’t running a full node environment, there may be subtle differences in how your Cloud Code runs in Parse Server. We recommend exercising all your critical code paths to ensure full functionality.
I switched from using cloud code for making charges to creating a route in my index.js file for making charges. In index.js create a route as such
var stripe = require('stripe')('sk_test_****');
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: false
}));
app.post('/charge', function(req, res){
var token = req.body.token;
var amount = req.body.amount;
stripe.charges.create({
amount: amount,
currency: 'usd',
source: token,
}, function(err, charge){
if(err)
// Error check
else
res.send('Payment successful!');
}
});
I call this route using jQuery post however, you could also call it in a form
var handler = StripeCheckout.configure({
key: 'pk_test_****',
locale: 'auto',
token: function(token){
$.post('/charge', {
token: token.id,
amount: total,
}, function(data, status){
alert(data);
});
}
});

How to attach file to email in Ionic Framework Android?

I'm using Ionic Framework to build an iOS / Android app which writes sqlite data to a CSV file, then attaches that file to an Email and sends it. The following code works correctly on iOS (actual device iPhone 5).
I don't have an Android device, but in the Android emulator (nexus 5), the file sent never has a file attachment (despite the emulator showing that it does).
Is there a different way I should be writing this code?
I looked at the documentation here, but it does not clarify
https://github.com/katzer/cordova-plugin-email-composer#adding-attachments
$cordovaFile.writeFile(cordova.file.dataDirectory,
"PatientEncounters.csv",
data.join("\n"),
true)
.then(function (success) {
$cordovaEmailComposer.isAvailable().then(function() {
var emailOpts = {
to: [email],
attachments: ['' +
cordova.file.dataDirectory.replace('file://','') + "PatientEncounters.csv"],
subject: 'Patient Encounters',
body: 'A CSV containing Patient Encounters is attached',
isHtml: false
};
$cordovaEmailComposer.open(emailOpts).then(null, function () {
// user cancelled email
});
return;
}, function (error) {
return;
});
}, function () {
// not available
});
My problem was using cordova.file.dataDirectory instead of cordova.file.externalDataDirectory. The mail app in android would not allow attaching files from internal storage.

Categories

Resources