React Native expo-permission deprecated what to use now? - react-native

I am using Permissions from the expo-permission Library to get the location coords of the user:
import * as Location from "expo-location";
import * as Permissions from 'expo-permissions';
const granted = await Permissions.askAsync(Permissions.LOCATION);
The above works but keeps giving the warning that expo-permissions is deprecated.
If I use:
import {Location, Permissions } from 'expo';
it says Cannot read property 'askAsync' of undefined.
Does someone know what i should use? I use sdk42
Thx!

As this blog by Brent Vatne says,
expo-permissions has been deprecated in favor of module-specific permissions methods You should migrate from using
Permissions.askAsync and Permissions.getAsync to the permissions
methods exported by modules that require the permissions.
For example: you should replace calls to
Permissions.askAsync(Permissions.CAMERA) with
Camera.requestPermissionsAsync()
There shouldn’t be two ways to do an identical thing in a single SDK,
and so we picked our preferred approach and are consolidating around
it.
So now, you will have to use Permissions from individual packages
For Location,
Firstly, install expo-location
expo install expo-location
Then you can use it like this
import * as Location from 'expo-location';
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
console.log('Permission to access location was denied');
return;
}

If someone comes here and wants to get permissions for ImagePicker, then according to the docs you should do this:
import * as ImagePicker from "expo-image-picker";
const getPermissionAsync = async () => {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== "granted") {
alert("...");
}
};

Now with expo, each libs have their own permissions requests methods.
Example with Location:
let { status } = await Location.requestForegroundPermissionsAsync();
Documentation

works:
import { Camera } from 'expo-camera';
import * as ImagePicker from "expo-image-picker";
const resultPermision = await Camera.requestCameraPermissionsAsync();
const resultPermisionCamera = resultPermision.status;
if (resultPermisionCamera === "denied") {
toastRef.current.show("Gallery permissions are needed");
} else {
const result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 3]
})
........
Now, expo-camera works great, but also I believe something is pending on the side of the app.json.
Do you still need to add these lines?:
"permissions": [
"CAMERA",
"WRITE_EXTERNAL_STORAGE",
"CAMERA_ROLL"
question for everyone here :)

import { Camera } from "expo-camera";
this.state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
};
componentDidMount = async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
this.setState({ hasCameraPermission: status === "granted" });
};

Related

#react-native-async-storage/async-storage getItem is giving value as false

I am trying to access react-native Async storage in a different file from where it has been set. In the same file where it is being set , i am able to get the value. but in the different file i am getting "false" as the value.
Any help would be greatly be appreciated.
import AsyncStorage from '#react-native-async-storage/async-storage';
const getData = async () => {
console.log("fetching data from asyncstorage")
try {
const value = await AsyncStorage.getItem('userToken'); << retuning false
if(value !== null) {
console.log(value);
token.token=value;
}
} catch(e) {
console.log(e);
}
}
const callfunction=()=>{
getData();
}
This is how i was able to make it work,If somebody got a better solution please do post here,
As operation with AsyncStorage are happening in async manner, meaning the main thread will not wait for the function call to be coompleted, i found it best to call the function way before i needed it and keep it stored.
In order to acheive this i used a react hook "useEffect" this is similar to springboot alternative #PostConstruct, meaning "useEffect" will be called the moment you are navigate to the page. So the code looks something like this.
import AsyncStorage from '#react-native-async-storage/async-storage';
import React,{useEffect} from 'react';
const [token, setToken] = React.useState({
token: "",
});
const getData = () => {
console.log("fetching data from asyncstorage")
AsyncStorage.getItem('userToken').then((value) => {
console.log("token : "+ value);
token.token=value;
}).done();
}
useEffect(() => {
if(token.token=="")
{
getData();
}
});
If someone finds any good blog or video supporting this do post it here, also if my explanation, is deviating from technical aspect please help me understand it better.

React Native Expo Location Permissions, requestForegroundPermissionsAsync, requestBackgroundPermissionsAsync how make them work

I am working on an app that records the location when the aplication is active or in the background.
After Permissions.getAsync got depricated, my app is not recording the coordonates when in background.
I understand I have to change to requestForegroundPermissionsAsync and requestBackgroundPermissionsAsync but I can not make it work.(I don't know how to use requestBackgroundPermissionsAsync)
Here is the code:
import { useState, useEffect } from 'react';
import {
Accuracy,
requestForegroundPermissionsAsync,
requestBackgroundPermissionsAsync,
watchPositionAsync
} from 'expo-location';
export default (shouldTrack, callback) => {
const [err, setErr] = useState(null);
useEffect(() => {
let subscriber;
const startWatching = async () => {
try {
const { granted } = await requestForegroundPermissionsAsync()
if (!granted) {
throw new Error('Location permission not granted');
}
subscriber = await watchPositionAsync(
{
accuracy: Accuracy.BestForNavigation,
timeInterval: 1000,
distanceInterval: 10
},
callback
);
} catch (e) {
setErr(e);
}
};
Question needs additional information to troubleshoot. For starters, are you on iOS\Android\both? Does it work on one platform but not the other? What permissions are listed in app.json (is this a managed\bare workflow)? Are the foreground updates working? Background updates require additional code and none of that is included here.
Have you gone through Expo's documentation? https://docs.expo.io/versions/latest/sdk/location

Possible Unhandled Promise Rejection (id:0) TypeError: undefined is not an object (evaluating 'ImagePicker.Permissions.askAsync)

I am building an iOS app using React-Native and Expo. I have figured out how to access the user's Photo Library but am unable to request permissions from their device. It instead just accesses the camera roll without asking, which is obviously not allowed in iOS. Below is some of my code:
import React, {useState, useEffect, useRef} from 'react';
import * as ImagePicker from 'expo-image-picker';
import Permissions, {usePermissions} from 'expo-permissions';
import Constants from 'expo-constants'
//The useEffect function is what is ran when checking to see if the async function has been accepted or not
const Screen = ({navigation}) => {
const [ imagePicker1, setImagePicker1 ] = useState(null);
useEffect(() => {
const permission_get1 = async ()=> {
if (Platform.OS !== 'web'){
let { status } = await ImagePicker.Permissions.askAsync(Permissions.MEDIA_LIBRARY);
if (status !== 'granted'){
console.log('No permission given')
alert('Camera roll required for to upload photo from your library');
return;
}
/*if (status === 'granted'){
console.log('Permission granted')*/
let imagePicker1 = await ImagePicker.getMediaLibraryAsync()
setImagePicker1(imagePicker1)
console.log('It worked')
}
};
permission_get1();
}, []);
I ended up getting it to work using this: I believe the previous example was using a depreciated method.
import * as ImagePicker from 'expo-image-picker'
const pickImage = async ()=>{
const { granted } = await Permissions.askAsync(Permissions.CAMERA_ROLL)
if(granted){
console.log('access granted')
let data = await ImagePicker.launchImageLibraryAsync({
mediaTypes:ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect:[1,1],
quality:0.5,
})
console.log(data)
if (!data.cancelled){
setImage(data.uri);
}
}else{
Alert.alert('Permissions required to access camera roll.')
}
}

Expo react-native bare workflow using Push notifications

Firstly i will be really appreciated for your helps.
I'am trying to implement expo push notification using expo-bare workflow. When i run app, it gives me error like this so i could not get token.
error [TypeError: null is not an object (evaluating '_ExponentNotifications.default.getExponentPushTokenAsync')]
Here is my code:
import { Notifications } from "expo";
import * as Permissions from "expo-permissions";
import Constants from "expo-constants";
export const getToken = async () => {
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();
}
else {
console.log("Must use physical device for Push Notifications");
}
return token;
};
You need to install the expo notifications package:
expo install expo-notifications also don't forget to cd into the ios folder and run pod install to properly link the package.
Next, you need to change the way you import and use Notifications like:
import * as Notifications from 'expo-notifications';
Then to get expo token you do something like:
Notifications.getExpoPushTokenAsync({experienceId:'#your_username/your_app_slug'})
which would resolve to a promise containing your expo token in an object format like:
{"data": "ExponentPushToken[ID]", "type": "expo"}
NB: Most method support in the Notifications from expo is different from the one in expo-notifications. You should check here for more details.
To expand on my comment some, I had a similar setup as yours when I was on Expo managed, but I ejected. According to their docs, the bare workflow is a little different, and so mine is set up like this:
// at the top:
import * as Notifications from 'expo-notifications';
// --------
// inside the code:
let settings = false
settings = Notifications.getPermissionsAsync()
if (!settings.granted) {
settings = Notifications.requestPermissionsAsync()
}
if (settings.status === 1 || settings.status === 'granted') {
const experienceId = '#proj/example' // (see docs on using expo credentials:manager)
const token = Notifications.getExpoPushTokenAsync({ experienceId })
const resp = api.sendNotificationToken({ token: token.data })
}

Integrating Amplitude Analytics to React Native App with Expo

I am trying to integrate Amplitude to my React Native project. I am currently still developing the application and using Expo. The first event I am trying to capture is when a user is logged in.
const events = {
USER_LOGGED_IN: 'USER_LOGGED_IN',
USER_CREATED_ACCOUNT: 'USER_CREATED_ACCOUNT',
};
let isInitialized = false;
const apiKey = 'xxxxxxxxxxxxxxxxxxxxxxxx';
const initialize = () => {
if (!Environment.isProduction || !apiKey) {
return;
}
Amplitude.initialize(apiKey);
isInitialized = true;
};
In my render function (above the return) I have this line of code:
render() {
Expo.Amplitude.logEvent('USER_LOGGED_IN')
return (
I am not seeing any events coming into amplitude. Is it possible to see events while using expo to run my code?
Note- this code is in my home screen component
You need to publish your Expo app to see the events on Amplitude because the integration works only on prod env. Once your app is published, you'll see the events on Amplitude dashboard with a small delay, usually 1 minute.
This is what I did for amplitude to work
expo install expo-analytics-amplitude
Analytics.js
import * as Amplitude from 'expo-analytics-amplitude'
let isInitialized = false
const apiKey = 'YOUR_KEY_HERE'
export const events = {
HOME: 'HOME'
}
export function initialize() {
if (isInitialized || !apiKey) {
return
}
Amplitude.initialize(apiKey)
isInitialized = true
}
export function track(event, options) {
initialize()
if (options) {
Amplitude.logEventWithProperties(event, options)
} else {
Amplitude.logEvent(event)
}
}
export default {
events,
initialize,
track
}
Import in the file where you need tracking
import Analytics from '../auth/Analytics'
...
useEffect(() => {
Analytics.track(Analytics.events.HOME)
}, [])
Expanding on the code above, I made a few minor updates. I will update this if I find a better way to fully integrate.
expo install expo-analytics-amplitude
import * as Amplitude from 'expo-analytics-amplitude'
let isInitialized = false
const apiKey = 'your API key'
export const events = {
HOME: 'HOME'
}
export function initialize() {
if (isInitialized || !apiKey) {
return
}
Amplitude.initializeAsync(apiKey)
isInitialized = true
}
export function track(event, options) {
initialize()
if (options) {
Amplitude.logEventWithPropertiesAsync(event, options)
} else {
Amplitude.logEventAsync(event)
}
}
export default {
events,
initialize,
track
}
Import into the file you need tracking.
I initialized my connection to Amplitude in App.js.
import Analytics from "./app/auth/Analytics";
useEffect(() => {
Analytics.initialize()
Analytics.track(Analytics.events.HOME)
}, []);