Font.loadAsync does not load fonts and because of this shows splash - android

the loading of fonts has not been working for several days and I cannot find the reason, and there is something else wrong with expo go, it takes a very long time to load, and for some reason after exp publish the application is not updated in any way, does anyone know the reason?
during development (6 months) there were no problems, but two days ago for some reason the fonts broke and I can't find the reason
if you remove the loading of fonts, then the application is loaded.
"expo-cli": "4.11.0",
"expo": "~40.0.0",
"expo-app-loading": "^1.0.1",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",

*In my case, when using expo go, I noticed that it takes a long time to load with AppLoading if the clocks(of my phone and my computer) are not in sync.
*IF it helps I'll show you How I load Fonts in my app, I am using currently using:
"expo": "^41.0.0",
"expo-app-loading": "^1.1.2",
"expo-font": "~9.1.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz",
const fetchFonts = async () => {
return await Font.loadAsync({
'gotham-narrow-black':{
uri: require('./assets/fonts/gotham/GothamNarrow-Black.otf'),
display: Font.FontDisplay.FALLBACK
},
'gotham-narrow-book':{
uri: require('./assets/fonts/gotham/GothamNarrow-Book.otf'),
display: Font.FontDisplay.FALLBACK
},
'gotham-ultra':{
uri: require('./assets/fonts/gotham/Gotham-Ultra.otf'),
display: Font.FontDisplay.FALLBACK
},
'gotham-light':{
uri: require('./assets/fonts/gotham/GothamLight.otf'),
display: Font.FontDisplay.FALLBACK
},
'gotham-book':{
uri: require('./assets/fonts/gotham/Gotham-Book.otf'),
display: Font.FontDisplay.FALLBACK
},
})
}
export default function App() {
const [fontLoaded, setFontLoaded] = useState(false);
if(!fontLoaded) {
return <AppLoading
startAsync = { fetchFonts }
onError = { console.warn }
onFinish = { () => setFontLoaded(true) }
/>
}
return <MainApp />;
}

As your font is a static file you will have to change your fontLoading function
Change this
import Helvetica from './Helvetica.ttf';
const useFonts = async () =>
await Font.loadAsync({
Helvetica: Helvetica, // not like this
});
to this
const useFonts = async () =>
await Font.loadAsync({
Helvetica: require('./Helvetica.ttf'), // correct location
});
So in your case change your loadFonts function to this
const loadFonts = async () =>
await Font.loadAsync({
montserratRegular: require('./assets/Montserrat-Regular.ttf'),
montserratBold: require('./assets/Montserrat-Bold.ttf'),
montserratSemiBold: require('./assets/Montserrat-SemiBold.ttf'),
montserratMedium: require('./assets/Montserrat-Medium.ttf'),
});

Related

'ExponentImagePicker.launchCameraAsync' has been rejected

On a specific device (Samsung Galaxy S9 with Android 9), when I try to open the camera through ExponentImagePicker, I get the following error:
Error: Call to function 'ExponentImagePicker.launchCameraAsync' has been rejected.
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property cameraLauncher has not been initialized
On an Android 9 emulator it works, and also for newer API version emulators.
This was working previously, but seems to have stopped working after updating react native and other libraries.
Anything I can do about it?
Code:
import * as ImagePicker from 'expo-image-picker';
const MediaSelector: React.FC<Props> = (props) => {
const open = async () => {
const permissions = await ImagePicker.requestCameraPermissionsAsync();
if (!permissions.granted) return Alert.alert("permission denied!"))
const config: ImagePicker.ImagePickerOptions = {
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
allowsMultipleSelection: false,
exif: false,
aspect: [1, 1],
}
try {
const result = await ImagePicker.launchCameraAsync(config);
} catch (error) {
console.log(error)
Alert.alert("error!")
return
}
}
return <Pressable style={styles.container} onPress={open}>
<ImageView img={props.image}/>
</Pressable/>
}
versions:
"react": "18.0.0",
"expo-image-picker": "~13.3.1",
"react-native": "0.69.6",
I had the same issue, and for some reason using getCameraPermissionsAsync() fixed the issue - whereas requestCameraPermissionsAsync() on its own would cause launchCameraAsync() to be rejected on Android devices.
See the following:
let permissionResult = await ImagePicker.getCameraPermissionsAsync();
if(permissionResult.status !== 'granted') {
permissionResult = await ImagePicker.requestCameraPermissionsAsync();
}
if(permissionResult.status !== 'granted') {
alert("You must turn on camera permissions to record a video.");
}
else {
let result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Videos,
allowsEditing: true,
aspect: [3, 4],
});

react-redux dispatch action does not work on android but works on ios

I have set up my store correctly and everything works perfectly fine on ios. But on android with the exact same code, the dispatch action has no effect, it does not populate my context with the value returned from my APi.
Since it is exactly the same code, I have been struggling to figure out what the issue could be.
I am using
"react-redux": "^7.2.1",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"react-native": "0.66.4",
calling the action on app launch
const dispatch = useDispatch()
const trans = useSelector(state => state.translation);
useEffect(() => {
fetchTranslations(dispatch)
}, [])
reducer
import React from "react";
const initState = {};
const TranslationReducer = (state = initState, action) => {
switch (action.type) {
case 'FETCH_TRANSLATIONS':
return action.payload.data
default:
return state;
}
};
export default TranslationReducer
action
import { get } from '../api/query';
export function fetchTranslations(dispatch) {
try {
return (
get('/api/v3/labels/mobile_app/')
.then(res => {
console.log('res', res)
return res.json()
})
.then(response => {
console.log('response', response)
dispatch({
type: 'FETCH_TRANSLATIONS',
payload: response
})
})
)
} catch (e) {
console.log('error', e)
}
}
everything is correctly returned from the api, but dispatching the action does nothing to the state, it stays empty on android, but works fine on ios.
Ok so after many days of searching, I went back into the setting up of redux-devtoools and changed a line in the initialisation of my store.
before
const store = createStore(
reducers,
{},
composeWithDevTools(applyMiddleware(ReduxThunk))
);
solution
const store = createStore(
reducers,
{},
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
this is the line that seemed to be causing the error on Android only
composeWithDevTools(applyMiddleware(ReduxThunk))
I have yet to understand why, but for everyone going through a similar error, I hope this will be useful.

Why does getCurrentPositionAsync never returns anything?

Thank you for visiting this post.
I am having a trouble with React Native getting user location.
I have searched for a quite some time and read other people's posts about this function.
It seems like this function has some several problems.
And also react native expo documentation seems to be outdated.
https://docs.expo.dev/versions/latest/sdk/location/
I use the code from here under usage section.
import React, { useState, useEffect } from 'react';
import { Platform, Text, View, StyleSheet } from 'react-native';
import * as Location from 'expo-location';
export default function App() {
const [location, setLocation] = useState(null);
const [errorMsg, setErrorMsg] = useState("");
useEffect(async () => {
(async () => {
let { status } = await Location.requestForegroundPermissionsAsync();
console.log(status);
if (status !== 'granted') {
console.log("denied")
setErrorMsg('Permission to access location was denied');
return;
}
console.log("status", status); // <=== always says "granted"
let location = await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.Highest,
maximumAge: 10000,
timeout: 5000
});
console.log({ location }) // <== never reach here.
setLocation(location);
setErrorMsg('No ERROR');
})();
}, []);
let text = 'Waiting..';
if (errorMsg) {
text = errorMsg;
} else if (location) {
text = JSON.stringify(location);
}
return (
<View>
<Text>{text}</Text>
</View>
);
}
I have seen one of the post saying I have to pass the arguments of accuracy, maximumAge to getCurrentPositionAsync, instead of {} empty object which is provided in the expo docs.
But still does not work. since getCurrentPositionAsync is hanging, the screen keep displaying waiting....
And of course, the android emulator is setup correctly I believe, since I do see the status log and it says "granted".
Thank you in advance so much for your help and reading my post.
"expo": "~43.0.2",
"expo-location": "~13.0.4",
"expo-status-bar": "~1.1.0",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"react-native-web": "0.17.1"
You can't use async with useEffect, and therefore not await.
Have you tried the other way around?
const [position, setPosition] = useState(false)
// useEffect
Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.Highest,
maximumAge: 10000,
timeout: 5000
})
.then(res => setPosition(res))
.catch(e => console.log(e)
I've also had more chances without non-fat arrowed IIFE, you should try out
(function () {
let { status } = await Location.requestForegroundPermissionsAsync();
console.log(status);
if (status !== 'granted') {
console.log("denied")
setErrorMsg('Permission to access location was denied');
return;
}
console.log("status", status); // <=== always says "granted"
let location = await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.Highest,
maximumAge: 10000,
timeout: 5000
});
console.log({ location }) // <== never reach here.
setLocation(location);
setErrorMsg('No ERROR');
})();

React Native firebase realtime database not working

I'm trying to use Firebase realtime database on my React Native project. Based on the documentation I did following things on Android side(I'm checking for Android).
yarn add #react-native-firebase/app
Then put the google-services.json and did all gradle related changes.
yarn add #react-native-firebase/database
I have created a small test db as well to test the functionality.
This is the code that I have tried on my home page.
componentDidMount() {
console.log("Component Did Mount")
database()
.ref('name/')
.on('value', snapshot => {
console.log('User data: ', snapshot);
});
}
'User data' has not been printed in console. Not only the snapshot values but also user data text. Only 'component did mount' text is printed in console there. I added all the relevant permissions in AndroidMainifest as well
AndroidManifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
package json
"dependencies": {
"#react-native-async-storage/async-storage": "^1.15.5",
"#react-native-community/masked-view": "^0.1.11",
"#react-native-firebase/app": "^12.7.5",
"#react-native-firebase/database": "^12.7.5",
"#react-native-firebase/firestore": "^12.7.5",
"#react-native-firebase/remote-config": "^12.8.0",
"#react-navigation/bottom-tabs": "^5.11.11",
"#react-navigation/native": "^5.9.4",
"#react-navigation/stack": "^5.14.5",
"#reduxjs/toolkit": "^1.6.0",
"#thecodingmachine/redux-toolkit-wrapper": "2.0.1",
"axios": "^0.21.1",
"i18next": "^20.3.2",
"prop-types": "^15.7.2",
"react": "17.0.1",
"react-i18next": "^11.11.0",
"react-native": "0.64.2",
"react-native-flipper": "^0.94.1",
"react-native-gesture-handler": "^1.10.3",
"react-native-linear-gradient": "^2.5.6",
"react-native-reanimated": "^2.2.0",
"react-native-safe-area-context": "^3.2.0",
"react-native-screens": "^3.4.0",
"react-native-webview": "^11.13.0",
"react-redux": "^7.2.4",
"redux": "^4.1.0",
"redux-flipper": "^1.4.2",
"redux-persist": "^6.0.0"
},
"devDependencies": {
"#babel/core": "^7.12.9",
"#babel/runtime": "^7.12.5",
"#react-native-community/eslint-config": "^2.0.0",
"babel-jest": "^26.6.3",
"babel-plugin-module-resolver": "^4.0.0",
"eslint": "^7.22.0",
"eslint-import-resolver-babel-module": "^5.1.2",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^24.3.5",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.6.3",
"metro-react-native-babel-preset": "^0.64.0",
"react-test-renderer": "17.0.1"
},
I'm using this boilerplate
https://github.com/thecodingmachine/react-native-boilerplate
The DatabaseReference#on() method accepts two separate callbacks, one for when the requested event fires and one that handles errors.
database()
.ref('name') // no trailing "/"! (even though it does get trimmed off internally)
.on(
'value',
snapshot => {
console.log('Latest value for "/name": ', snapshot);
},
error => {
console.error('Failed to retrieve "/name": ', snapshot);
}
);
Importantly, this method also returns the first snapshot-listening callback, so that you can use it with DatabaseReference#off when unmounting your component.
const nameListener = database()
.ref('name')
.on(/* ... */);
// create a callback to be called in the `componentWillUnmount()` method
const unsubscribeNameListener = () => nameRef.off('value', nameListener);
Rolling this together gives:
class NameFromDatabase extends React.Component {
private unsubscribers = [];
componentDidMount() {
const nameRef = database().ref('name');
const nameListener = nameRef
.on(
'value',
snapshot => {
console.log('Latest value for "/name": ', snapshot);
},
error => {
console.error('Failed to retrieve "/name": ', snapshot);
}
);
// create a callback to be called in the `componentWillUnmount()` method
unsubscribers.push(() => nameRef.off('value', nameListener));
}
componentWillUnmount() {
unsubscribers.forEach(unsub => unsub());
}
}
Although the above code works, you really should make use of the React Hooks API and the new Firebase SDK's Modular API instead. Using the class-based form of React and namespace-based version of Firebase is ill-advised for new projects.
import { useState, useEffect } from 'react';
import { getDatabase, ref, onValue, off } from 'firebase/database';
const NameFromDatabase = () => {
const [name, setName] = useState();
useEffect(() => {
const nameRef = ref(getDatabase(), 'name');
// onValue returns its own unsubscribe function
return onValue(
nameRef,
snapshot => {
console.log('Latest value for "/name": ', snapshot.val());
setName(snapshot.val());
},
error => {
console.error('Failed to retrieve "/name": ', error);
setName(null);
}
);
}
if (name === void 0)
return (<div>Loading...</div>);
if (name === null)
return (<div class="error">Name not found!</div>);
return (<div>{ name }</div>);
}

UI doesn't update until tap on the screen when setState is called inside a realm listener callback

UPDATED
DESCRIPTION
I have a listener on a Realm Object for getting updates. When there is an update on the server (or in the client) the function provided to the listener calls setState({}).
The strange part is that even if the console says that everything is ok, and it shows that the render method was called with correct data, I can't see any updates to my app.
If I tap on the screen randomly (after 1s,2s, 20s...) the UI magically updates and everything is correct.
If I do the same setState with a function called from a button it works, I guess because the animation of the button triggers the UI update.
Thanks for reading this.
STEP TO REPRODUCE
You have to update the server_url and credential in order to work.
react-native init test
npm install realm
react-native link realm
Since realm is not ready for 64-bit you must also be sure t compile only in 32bit in order to avoid app crashing when launched
use this code:
App.js
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View} from 'react-native';
import Realm from 'realm'
import { SERVER_URL } from "./config/realm";
import { Utente } from "./config/schema";
export default class App extends Component {
loginAsync = async () => {
var realm_user = Realm.Sync.User.current
if(!realm_user){
const credentials = Realm.Sync.Credentials.usernamePassword('admin', '******' ,false);
realm_user = await Realm.Sync.User.login(SERVER_URL, credentials);
}
const config = realm_user.createConfiguration({
schema: [
Utente,
Realm.Permissions.Permission,
Realm.Permissions.User,
Realm.Permissions.Role],
schemaVersion: 1,
});
this.realm = new Realm(config);
var connectedUserData = this.realm.objects("Utente").filtered("id = $0", realm_user.identity)
connectedUserData.subscribe()
connectedUserData.addListener((connectedUserData)=>{
if(connectedUserData[0]){
this.setState({
connectedUserData: connectedUserData[0]
})
}
})
}
constructor(props){
super(props)
this.loginAsync()
this.state = {
connectedUserData: {
nome: 'not loaded'
}
}
}
render() {
return (
<View style={styles.container}>
<Text>{ this.state.connectedUserData.nome }</Text>
</View>
);
}
}
Schema.js
export const Utente = {
name: "Utente",
primaryKey: "id",
properties: {
id: "string",
nome: 'string?',
permissions: '__Permission[]'
}
}
Package.json
{
"name": "testBaseRealm",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"react": "16.6.3",
"react-native": "0.57.7",
"realm": "^2.27.0-rc.3"
},
"devDependencies": {
"#babel/core": "7.4.4",
"#babel/runtime": "7.4.4",
"babel-jest": "24.8.0",
"jest": "24.8.0",
"metro-react-native-babel-preset": "0.54.1",
"react-test-renderer": "16.6.3"
},
"jest": {
"preset": "react-native"
}
}
Some other strange things :
If I remote debug js to react native debugger (on Windows, but I guess is the same) the problem disappears.
The same thing happens on 3 different devices( 2 real, 1 emulator)
In my case, I just stop the debugger (CMD+D), and that weird behavior went away.
UPDATE 2
setState({}) doesn't work when is inside the listener callback. I've
just done a test changing the code in componentDidMount of Home.js,
and in this way, it works.
It doesnt work because you are not binding the method that is calling it. it is beyond component context so setState is not there.
Do
openRealmAndLogin = (realm_user) => {...}
instead of regular function as this one will bind the function to context. e.g. you can also bind it in constructor (but from what i've seen you are already doing something similar for other function - so better to keep it consistent)
I would suggest that you change the key of the element; this will force it to reload whatever happens.
Ex:
{
articoli.map(articolo => {
const isLoved = connectedUserData.loved_articles.filtered("id = $0", articolo.id ).length
const isLiked = connectedUserData.liked_articles.filtered("id = $0", articolo.id ).length
const numCommenti = articolo.commenti.length
return (
<SchedaArticolo
key={ `ALL_${articolo.id}_${isLoved}_${isLiked}_${numCommenti}` }
articolo={articolo}
isLoved={isLoved}
isLiked={isLiked}
numCommenti={numCommenti}
/>
)
})
}

Categories

Resources