I want to convert my angular web app to mobile app.
I understand how works cors in web, there is just need to set port in frontend and the same port and url in backend allowedOrigins settings. But I can't understand how does work cors in mobile app because IP is different in each mobile device, not static like in frontend.
I can config in my computer something like this:
In server:
app:
auth:
cors:
allowedOrigins: http://127.0.0.1:8100,
In mobile app (capacitor.config.ts):
import { CapacitorConfig } from '#capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.my.app',
appName: 'my-mobile',
webDir: 'dist/my-mobile',
bundledWebRuntime: false,
server: {
cleartext: true,
hostname: '127.0.0.1:8100',
}
};
export default config;
And this works, but in locale, how to do it in prod, on real android devices?
I got answer here https://forum.ionicframework.com/t/how-works-cors-in-capasitor-on-real-devices/230474
In prod, the apps run at the following URL/origin by default:
iOS: capacitor://localhost
Android: http://localhost
So, both of those need to be configured in your backend as allowed origins. You could also use Capacitor’s HTTP plugin to get around CORS all together.
Related
I'm developing a Vue-cli + Node (express) application, Vue-cli is running on port 8080 and my node server in port 3001, both on localhost.
When I test my app in my desktop it works just as expected, I can navigate the entire app without issues, the problem appears when I test it on android, for all request the frontend does to the backend I get this error whether using fetch or axios:
<whatever rest verb> https://localhost:3001/<whatever endpoint> net::ERR_CONNECTION_REFUSED
My axios instance:
const http = axios.create({
baseURL: 'https://localhost:3001',
withCredentials: true
});
And this is the relevant node server configuration:
const corsOptions = {
origin: 'https://<my local ip>:8080',
credentials: true,
};
app.use(cors(corsOptions)); // <-- this is located before any other express middleware
I'm setting credentials in both part because I'm using passportjs and cookie-session to handle login, but this issue is present even in a simple GET request, also I already tried without setting credentials but the issue persists.
Axios version 1.2.1
cors middleware version 2.8.5
The solution was to use the local ip (as oppose to localhost) also in the baseUrl for the axios instance:
const options = {
baseURL: 'https://<your local ip>:<your api's server port>',
withCredentials: true
}
I'm working on a proof of concept for my company to demonstrate how our monorepo could benefit from Nx/Capacitor. So far, in my poc, I have a simple Nx monorepo with a backend app serving a couple of APIs, and I also have a React frontend connecting to the APIs, based on which I'm generating Android and iOS hybrid mobile apps with Capacitor using nxtend plugin for Nx (https://nxtend.dev/docs/capacitor/overview)
I'm not able to figure out how to make the Android and iOS applications running in the virtual devices to connect to the backend server in my development machine. When I access the web application in a browser in the development machine (and even in the browser of the virtual device), I get the result of the API, but from within the Android application, the API call returns the html file below instead. I tried switching out fetch with axios and capacitor-community/http in my React code to make http requests and still wasn't able to get the right response in the generated hybrid mobile apps with any of them (while the web app works fine in the browser in all cases). What could I be missing?
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript">window.Capacitor = { DEBUG: true, isLoggingEnabled: true, Plugins: {} };
window.WEBVIEW_SERVER_URL = 'http://localhost';
/*! Capacitor: https://capacitorjs.com/ - MIT License */
/* Generated File. Do not edit. */
const nativeBridge = (function (exports) {
'use strict';
// For removing exports for iOS/Android, keep let for reassignment
// eslint-disable-next-line
let dummy = {};
const initBridge = (w) => {
const getPlatformId = (win) => {
var _a, _b;
if (win === null || win === void 0 ? void 0 : win.androidBridge) {
return 'android';
}```
I am using the axios package to send API requests from my app to my backend
The backend is built with Laravel and is a simple rest API
If I run the Ionic app on desktop using ionic serve it works fine
If I build an APK and install the app:
on an Android device with version 8 or below it works fine
on an Android device with version 9 or above the preflight checks keep failing
(This is using the remote devices feature by Chrome to inspect requests from the app)
Initially, the requests wouldn't even send and it would error out before then and so I setup my network security configuration for Android and that removed the initial error but now it keeps failing on preflight
My suspcion is that it might be related to the fact that the requests on the app are being sent from http://localhost but I'm not sure how to resolve this. Can you force it to use an SSL? If so, how?
My CORS setup for Laravel is more leniant than the default CORS config that Laravel ships with:
return [
'paths' => ['*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];
The issue was related to SSL/TLS pinning which axios doesn't deal with as per this comment.
The Ionic Native HTTP plugin handles the pinning natively and that worked for but of course it makes use of Cordova which isn't available on your non-mobile devices.
There were two potential solutions:
Implement SSL/TLS pinning natively
Create a service/factory which determines whether we want to use axios or the native plugin
I opted for #2 - if you want information regarding #1, see this answer.
The following method for me determines which HTTP wrapper to use:
static makeRequest() {
return isPlatform('cordova') ? cordovaHttpService : axiosHttpService;
}
Of course, that can be amended with each specific case.
I have a working react-native app installed in my mobile device. Also, I have an REST server running in my machine.
GOAL
I want that the app should communicate to the REST api server. I am trying to use REST method to fetch data from the site.
PROBLEM/MOTIVATION
I was able to use my router's IP address as connection for the app and api.
Below are the URLs that can be accessed in both mobile browser and my machine/laptop browser.
Api browser debugger-ui runs in
http://192.168.254.106:8081/debugger-ui
REST server runs in
http://192.168.254.106/open_social
Things I've done so far:
I modified the app using jsonapi(waterwheel) code to fetch or update data from the site.
const Waterwheel = require('waterwheel');
const waterwheel = new Waterwheel({
base: 'http://192.168.254.106/open_social',
timeout: 10000,
oauth: {
grant_type: 'password',
client_id: '2249cb82-98d8-49ea-a32b-a7cff7912a7e',
client_secret: 'admin',
username: 'admin',
password: 'n8hBtuFY8R',
scope: 'administrator'
}
})
waterwheel.jsonapi.get('node/test', {}, "1cc692b8-c37c-4ee7-942f-b2e6b8276f35")
.then(res => {
console.log(res)
console.log('Success..!')
})
.catch(err => {
console.log(err)
})
Waterwheel is a module added in the node_modules folder in my app when running npm install waterwheel
CORS are also enabled in my api:
cors.config:
enabled: true
allowedHeaders: ['Content-Type', 'Access-Cntrol-Allow-Headers', 'Authorization']
allowedMethods: ['POST', 'GET', 'OPTIONS', 'PATCH', 'DELETE']
allowedOrigins: ['*']
exposedHeaders: true
maxAge: false
supportsCredentials: true
Manifest permission is also enabled
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Expected result: I should be able to get response from the REST api server when this code is added in the app.
I think there is no connection made from the app and api that I need to resolve and need help from this.
TIA
Are you testing on IOS device? check this!
PS: I don't have enough reputation to make a comment
By default, iOS will block any request that's not encrypted using SSL.
If you need to fetch from a cleartext URL (one that begins with http)
you will first need to add an App Transport Security exception. If you
know ahead of time what domains you will need access to, it is more
secure to add exceptions just for those domains; if the domains are
not known until runtime you can disable ATS completely. Note however
that from January 2017, Apple's App Store review will require
reasonable justification for disabling ATS. See Apple's documentation
for more information.
I am developing an app in ionic and I can't connect to the socket server when running on a device.
I have managed to connect my app (port:8100) to a node server(port:9000) locally when developing (via ionic serve), I don have a cors issue, everything runs fine.
Client looks something like this :
socket = new io.connect('http://192.168.1.106:9000');
socket.on('reconnect_attempt',function() {
alert('crap');
});
P.S: the above code is from my own memory, but I know I have provided the ip and port
If the server is working or not I still get the alert...
I have also checked the manifest of the app and it has the appropriate permissions:
android.permission.INTERNET
I also added a js error handler to check if there is a js error:
window.onerror = function (errorMsg, url, lineNumber) {
alert(errorMsg);
}
var MyApp = angular.module('scotch-todo', ['ionic']);
...
I had a small error and fixed it (so the handler works) but now nothing is catched...
If I understand correctly, you can connect when developing on your PC, but now when testing on your physical device.
Since Cordova v4, they changed the default behavior so it won't connect to any address outside its own WebView pages. There exists a cordova whitelist plugin that lets you connect to a list of address in the whitelist
http://docs.ionic.io/docs/cordova-whitelist