I uploaded my app to Play Store without any problem. However, when I tried to install the App Store, the application was rejected and I received the following message.
Guideline 2.1 - Performance - App Completeness
We discovered one or more bugs in your app. Specifically, the app
displayed only a splash screen.
Review device details:
Device type: iPhone
OS version: iOS 15.1
I tried the application both on the simulator and on the real device with testflight. But I have never encountered such a problem. Does anyone know the reason or are having the same problem?
I've done almost the same application before. The only difference is that I add anonymousSignIn() in this app. Is this what broke the app or is there something else? Here my splash screen codes:
import React, { useEffect } from 'react'
import AsyncStorage from "#react-native-async-storage/async-storage"
import { View } from 'react-native'
import AppIcon from '../../assets/svgs/app-icon.svg'
import styles from './styles/SplashStyles'
import { RemoteConfig } from '../../api/RemoteConfig'
import { getData } from '../../api/RealtimeDb'
import { NotificationUtil } from "../../utils/NotificationUtil"
import { InitializeUtil } from "../../utils/InitializeUtil"
import { pushNotification } from '../../api/PushNotification';
import { anonymousSignIn } from '../../api/Auth'
const remoteConfig = new RemoteConfig()
const notificationUtil = new NotificationUtil()
const initializeUtil = new InitializeUtil()
const Splash = ({ navigation }) => {
// asking user for notification permission (iOS)
function permission() {
notificationUtil.pushNotificationAPNsPermissions()
}
useEffect(() => {
async function splash() {
// fetches the remote config data from firebase
remoteConfig.init()
pushNotification()
//message to be shown in the alert
const message = remoteConfig.getAlertMessage().text
// alert before notification permission
await notificationUtil.alertBeforeNotificationPermission(
message,
permission
)
await anonymousSignIn()
getData()
.then(async (response) => {
const lastViewedWord = await AsyncStorage.getItem("lastViewedWord")
const page = await initializeUtil.getPageNameToVisit()
navigation.reset({
index: 0,
routes: [{
name: page, params: {
lastViewedWord: lastViewedWord,
allData: response,
}
}]
})
})
}
splash()
}, [])
return (
<View style={styles.container} >
<AppIcon
height='100%'
width='50%'
/>
</View >
)
}
export default Splash
Related
I have a React Native app that needs to be served on its web version. So, I need to implement the Google OAuth with the firebase js lib.
I'm following these steps.
If I use the same code from the docs I have a weird error (of course I put the proper config object in the initializeApp method):
import * as React from 'react';
import * as WebBrowser from 'expo-web-browser';
import { ResponseType } from 'expo-auth-session';
import * as Google from 'expo-auth-session/providers/google';
import { initializeApp } from 'firebase/app';
import { getAuth, GoogleAuthProvider, signInWithCredential } from 'firebase/auth';
import { Button } from 'react-native';
// Initialize Firebase
initializeApp({
/* Config */
});
WebBrowser.maybeCompleteAuthSession();
export default function App() {
const [request, response, promptAsync] = Google.useIdTokenAuthRequest(
{
clientId: 'Your-Web-Client-ID.apps.googleusercontent.com',
},
);
React.useEffect(() => {
if (response?.type === 'success') {
const { id_token } = response.params;
const auth = getAuth();
const credential = GoogleAuthProvider.credential(id_token);
signInWithCredential(auth, credential);
}
}, [response]);
return (
<Button
disabled={!request}
title="Login"
onPress={() => {
promptAsync();
}}
/>
);
}
The error is:
I get this error specifically when I call signInWithCredential()
The strange thing is that in the Network tab (Chrome DevTools) I have a successful response:
And the problem is: If I want to get the user information with onAuthStateChanged, it is null because the login attempt just failed (despite the dev-tools being all good)
Note: I've tried with a new starter project, moving our dependencies with the same version as they are here and it's working.
But I can't figure out what can be happening with this project.
EDIT: Adding images of the requests that are being made:
I am trying to build a basic notification app that uses the react-native-background-task module. For some reasons it gives this error: Cannot read properties of undefined (reading 'schedule')
Below is the code:
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import BackgroundTask from 'react-native-background-task';
// import { Notifications, Permissions, Constants } from 'expo';
import * as Notifications from 'expo-notifications';
import * as Permissions from 'expo-permissions';
import React, { useEffect } from 'react'
console.log("object")
BackgroundTask.define(async () => {
console.log("bgtask")
// if time is 12pm, fire off a request with axios to fetch the pills info
// Notification configuration object
const localNotification = {
title: text,
body: 'msg',
data: data,
ios: {
sound: true
}
}
// trigger notification, note that on ios if the app is open(in foreground) the notification will not show so you will need to find some ways to handling it which is discribed here https://docs.expo.io/versions/latest/guides/push-notifications
Notifications
.presentLocalNotificationAsync(localNotification)
.catch((err) => {
console.log(err)
})
BackgroundTask.finish()
})
export default function App() {
useEffect(() => {
console.log("uef")
const componentDidMount = async () => {
// allows the app to recieve notifications (permission stuff)
console.log("cdm")
registerForPushNotificationsAsync().then(() => {
console.log("bg sche")
BackgroundTask.schedule()
}).catch((e) => {
console.log("err")
console.log(e)
});
}
componentDidMount()
}, []);
const registerForPushNotificationsAsync = async () => {
console.log("reg")
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
if (status !== 'granted') {
console.log("permission not granted")
return;
}
console.log("permission granted")
let deviceToken = await Notifications.getExpoPushTokenAsync()
}
return (
<View style={styles.container}>
<Text>Open up App.js \o start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
The problem comes when I do the BackgroundTask.schedule() function. It says in the error that BackgroundTask is undefined. I know for a fact that all the other functions worked fine because the console.logs all get printed right until "bg sche" and then it goes and print "err" in the catch block.
I also tried to use ctrl + click on the package name that should bring me to source where this BackgroundTask object is exported but it doesn't work like it usually does for other modules. So I think for some reasons the module can't be found but I have already installed it and it is in my package.json file and I see it in my node_modules folder.
I am attempting to integrate Facebook authentication into my app that interacts with firebase auth. I have followed the guide provided at the expo.dev docs for Facebook but am having a hard time getting it working. I am able to successfully log in to Facebook, and return an access_token. I am even successfully generating the firebase credential with FacebookAuthProvider.credential(access_token). But when trying to then authenticate with firebase I get a Cannot parse ID token. I was able to implement authentication with Google with no issues following the same methods but Facebook just will not work.
Here is the code in question:
import React, { useEffect, useState } from "react";
import { View } from "react-native";
import { FontAwesome5 } from "#expo/vector-icons";
import { useDispatch, useSelector } from "react-redux";
import * as WebBrowser from 'expo-web-browser';
import { ResponseType } from 'expo-auth-session';
import * as Facebook from 'expo-auth-session/providers/facebook';
import { addError } from "../../redux/actions/error.actions";
import { firebaseLogin } from "../../redux/actions/firebase.actions";
import { auth, facebookProvider } from '../../config';
WebBrowser.maybeCompleteAuthSession();
export default function FacebookLogin() {
const dispatch = useDispatch();
const [ request, response, promptAsync] = Facebook.useAuthRequest({
responseType: ResponseType.Token,
clientId: 'XXXXXXXXXXXXXXX',
});
useEffect(() => {
if (response?.type === 'success') {
const {access_token} = response.params;
console.warn(`access_token type: ${typeof access_token}`);
const credential = facebookProvider.credential(access_token);
auth.signInWithCredential(credential).then(
(userCredential) => {
if (userCredential.additionalUserInfo.isNewUser) {
console.warn('New Facebook User.');
} else {
dispatch(firebaseLogin(userCredential.user));
}
},
(error) => {
let email = error.email;
let credential = error.credential;
// TODO: Handle linking of account if credential exists.
if (error.code === "auth/popup-closed-by-user") {
console.log('user closed popup');
}
}
)
.catch((error) => {
setError(true);
setErrorMessage({ type: "Facebook Login", message: error });
dispatch(addError({ type: "Facebook Login", message: error }));
});
}
}, [response]);
return (
<View style={{ marginBottom: 10 }}>
<FontAwesome5.Button
name="facebook-f"
backgroundColor="#3B5998"
onPress={promptAsync}
borderRadius={24}
size={18}
style={{ marginLeft: 7, marginRight: 7 }}
>
Sign In with Facebook
</FontAwesome5.Button>
</View>
)
}
The only thing not visible in this component is how auth and facebookProvider are defined.
import firebase from 'firebase/app';
import 'firebase/auth';
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
} else {
firebase.app();
}
export const auth = firebase.auth();
export const facebookProvider = new firebase.auth.FacebookAuthProvider();
export {firebase};
You have to enable 'Advanced Access' for 'public_profile'. Also any other fields you request at login, in my case I was grabbing the 'email' field as well. This is under App Review -> Permissions and Features in the Facebook Developer Console.
Img of FB Dev Console Location
Also make sure you are using the function without the nonce if you are using a custom button instead of the default Facebook one. That was also an issue I had with this.
let loginManager = LoginManager()
loginManager.logIn(permissions: ["public_profile", "email"],from: controller) { result, error in
if let error = error {
print(error.localizedDescription)
return
}
guard let idTokenString = result.token?.tokenString
else { throw NSError() }
let credential = OAuthProvider.credential(withProviderID: "facebook.com",
accessToken: idTokenString)
Auth.auth().signIn(with: credential) { (authResult, error) in }
}
I am trying to navigate to a certain screen whenever I click on an Expo Push Notification. The screen that I want to navigate to is rather deep into the NavigationContainer.
However, the issue that I am facing now is being unable to even navigate to anywhere except having the app restart on its own. I'm running all the testing on a real device.
I'm using Expo to work on this school project.
I have only managed to find this question in SO and Expo Forums (duplicate) useful.
This is my application Navigation structure:
-Navigation Structure-
AppNavigator
DrawerNavigator
MainNavigator
TabsNavigator
StackNavigator
StackNavigator
TabsNavigator
ScreenA (Want to navigate to)
ScreenB (Want to navigate to)
StackNavigator
ScreenA
ScreenB
StackNavigator
ScreenA
AuthNavigator
RegisterNavigator
ScreenA
There is a useNotifications hook created and I called it in the main App Navigator where the NavigationContainer resides in.
import React, { useEffect } from 'react';
import * as Notifications from 'expo-notifications';
import navigation from '../navigation/RootNavigation';
const useNotifications = () => {
const notiResponseListener = React.createRef();
useEffect(() => {
notiResponseListener.current =
Notifications.addNotificationResponseReceivedListener(res => {
console.log(res.notification.request.content.data);
console.log('addNotificationResponseReceivedListener');
navigation.navigate(
('DrawerNavigator', { screen: 'ChangePassword' }),
{}
);
});
return () =>
Notifications.removeNotificationSubscription(notiResponseListener);
}, []);
};
export default useNotifications;
There is a ref added to the NavigationContainer.
import { navigationRef } from '../navigation/RootNavigation';
import useNotifications from '../hooks/useNotifications';
const App = createStackNavigator();
const AppNavigator = () => {
useNotifications();
return (
<NavigationContainer ref={navigationRef}>
<App.Navigator headerMode='none'>
...
</App.Navigator>
</NavigationContainer>
);
};
And lastly, the file that contains the ref used in the NavigationContainer.
import React from 'react';
export const navigationRef = React.createRef();
const navigate = (name, params) => {
console.log('entered navigating'); // does not print
navigationRef.current?.navigate(name, params);
};
export default {
navigate
};
I have searced high and low but I can't seem to find out what's wrong. Looked at the documentation for Expo and React Navigation but I'm not sure what's going on. It's my first time working on Push Notifications and such a case.
I appreciate any help, thank you
We have fixed the problem with the usage of useLastNotificationResponse.
const [notification, setNotification] = useState(false);
const notificationListener = useRef();
const responseListener = useRef();
//add this
const lastNotificationResponse =
Notifications.useLastNotificationResponse();
useEffect(() => {
if (lastNotificationResponse) {
//console.log(lastNotificationResponse);
//get the route
const route = JSON.stringify(
lastNotificationResponse.notification.request.content.data.route
);
//use some function to return the correct screen by route
getFullPath(JSON.parse(route));
}
}, [lastNotificationResponse]);
Based on your routes, navigate to correct screen
getFullPath:
import { navigationRef } from "./rootNavigation";
import routes from "./routes";
export function getFullPath(route) {
switch (route) {
case "HomeScreen":
return navigationRef.current?.navigate(routes.HOME);
case "Account":
return navigationRef.current?.navigate(routes.ACCOUNT, {
screen: routes.ACCOUNTSCREEN,
});
default:
return;
}
}
I am using Okta-React for authentication in my React project and when I run the React test server my login authenticates successfully and redirects to the account page. When I run the React build command and render the build files with Django, my login authenticates properly, but when it redirects back to my site I get a blank /implicit/callback page, no login token or user info, and the code & state gets stuck in the URL. Does anyone know why this is only happening when using Django, and what I can do to resolve this issue?
Here is my authConfig:
const config = {
issuer: 'https://dev-#######.okta.com/oauth2/default',
redirectUri: window.location.origin + '/implicit/callback',
clientId: '#################',
pkce: true
};
export default config;
Here is my accountAuth
import React, { useState, useEffect } from 'react';
import { useOktaAuth } from '#okta/okta-react';
import '../scss/sass.scss';
import "../../node_modules/bootstrap/scss/bootstrap.scss";
import 'react-bootstrap';
const AccountAuth = () => {
const { authState, authService } = useOktaAuth();
const [userInfo, setUserInfo] = useState(null);
useEffect(() => {
if (!authState.isAuthenticated) {
// When user isn't authenticated, forget any user info
setUserInfo(null);
} else {
authService.getUser().then((info) => {
setUserInfo(info);
});
}
}, [authState, authService]); // Update if authState changes
localStorage.setItem("username", userInfo && userInfo.given_name)
const login = async () => {
// Redirect to '/account_page' after login
localStorage.setItem("accountLink", "/account_page")
localStorage.setItem("loginPostingVisibilityStyle", { display: "none" })
localStorage.setItem("postingVisibleStyle", { display: 'block' })
authService.login('/auth_index');
}
const logout = async () => {
// Redirect to '/' after logout
localStorage.setItem("username", null)
localStorage.setItem("accountLink", "/auth_index")
localStorage.setItem("loginPostingVisibilityStyle", { display: "block" })
localStorage.setItem("postingVisibleStyle", { display: 'none' })
authService.logout('/');
}
return authState.isAuthenticated ?
<button className="settings-index" onClick={logout}>Logout</button> :
<button className="settings-index" onClick={login}>Login</button>;
};
export default AccountAuth;
Here is an example of the URL when it's stuck
http://localhost:8000/implicit/callback?code=-mRoU2jTR5HAFJeNVo_PVZsIj8qXuB1-aioFUiZBlWo&state=c9RXCvEgQ4okNgp7C7wPkI62ifzTakC0Ezwd8ffTEb29g5fNALj7aQ63fjFNGGhT
It doesn't look like you're handling the callback to exchange the authorization_code for tokens. You might want to check out Okta's React sample app to see how it works.