Unifying localhost dev api server access for expo app across Android, IOS, and web? - react-native

I'm setting up a simple React Native learning app for several students on Expo, that also talks to an API server the student is learning to code.
The student's API server is run via node server.js, and serves on localhost:3000 on the student's machine. It has nothing to do with expo.
I want students to be able to run their app via any of expo start --android, expo start --ios, or expo start --web, on the same machine that runs their API server. Each student runs from home on a different home wifi network, and doesn't necessarily know the ins and outs of ip addresses or networking.
When using expo start --web, we get CORS exceptions, unless we use the custom webpack.config.js work around (first create webpack.config.js via https://docs.expo.io/guides/customizing-webpack/, then put this in webpack.config.js):
const createExpoWebpackConfigAsync = require('#expo/webpack-config');
module.exports = async function(env, argv) {
const config = await createExpoWebpackConfigAsync(env, argv);
if (config.mode === 'development') {
config.devServer.proxy = {
'/**': {
target: {
host: 'localhost',
protocol: 'http:',
port: 3000,
},
secure: false,
changeOrigin: true,
logLevel: 'info',
},
};
}
return config;
};
This is great, because we can make api calls to ./end/point without knowing the student's ip address, and the webpack devServer launched by expo-cli effectively proxies around to http://localhost:3000/end/point on the student's development machine.
Meanwhile, for iOS and Android, I've found this snippet:
import Constants from "expo-constants";
const { manifest } = Constants;
const SERVER_URL = "http://"+manifest.debuggerHost.split(`:`).shift().concat(`:3000`)+"/";
and then using SERVER_URL when using fetch().
But, we're missing a unified solution that works agnostic of which environment we're in (web, ios, or android). The webpack proxy only appears to be on and work when using the expo web client (expo-cli doesn't launch webpack for ios or android), and the 2nd option (A) doesn't work out of the box on web and (B) would trigger a CORS exception anyway.
How can I elegantly write one bit of code, or otherwise set up the project for the students, so that (A) they don't need to know their dev machine's ip address, or what that means and (B) it will work regardless of whether they're in the web, android, or ios expo client?

Don't like this as an answer and would prefer someone who knows better to point out better, but this is what I ended up using that seems to work, at least in development:
// Some chatter that Contants.manifest needs to come from a different package?
import Constants from "expo-constants";
const { manifest } = Constants;
const SERVER_URL = (() => {
// TODO - put a "prod" api server somewhere
// Android / IOS - no CORS issue.
if (!!manifest.debuggerHost) {
return "http://"+manifest.debuggerHost.split(`:`).shift().concat(`:3000/`);
}
// Expo Web client, making use of webpack.config.js (see original question) for devServer proxy.
else {
return "./";
}
})();
...
fetch(SERVER_URL + 'some_endpoint/').then(...)

Related

Running html only if running in Electron.js [duplicate]

I'm trying to serve real react app on electron app. It doesn't mean I'm developing electron app with react. I've created a react app and injected it into electron app. (Like slack, it will serve as a web application and desktop application.) But I'm confused that send desktop notifications.
Now the main question is:
How can I get the application type. I mean, is user using my app on web or on desktop. How can I get this?
Thank you :)
There are many ways to detect whether you are running in a desktop environment or not.
You can check the User-Agent and you can set the userAgent value in Electron when you call loadURL.
Another way is declaring a global variable using a preload script.
// main process
new BrowserWindow({
webPreferences: {
preload: "preload.js",
},
});
// preload.js
// you don't need to use contextBridge if contextIsolation is false
// but it's true by default in Electron 12
const { contextBridge } = require("electron");
contextBridge.exposeInMainWorld("IN_DESKTOP_ENV", true);
// renderer process (your React world)
if (globalThis.IN_DESKTOP_ENV) {
// do something...
}

Problem with deep linking when published with Expo

can you please give me a hand with Deep Linking. When I work in a development environment it works for me with the URL: exp://192.168.100.4:19000/--/resetPassword/rzBsP3tJ, however, when I publish it, I open it with the URL: exp://exp.host/#user/#nameApp/--/resetPassword/rzBsP3tJ?release-channel=testing, it just opens the app, but it doesn't redirect me to the screen I want. What I can do?
An assumption here: you talk about screens so assuming you are using react-navigation and making use of LinkingOptions.
The issue is caused by a mismatch between how Expo defines a linking URL and how react-navigation defines LinkingOptions. LinkingOptions is in terms of a path, not a URL that has any query params. In development there are no query params, but an app that is is published to a channel has the 'release-channel' query param so this will never match in react-navigation's LinkingOptions.
The solution is just to remove the release-channel query param from the URL returned by Linking.createURL:
import * as Linking from 'expo-linking';
import { URL } from 'react-native-url-polyfill';
const urlWithReleaseChannel = Linking.createURL('/')
const parsedUrl = new URL(urlWithReleaseChannel)
parsedUrl.searchParams.delete("release-channel")
export const resetLinkingOptions = {
prefixes: [parsedUrl.toString()],
config: {
screens: {
ResetPassword: {
path: 'resetPassword/:id'
}
}
}
}
This works for both development and deployed apps: if present, release-channel then behaves as a regular query param. Note that react-native-url-polyfill is required as a project dependency as out of the box the RN URL is not fully featured and lacks in this case the ability to delete a query param.

React native axios is not working properly

I have this route on me BE
app.get('/welcomeRoute',(req,res)=> {
res.send("Hello world")
})
app.listen(4000,()=> {
console.log("Server is up")
})
I installed axios on my react native project with npm i axios , I created my project with expo init.
Here is how I use route
test = () => {
axios.get('http://localhost:4000/welcomeRoute').then((res)=> {
console.log('--------res', res);
}).catch((err)=> {
console.log('--------err', err);
})
}
Whenever i call this route i Always get --------err [Error: Network Error].
I tested this route in the postman and it is working fine.
Any suggestions please?
If the issue is on Android, the solution is to add below in in your AndroidManifest.xml file
android:usesCleartextTraffic="true"
In IOS, unencrypted network requests are blocked by default, i.e. https will work, http will not.
Your server from your emulator/device you need to access server via IP Address. Instead of http://localhost:port you should use http://your_ip_address:port
Actually in React Native you better give ip address of system rather than localhost because the device don't recognize your ip address using localhost

How to refer other html file to load in production mode of application that are developed using electron?

I have problem in building electron application, which is made using electron.js and vue.js.
The development is almost done, so I need to build it and make production.
Basically, my project has license system, so when the program starts, users should activate it by entering license key. I wrote this part inside activate.html. So, inside public folder, there are two html files, one is default index.html, and the other is activate.html
Inside activate.html, when activation is success, startMain() javascript function is called. Inside this function, the program is navigated to main program, especially to index.html. This html file is Vue application, and then main program is started.
All this process is working fine in the development mode. But when it
comes to production, this is not working anymore. I probably know why this
happens, this is just because index.html is not available in
production mode when all these are built up.
Alternatively, I tried to load localhost:8080 inside
startMain(). But also this works fine in development mode, but unluckily, we don't have localhost server on production mode, so this
doesn't solve the problem.
This is startMain() inside activate.html
function startMain() {
window.__static = "index.html";
// Alternatively, we can use location.href on development mode.
// window.location.href = "http://localhost:8080/";
}
This is background.js ( electron main engine)
function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 1400,
height: 900,
titleBarStyle: "hiddenInset"
});
win.setMenuBarVisibility(false);
if (isDevelopment) {
// Load the url of the dev server if in development mode
// win.loadURL(process.env.WEBPACK_DEV_SERVER_URL);
win.loadURL(`file://${process.cwd()}/public/activate.html`);
// if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
createProtocol("app");
// Load the index.html when not in development
win.loadFile("activate.html");
}
win.on("closed", () => {
win = null;
});
}
What I want is to make it run correctly in production mode.
Specifically, when the user finishes activation flow ( activate.html),
it should start main program ( index.html )
Please help me with this issue. I welcome any comments.
I built this application using vue-cli-plugin-electron-builder package
In Vue usually you use vue-router to switch between views. You set the BrowserWindow.location the first time, in background.js, but after that you are in the Vue app and you make router calls like this:
router.replace({ name: "index" }).catch(() => { });
It's hard to guess what to do in your case, without seeing the rest of your activate.html. You need to define router in your App and probably want to convert your activate.html into an activate.vue component and make it the proper first page of your App.
I think the cli-plugin boilerplate will call main.js where you will define your app and bootstraps it. You add router there:
import router from "./router";
window.$app = new Vue({
router,
In your bootstrap function you can also call something like router.replace({ name: "activate"}) to start your app with your activate vue component.

Electron Builder Vue cli 3 application on Windows throwing error registerStandardSchemes undefined

Background
We are building an Electron application and have been able to work on it, and build it using Linux and Mac OS. When we move it to a Windows machine in development or when build on a Mac OS machine then ran on the Windows machine, it fails.
When we follow the instructions here it says,
vue add electron-builder
yarn electron:serve
should run the application. On a fresh install using Windows this fails for us.
Problem
When we try and start the application on Windows we get an error,
TypeError
electron__WEBPACK_IMPORTED_MODULE_0__.protocol.registerStandardSchemes
is not a function
Example
This line comes with the boilerplate when we add Electron Builder to the app that seems to be throwing the error.
protocol.registerStandardSchemes(['app'], { secure: true })
It is being used like this,
import { protocol} from 'electron'
protocol.registerStandardSchemes(['app'], { secure: true })
// Helper to create our main view BrowserWindow
function createWindow() {
// Create the browser window.
win = new BrowserWindow({ width: 800, height: 600 })
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
createProtocol('app')
// Load the index.html when not in development
win.loadURL('app://./index.html')
}
}
What We Tried
When I console.log protocol the only key available is, registerSchemesAsPrivileged which is in the docs but not what came with the boiler and nor does it work. I can see at this page that the registerStandardSchemes is referenced in a paragraph but it is not well explained in it's own section like the rest of the methods on that page.
Question
What does one need to do to access the method, protocol.registerStandardSchemes(['app'], { secure: true }) when running an Electron-Builder application scaffold with Vue CLI 3 on Windows 10?
I recently had this issue - if you're just looking to get back to development, running vue add electron-builder again fixed it for me.