I've been working on an app, and I have been using both the Android emulator and my Android device for testing using Expo.
It works great, everything goes perfect. However, I just built an Android APK (I executed expo build:android), and I can see the login of my app, but after introducing credentials, it kinda shows like it closes the app and then restores it, but now it keeps showing just a blank screen.
Here is a gif showing you exactly what happens.
https://giphy.com/gifs/hdtXNeM2s5Dx7FnbNJ
Also, here's the code of my App.js, which works showing the <AuthNavigator /> (The login screen), but it stops working when a user is set and then <AppNavigator /> does not appear.
import React, { useState } from "react";
import { StyleSheet } from "react-native";
import { NavigationContainer } from "#react-navigation/native";
import { AppLoading } from "expo";
import AppNavigator from "./app/navigation/AppNavigator";
import AuthNavigator from "./app/navigation/AuthNavigator";
import AuthContext from "./app/auth/context";
import authStorage from "./app/auth/storage";
export default function App() {
const [user, setUser] = useState();
const [isReady, setIsReady] = useState(false);
const restoreUser = async () => {
const user = await authStorage.getUser();
if (user) setUser(user);
};
if (!isReady) {
return (
<AppLoading startAsync={restoreUser} onFinish={() => setIsReady(true)} />
);
}
return (
<AuthContext.Provider value={{ user, setUser }}>
<NavigationContainer>
{user ? <AppNavigator /> : <AuthNavigator />}
</NavigationContainer>
</AuthContext.Provider>
);
}
Also my app.json, just in case it's needed:
{
"expo": {
"name": "Agro-Mobile",
"slug": "Agro-Mobile",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./app/assets/icon.png",
"splash": {
"image": "./app/assets/splash.png",
"resizeMode": "cover",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": ["**/*"],
"ios": {
"supportsTablet": true
},
"android": {
"package": "com.smartbase.agrocognitive",
"versionCode": 1
},
"web": {
"favicon": "./app/assets/favicon.png"
},
"description": ""
}
}
In app.json you need change:
"android": {
"package": "com.smartbase.agrocognitive",
"versionCode": 1
for this
"android": {
"package": "com.agrocognitive.agrocognitive",
"versionCode": 1
in other words you need only change the name of company for the name of your app, make sure use only lowercase characters without simbol. The folder that your create have the same name of your app. And for other people delete any commentary in App.js.
This works for me in bluestacks emulator and in my phone running apk file
I hope help you
Related
I'm developing react native expo application which takes photo using expo-image-picker and saves that image into a different location by using expo-media-library.
Everything seems to be working fine but this pop up keeps getting every time user captures the image. This keeps happening on Android. It's affecting UX.
It would be great if you guys could help me to sort out this issue.
Thanks
Allow Expo Go to modify this photo?
Versions
"react-native": "0.64.3"
"expo": "~44.0.0"
"expo-image-picker": "~12.0.2"
"expo-media-library": "~14.0.0"
Here is the code which I'm using to archive mentioned functionality.
import * as ImagePicker from "expo-image-picker";
import * as MediaLibrary from "expo-media-library";
const savePhoto = async (data, onSucess) => {
const asset = await MediaLibrary.createAssetAsync(data?.uri);
const album = await MediaLibrary.createAlbumAsync(
"TEST_FOLDER",
asset,
false
);
const albumAssets = await MediaLibrary.getAssetsAsync({
album: album,
first: 1,
sortBy: [[MediaLibrary.SortBy.creationTime, false]],
});
if (albumAssets?.assets[0]) {
onSucess(albumAssets.assets[0], data);
}
};
const takePicture = async (onSucess, onError) => {
let data = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 0.8,
allowsEditing: true,
base64: true,
});
if (data.cancelled === false) {
savePhoto(data, onSucess);
} else {
onError();
}
};
And here is the app.json file.
{
"expo": {
"name": "product",
"slug": "product_frontend",
"version": "1.0.0",
"orientation": "landscape",
"icon": "./assets/images/icon.png",
"userInterfaceStyle": "automatic",
"splash": {
"image": "./assets/images/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"plugins": [
[
"expo-media-library",
{
"photosPermission": "Allow $(PRODUCT_NAME) to access your photos.",
"savePhotosPermission": "Allow $(PRODUCT_NAME) to save photos.",
"isAccessMediaLocationEnabled": "true"
}
],
[
"expo-image-picker",
{
"cameraPermission": "Allow $(PRODUCT_NAME) to access your camera",
"photosPermission": "The app accesses your photos to let you share them with your friends."
}
]
],
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": ["**/*"],
"ios": {
"supportsTablet": true
},
"android": {
"package": "com.comapny.product",
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
},
"softwareKeyboardLayoutMode": "pan",
"permissions": []
},
"web": {
"favicon": "./assets/images/favicon.png"
},
"scheme": "product"
}
}
It would be great if you guys cold help me to sort out this issue.
Thanks.
SDK Version: 43.0.0
Platforms(Android/iOS/web/all): Android
Hello, I'm using expo-auth-session in the managed workflow to collect Instagram user data through its official API, it's working fine on the development environment (through the "expo run:android" command), but once a build APK is created when the user makes the authorization process and the redirect starts there is a popup asking “Open with” and two options for my app, the first one works perfectly the second one goes back to the app but does nothing, I didn't test on IOS.
Here is the image that represent it:
Click here to see
When I was developing I tried to do the google sign-in process but was stuck in the same error, partially resolved by implementing google native sign-in. I verified my schemes in app.json but didn`t identify wrong on it, as follows:
app.json:
{
"expo": {
"name": "Secreet",
"slug": "secreet",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"scheme": "com.davidtmiranda.secreet",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": ["**/*"],
"ios": {
"supportsTablet": true,
"usesAppleSignIn": true,
"bundleIdentifier": "com.davidtmiranda.secreet",
"googleServicesFile": "./GoogleService-Info.plist",
"config": {
"googleSignIn": {
"reservedClientId": "com.googleusercontent.apps.--------------------"
}
}
},
"android": {
"versionCode": 1,
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
},
"package": "com.davidtmiranda.secreet",
"googleServicesFile": "./google-services.json"
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
also, my authSession code looks like this:
webBrowser.maybeCompleteAuthSession();
const useProxy = Platform.select({ web: false, default: true });
const client_id = ---;
const redirect_uri = "https://auth.expo.io/#davidtmiranda/secreet";
const scope = "user_profile";
const site =
"https://api.instagram.com/oauth/authorize?client_id=" +
client_id +
"&redirect_uri=" +
redirect_uri +
"&scope=" +
scope +
"&response_type=code&state=1";
const discovery = { authorizationEndpoint: site };
const [request, response, promptAsync] = useAuthRequest(
{
redirectUri: makeRedirectUri({
useProxy,
native: redirect_uri,
}),
scopes: [scope],
clientId: String(client_id),
},
discovery
);
useEffect(() => {
if (response?.type === "success") {
...
}
}, [response]);
function GetInstagramID() {
return promptAsync({
useProxy,
});
}
Any suggestions about how to solve this problem? I believe it is schema-related but could not identify what is wrong.
Maybe you can try to remove scheme in the app.json
"scheme": "com.davidtmiranda.secreet",
and it will change appAuthRedirectScheme in the android/app/build.gradle
manifestPlaceholders = [appAuthRedirectScheme: 'com.davidtmiranda.secreet']
It solves my issue.
Since I had a very dated app, react-native 0.59.9 + native-base 2.10.0, or decided to update it starting from a clean project using the classic:
npx react-native init AwesomeProject
at this point I also installed the new native-base 3.2.1 and I overturned all the files and updated their dependencies, many things were different, especially those related to react-navigation.
Once the dependencies have been resolved, the compilation takes place correctly, as seen from the metro bundler (react-native start) but the application immediately crashes reporting:
Require cycles are allowed, but can result in uninitialized values. Consider refactoring to remove the need for a cycle.
ERROR TypeError: undefined is not an object (evaluating 'Comp.displayName')
ERROR Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication). A frequent cause of the error is that the application entry file path is incorrect.
This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.
ERROR Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication). A frequent cause of the error is that the application entry file path is incorrect.
This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.
I tried to clear the cache, delete node_modules and recreate it but the error always appears.
From what I understand there is some problem with the appRegistry in the early stage, these are my files where I assume something abnormal is happening.
app.json
{
"name": "MyApp",
"displayName": "MyApp"
}
index.js
import {AppRegistry, Text, TextInput } from 'react-native';
import App from './App';
import {name as appName} from './app.json';
//Disable the FontScaling set by the device (Component "Text").
Text.defaultProps = Text.defaultProps || {};
Text.defaultProps.allowFontScaling = false;
//Disable the FontScaling set by the device (Component "TextInput").
TextInput.defaultProps = Text.defaultProps || {};
TextInput.defaultProps.allowFontScaling = false;
AppRegistry.registerComponent(appName, () => App);
App.js
import React from 'react';
import Setup from './src/boot/setup.js';
export default class App extends React.Component {
render() {
return (
<Setup/>
);
}
}
./src/boot/setup.js (here I inserted the NativeBaseProvider component which was not used before.)
import React from 'react';
import { NativeBaseProvider } from 'native-base';
import App from '../App.js';
export default class Setup extends React.Component {
render() {
return (
<NativeBaseProvider>
<App />
</NativeBaseProvider>
);
}
}
./src/App.js
import React from 'react';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { createSwitchNavigator } from "#react-navigation/compat";
import Home from './components/Home/homeScreen';
import Login from './components/Login/loginScreen';
import ResetPassword from './components/Login/resetPassword';
import News from './components/News/newsScreen';
import Chat from './components/Chat/chatScreen';
import ProfileIndex from './components/Profile/profileIndex';
import SideBar from './components/sidebar/sidebar';
import NewsDetails from './components/News/newsScreenDetails';
import Privacy from './components/Privacy/privacyScreen';
import SignUpWorker from './components/SignUpWorker/signUpWorker';
import AuthLoadingScreen from './utils/authLoadingScreen';
const SignedInDrawer = createDrawerNavigator(
{
Home: { screen: Home },
ProfileIndex: { screen: ProfileIndex },
Chat: { screen: Chat },
News: { screen: News },
NewsDetails: { screen: NewsDetails },
Privacy: { screen: Privacy },
},
{
initialRouteName: 'Home',
contentComponent: props => <SideBar {...props} />,
}
);
const SignedOutDrawer = createDrawerNavigator(
{
Home: { screen: Home },
Login: { screen: Login },
ResetPassword: { screen: ResetPassword },
SignUp: { screen: SignUp },
News: { screen: News },
NewsDetails: { screen: NewsDetails },
Privacy: { screen: Privacy },
},
{
initialRouteName: 'Home',
contentComponent: props => <SideBar {...props} />,
}
);
const SignedInStack = createNativeStackNavigator(
{
DrawerIn: { screen: SignedInDrawer },
},
{
initialRouteName: 'DrawerIn',
headerMode: 'none',
}
);
const SignedOutStack = createNativeStackNavigator(
{
DrawerOut: { screen: SignedOutDrawer },
},
{
initialRouteName: 'DrawerOut',
headerMode: 'none',
}
);
export default createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
SignedIn: SignedInStack,
SignedOut: SignedOutStack,
},
{
initialRouteName:'AuthLoading'
}
);
./src/utils/authLoadingScreen.js
import { View, ActivityIndicator, StyleSheet, StatusBar, NetInfo } from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
import React from 'react';
export let globalUserToken;
export let globalNetworkOnline;
// this function is used to set the globalUserToken from other pages
export function setglobalUserToken(newValue: boolean) {
globalUserToken = newValue;
}
export async function checkNetwork() {
await NetInfo.getConnectionInfo().then(connectionInfo => {
if (connectionInfo.type === 'none') {
globalNetworkOnline = false;
} else {
globalNetworkOnline = true;
}
});
}
export default class AuthLoadingScreen extends React.Component {
constructor() {
super();
this._bootstrapAsync();
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
globalUserToken = await AsyncStorage.getItem('id_token');
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(globalUserToken ? 'SignedIn' : 'SignedOut');
};
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
The problem most likely starts from src/App.js as i have updated the functions for createNativeStackNavigator, createDrawerNavigator, createSwitchNavigator which were previously simply StackNavigator, DrawerNavigator, SwitchNavigator from 'react-navigation'.
Or the error resides in ./src/utils/authLoadingScreen.js where it is checked if a login token exists... maybe something has changed here too?
Finally I leave you my package.json:
{
"name": "MyApp",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint .",
"build:ios": "react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ios/main.jsbundle --assets-dest ios",
"build:android": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res"
},
"dependencies": {
"#react-native-async-storage/async-storage": "^1.15.9",
"#react-navigation/compat": "^5.3.20",
"#react-navigation/drawer": "^6.1.8",
"#react-navigation/native": "^6.0.6",
"#react-navigation/native-stack": "^6.2.4",
"#types/react-native-dotenv": "^0.2.0",
"native-base": "^3.2.1",
"react": "17.0.2",
"react-native": "0.66.0",
"react-native-dotenv": "^3.2.0",
"react-native-gesture-handler": "^1.10.3",
"react-native-htmlview": "^0.16.0",
"react-native-reanimated": "2.3.0-beta.2",
"react-native-safe-area-context": "^3.3.2",
"react-native-screens": "^3.8.0",
"react-native-size-matters": "^0.4.0",
"react-native-svg": "^12.1.1",
"rn-fetch-blob": "^0.12.0",
"styled-components": "^5.3.1",
"styled-system": "^5.1.5",
"tcomb-form-native": "^0.6.20"
},
"devDependencies": {
"#babel/core": "^7.12.9",
"#babel/runtime": "^7.15.4",
"#react-native-community/eslint-config": "^2.0.0",
"babel-jest": "^27.2.5",
"eslint": "^8.0.1",
"jest": "^27.2.5",
"metro-react-native-babel-preset": "^0.66.2",
"react-test-renderer": "17.0.2"
},
"jest": {
"preset": "react-native"
}
}
Has anyone had this problem or do you know if I have correctly changed the components of react-navigation no longer used in the new version?
"expo": "^39.0.0" / Library - expo-notifications.
Since moving to the new API, I have been facing various problems. I fixed problems with the icon, with receiving a notification in apk, with handlers, and now I could not find an answer to this question.
I have 3 phones Samsung Galaxy S9+ with Android 10, Xiaomi Redmi 4x with Android 7.12 N2G47H MIUI 10 Global 9.6.27 and Xiaomi Redmi Note 4 Global Android 7.0 nrd90m MIUI global 11.0.2.
Samsung Galaxy S9+. With my current config i receive notification
excellent as it should be:
Vibration +
Sound +
Popup when notification comes +
All this come from the box, i do not need to ask permissions or something like that.
Xiaomi Redmi 4x and Xiaomi Redmi Note 4.
With my current config i have problems:
Vibration - do not work both in both published and apk(standalone) versions
Sound +
Popup when notification comes +
AND THE MAIN PROBLEM: All this DO NOT come from the box, I need to manually give permission for notifications to pop up, sound, etc.
My app.json :
{
"expo": {
"name": "qwert",
"slug": "qwert",
"version": "1.1.2",
"orientation": "portrait",
"icon": "./src/assets/images/logo1024.png",
"scheme": "myapp",
"userInterfaceStyle": "automatic",
"privacy": "unlisted",
"splash": {
"image": "./src/assets/images/splashScreen.png",
"resizeMode": "contain",
"backgroundColor": "#f1f0f0"
},
"android": {
"package": "com.qwert.app",
"googleServicesFile": "./google-services.json",
"versionCode": 1,
"useNextNotificationsApi": true
},
"notification": {
"icon": "./src/assets/images/VIAicon96.png",
"color": "#8edcd5",
"androidMode": "collapse"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"web": {
"favicon": "./assets/images/favicon.png"
},
"description": ""
}
}
My permissions/configs:
import Constants from 'expo-constants';
import * as Notifications from 'expo-notifications';
import * as Permissions from 'expo-permissions';
import { Platform } from 'react-native';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: true,
}),
});
export const registerForPushNotificationsAsync = async () => {
let token;
if (Constants.isDevice) {
const { status: existingStatus } = await Permissions.getAsync(
Permissions.NOTIFICATIONS,
);
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
finalStatus = status;
}
if (finalStatus !== 'granted') {
console.log('Failed to get push token for push notification!');
return;
}
token = (await Notifications.getExpoPushTokenAsync()).data;
console.log(token);
} else {
console.log('Must use physical device for Push Notifications');
}
if (Platform.OS === 'android') {
Notifications.setNotificationChannelAsync('default', {
name: 'default',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C',
});
}
// eslint-disable-next-line consistent-return
return token;
};
Also, place where use all this:
useEffect(() => {
const handleNotification = async () => {
await getPermitsAndIntegrateIntoApp(store); // works great
};
const setPersistDataToStore = async () => {
const EXPO_PUSH_TOKEN = await registerForPushNotificationsAsync();
const qwertyyy = await getConfig(Constants.deviceId, EXPO_PUSH_TOKEN);
store.setQwerrt(config.destinations);
};
setPersistDataToStore();
Notifications.addNotificationReceivedListener(handleNotification);
return () => Notifications.removeAllNotificationListeners();
}, [store]);
On all 3 phones I have a logic for handling notifications ( send request, updates store, and updates screen on my app). It works correct.
How to automatically configure the permission to show push notifications? How to enable vibration on Xiaomi?
Finally i found an answers.
https://github.com/expo/expo/issues/8556 tells us that
And that
Permissions.askAsync not working as expected tells us how to let user set permissions to notifications.
And i still do not know why Xiaomi do not vibrate......
I have Xiaomi Redmi 6A, and with default configuration from examples in Expo documentation I received only vibration on notification. I have to manually turn on pop up (floating) and sound for default channel. Only after that notifications began to work as expected.
I am trying to develop an application and I am having trouble getting it to build once I added dotenv.
In my app.config.js I have
import "dotenv/config";
const API_URL = process.env["API_URL"] || "";
const API_VERSION = process.env["API_VERSION"] || "";
const MIRAGE_ENABLED = process.env["MIRAGE_ENABLED"] === "true" ? true : false;
const NODE_ENV = process.env["NODE_ENV"];
export default {
name: "My Application",
version: "0.0.0",
extra: {
API_URL,
API_VERSION,
MIRAGE_ENABLED,
NODE_ENV,
},
};
in my app.json I have:
{
"expo": {
"name": "my-application",
"slug": "my-application",
"owner": "my-expo",
"privacy": "unlisted",
"version": "0.0.0",
"orientation": "landscape",
"icon": "./assets/images/icon.png",
"sdkVersion": "37.0.0",
"platforms": ["ios"],
"splash": {
"image": "./assets/images/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": ["**/*"],
"ios": {
"supportsTablet": true,
"bundleIdentifier": "io.company.my-application",
"buildNumber": "0.0.0"
}
}
}
After reading the documentation I am more confused than before. The output of expo build is:
Failed to read config at: .../app.config.js
ConfigError: Failed to read config at: .../app.config.js
at Object.getDynamicConfig (/Users/me/.npm-global/lib/node_modules/expo-cli/node_modules/#expo/config/src/getConfig.ts:37:9)
at getConfig (/Users/me/.npm-global/lib/node_modules/expo-cli/node_modules/#expo/config/src/Config.ts:121:62)
at validateAsync (/#expo/xdl#58.0.12/src/project/Doctor.ts:438:24)
at Object.validateWithoutNetworkAsync (/#expo/xdl#58.0.12/src/project/Doctor.ts:419:10)
at /Users/me/.npm-global/lib/node_modules/expo-cli/src/exp.ts:644:35
at Command.<anonymous> (/Users/me/.npm-global/lib/node_modules/expo-cli/src/exp.ts:331:7
which is no help at all. Searching for Failed to read config at: .../app.config.js yielded no results whatsoever.
What am I doing wrong? What is the best practice for configuration using expo in this manner? Any help would be greatly appreciated.
To begin with, you need to override the app.json with your envirionment variables in app.config.js. To override the js object you can use separator operator, and to give "extra" variables you can use extra key. Let me give an example:
import 'dotenv/config'
export default ({config}) => {
const appConfig = ({
...config,
version: process.env.VERSION,
//override anything you want
extra: {
API_URL: process.env.API_URL,
//...
}
});
return appConfig;
}
This will attach the process env variables to your manifest. If you have any read errors about app.config.js, it's possible that you didn't install the dotenv package. Let me know.
first, you'll need to install the module 'dotenv' using the command npm i dotenv
Then, in your app.config.js file, provide the configuration in the arguments to the exported function:
import 'dotenv/config'
export default ({config}) => {
const appConfig = ({
...config,
version: process.env.VERSION,
//override anything you want
extra: {
API_URL: process.env.API_URL,
//...
}
});
return appConfig;
};