Determining if geolocation enabled with react native - ios

Building an app with RN I use the following to receive user's location :
navigator.geolocation.getCurrentPosition(
(position) => {
//do stuff with location
},
(error) => {
//error or locaiton not allowed
},
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
);
Which immediately invokes the inquiry for user to accept geolocation permissions. What I'm trying to achieve now is to have an explicit screen before prompting user to click on a button to accept those permissions. In order to get there, I need some way to check if he has accepted those permissions before or not. Caching it in storage would be a bad solution - it might go out of sync if user changes permissions in settings.
How can I check if user has accepted geolocation permissions without triggering the permission alert?

You can use this library https://github.com/yonahforst/react-native-permissions to check if user has accepted location permission.
Like this:
Permissions.getPermissionStatus('location')
.then(response => {
this.setState({ locationPermission: response })
})

In v2.x.x of react-native-permissions (https://github.com/react-native-community/react-native-permissions)
import { Platform } from "react-native";
import { PERMISSIONS, request } from "react-native-permissions";
import * as Geolocation from "#react-native-community/geolocation";
try {
request(
Platform.select({
android: PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
ios: PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
})
).then(res => {
if (res == "granted") {
Geolocation.getCurrentPosition( // do location staffs);
Geolocation.watchPosition( // do watch location staffs );
} else {
// console.log("Location is not enabled");
}
});
} catch (error) {
console.log("location set error:", error);
}

Check this library, this would help you to check location is enabled or not.
https://www.npmjs.com/package/react-native-device-info#isLocationEnabled
Note : Above will not check permission enabled on not. It will just check location truned on or not

Related

Ionic - How to request permission again after user rejected once?

Currently, I can request permission for microphone with the following code if the user has not rejected granting permissions:
permission = await this.diagnostic.isMicrophoneAuthorized();
if (!permission) {
permission = await this.diagnostic.requestMicrophoneAuthorization()
.then(async () => {
console.log('this.diagnostic.requestMicrophoneAuthorization succeed.');
return await this.diagnostic.isMicrophoneAuthorized();
})
.catch((err) => {
console.error('this.diagnostic.requestMicrophoneAuthorization failed, error: ', err);
return false;
})
}
But once they reject the request, the requestMicrophoneAuthorization is still triggered, but no dialog pop up and the result always returns false.
Is there a way to request the authorization again with Ionic 3?
To do this, you will need to use the cordova-diagnostic-plugin to check the current microphone authorization status and request authorization again if it has been denied.
import { Diagnostic } from '#ionic-native/diagnostic/ngx';
constructor(private diagnostic: Diagnostic) {}
async requestMicrophoneAuthorization() {
// Check the current microphone authorization status
let authorizationStatus = await this.diagnostic.getMicrophoneAuthorizationStatus();
if (authorizationStatus === this.diagnostic.permissionStatus.DENIED_ALWAYS) {
// If the authorization has been denied always, we need to ask the user to grant
// microphone permission again.
try {
// Request microphone authorization
authorizationStatus = await this.diagnostic.requestMicrophoneAuthorization();
console.log('Microphone authorization status: ', authorizationStatus);
} catch (error) {
console.error('Error requesting microphone authorization: ', error);
}
}
}

React native expo implementing Apple App Tracking Transparency (ATT) for iOS 14.5

What is the best way of implementing the Apple App Transparency Tracker (ATT) feature on react native expo? My app keeps getting rejected by apple even after I add:
app.json file :
"infoPlist": {
"NSUserTrackingUsageDescription": "App requires permission...."
}
On iOS 14 Apple introduced the App Tracking Transparency permission to access IDFA.
You need to prompt the user whether it allows your app to use libraries that track them or not, adding it on infoPlist just allows you to use this API within your application.
Expo doesn't have this feature yet, but some libraries you can use to prompt the permission
Example: https://docs.expo.io/versions/v41.0.0/sdk/facebook/#facebookgetpermissionsasync
You can use other libraries , such as https://github.com/mrousavy/react-native-tracking-transparency
where you can request the App tracking like
import { getTrackingStatus } from 'react-native-tracking-transparency';
const trackingStatus = await getTrackingStatus();
if (trackingStatus === 'authorized' || trackingStatus === 'unavailable') {
// enable tracking features
}
import { requestTrackingPermission } from 'react-native-tracking-transparency';
const trackingStatus = await requestTrackingPermission();
if (trackingStatus === 'authorized' || trackingStatus === 'unavailable') {
// enable tracking features
}
This might need an update in a near future, as expo releases a new SDK version with a solution for that.
EDIT
From Expo 44+
Expo now have a library for TrackTransparency: (https://docs.expo.dev/versions/latest/sdk/tracking-transparency/)
expo install expo-tracking-transparency
For bare applications: https://github.com/expo/expo/tree/main/packages/expo-tracking-transparency#installation-in-bare-react-native-projects
You can add it as a plugin at your app.json
{
"expo": {
"plugins": [
[
"expo-tracking-transparency",
{
"userTrackingPermission": "This identifier will be used to deliver personalized ads to you."
}
]
]
}
}
And now you can use like this:
import React, { useEffect } from 'react';
import { Text, StyleSheet, View } from 'react-native';
import { requestTrackingPermissionsAsync } from 'expo-tracking-transparency';
export default function App() {
useEffect(() => {
(async () => {
const { status } = await requestTrackingPermissionsAsync();
if (status === 'granted') {
console.log('Yay! I have user permission to track data');
}
})();
}, []);
return (
<View style={styles.container}>
<Text>Tracking Transparency Module Example</Text>
</View>
);
}
You need to request Tracking permissions first (I used react-native-permissions):
import { request, RESULTS, PERMISSIONS } from 'react-native-permissions'
export const requestPermissionTransparency = async () => {
return await request(PERMISSIONS.IOS.APP_TRACKING_TRANSPARENCY)
}
useEffect(() => {
;(async () => {
const result = await requestPermissionTransparency()
if (result === RESULTS.GRANTED) {
//You need to enable analytics (fb,google,etc...)
await firebase.analytics().setAnalyticsCollectionEnabled(true)
console.log('Firebase Analytics: ENABLED')
}
})()
}, [])
Remember to add this file in the root project:
// <project-root>/firebase.json
{
"react-native": {
"analytics_auto_collection_enabled": false
}
}
References: https://rnfirebase.io/analytics/usage
The solution I ended up using from expo was using the Facebook.getPermissionsAsync()
https://expo.canny.io/feature-requests/p/expo-permissions-add-support-to-apptrackingtransparency-permission-on-ios
Expo 41+
TrackingTransparency:
https://docs.expo.io/versions/latest/sdk/tracking-transparency/
import { requestTrackingPermissionsAsync } from 'expo-tracking-transparency';
const { status } = await requestTrackingPermissionsAsync();
if (status === 'granted') // do something
Expo 40 and below
Admob: https://docs.expo.io/versions/latest/sdk/admob/
import { requestPermissionsAsync } from 'expo-ads-admob'
const { status } = await requestPermissionsAsync()
if (status === 'granted') // do something

Turn on Wifi and connect to a protected SSID on ios with react native

I am working on IOT project with react native in which Phone must connect to a protected WiFi(no internet connection). I should programmatically turn on WiFi and connect to the protected ssid. So, I used the following library: https://github.com/JuanSeBestia/react-native-wifi-reborn.
On android, I have full control on device and everything works like a charm. On the other hand, on ios, I can't turn wifi on and even after that user turns the wifi on, it seems defined functions in library like connectToProtectedSSID just doesn't work.
Any advice would be appreciated.
P.s. I exactely followed the document in the library including location access in both platforms.
Finally, the solution for both platforms:
iOS:
with the following approach app will turn on WIFI and connect to the specific SSID (at least for iOS 13):
You should add these capabilities to your app :
Access WiFi Information
Hotspot Configuration ( this is missed in the README ! )
(iOS 13) "Privacy - Location When In Use Usage
Description" or "Privacy - Location Always and When In Use Usage
Description" in Settings -> info
import WifiManager from "react-native-wifi-reborn";
ConnectToNetwork = async () => {
WifiManager.connectToProtectedSSID("YourSSIDName", "YourPassword", false)
.then(
() => {
//console.log("connectToProtectedSSID successfully!");
},
(reason) => {
//console.log("connectToProtectedSSID failed!");
//console.log(reason);
}
);
}
Android:
Don't forget to turn on location!
disconnecting from the current SSID and connecting to the desired one:
import RNAndroidLocationEnabler from 'react-native-android-location-enabler';
import WifiManager from "react-native-wifi-reborn";
ConnectToNetwork() {
WifiManager.setEnabled(true);
WifiManager.disconnect();
//WifiManager.forceWifiUsage(true);
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: '',
message:'',
buttonNegative: '',
buttonPositive: '',
},
).then((granted) => {
//console.log(granted);
if (granted === PermissionsAndroid.RESULTS.GRANTED)
{
//console.log("granted");
RNAndroidLocationEnabler.promptForEnableLocationIfNeeded({interval: 10000, fastInterval: 5000})
.then(data => {
WifiManager.connectToProtectedSSID("YourSSIDName", "YourPassword", false)
.then(
() => {
//console.log("connectToProtectedSSID successfully!");
},
(reason) => {
//console.log("connectToProtectedSSID failed!");
//console.log(reason);
}
);
//console.log("location enabled");
//WifiManager.connectToProtectedSSID("", "", false)
WifiManager.getCurrentWifiSSID().then(
ssid => {
if(ssid =="YourSSIDName"){
}
else {
}
//console.log("Your current connected wifi SSID is " + ssid);
},
() => {
//console.log("Cannot get current SSID!");
}
);
}).catch(err => {
//console.log("not permitted to enable location");
});
}
else
{
//console.log("not granted");
// Permission denied
}
// expected output: "Success!"
});
}
There is no public API to control the Wifi on iOS.
Method setEnabled is only for android.

React Native Ios Push Notification Not Working

I use '#react-native-firebase/messaging' module to send notifications. On Android everything works fine, Following is the error log I get when I try const fcmToken = await firebase.messaging().getToken(); on ios device.
NativeFirebaseError: [messaging/unknown] The operation couldn’t be completed. (com.firebase.iid error 1001.)
I have already implemented "react-native-permissions" to grant notification permission.
My AppDelegate.m contains :
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}
Should I add anything else to it?
Any help or suggestion will be very helpful.
Thanks in advance
You need to check and ask messaging permission before get the fcm token in iOS
/**
* Check is notification showing permission enabled if not ask the permission.
*/
async checkFcmPermission() {
firebase
.messaging()
.hasPermission()
.then(enabled => {
if (enabled) {
// User has permissions
this.getFcmToken(); // const fcmToken = await firebase.messaging().getToken();
} else {
// User doesn't have permission
firebase
.messaging()
.requestPermission()
.then(() => {
// User has authorized
this.getFcmToken(); // const fcmToken = await firebase.messaging().getToken();
})
.catch(error => {
// User has rejected permissions
console.log(
'PERMISSION REQUEST :: notification permission rejected',
);
});
}
});
}
There are a lot of solutions to this issue. I post my answer since some StackOverflow users requested.
Here is my code
const sleep = ms => {
return new Promise(resolve => setTimeout(resolve, ms));
};
async function requestPermissionForNotification() {
try {
const permission = await requestNotifications(["alert", "badge", "sound"]);
if (permission.status === "granted") {
setupNotification();
}
} catch (e) {
console.log(e)
}
};
async function setupNotification() {
try {
await sleep(5000)
// TODO no need token for now, Will be used for future releases
const enabled = await firebase.messaging().hasPermission();
await requestNotifications(['alert', 'badge', 'sound']);
await firebase.messaging().registerForRemoteNotifications();
const token = await firebase.messaging().getToken();
firebase.messaging().onMessage(async (remoteMessage) => {
});
} catch (e) {
console.log(e)
}
}
And Also I have added following to Info.plist
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
To sum up, I use react permissions to grant permission and the sleep method is to wait for firebase to be ready. Finally uninstalled app couple time to get a result.
When It started working, I couldn't dare to touch the code since I spent days on this.

How to tell when use has answered iOS Notification Permissions request in React-Native

in iOS, in order to allow push notifications, the user must do 1 of the following 2 options.
answer the original prompt which asks permission for notifications. If they don't do this, you can't bring up the permission request again, so you must redirect them to the settings page.
Go to the settings page and manually change the permissions.
Here's my flow now:
Check permissions: if they have them, move to the next screen.
if they don't, show an alert stating why notifications are important for our app. If they click ok, it shows the real notification screen, if not it just waits to ask later.
If the user already saw the request for notifications screen, I want to show a dialog that asks them to go the settings to allow notifications.
Is there a way of knowing whether the user said yes or no to the original permission box? Is there a way to know when they've answered it?
The way I'm checking now doesn't wait for the user to click on an option in the original dialogue box, so it doesn't wait to check permissions and find s them the exact same as they were before.
is there any way to check whether they've had the request for permissions already and whether they said yes or no?
Here's the code I'm using:
(only relevant imports)
import {PushNotificationIOS} from 'react-native
import PushNotification 'react-native-push-notification'
const requestPermissionsIOS = navigateForward => {
PushNotification.requestPermissions().then( ({alert}) => {
if (!alert) {
settingsAlertIOS(navigateForward)
} else {
configurePushNotification()
scheduleNotifications()
navigateForward()
}
}).catch( err => {
settingsAlertIOS(navigateForward)
})
}
const configurePushNotification = () => {
PushNotification.configure({
onRegister: (token) => {
},
onNotification: (notification) => {
onNotification: notification => handleNotification(notification)
},
permissions: {
alert: true,
badge: true,
sound: true
},
popInitialNotification: true,
requestPermissions: false,
});
}
const settingsAlertIOS = (navigateForward) => {
Alert.alert(
'Go to settings page?',
'In order to receive important notifications, please enable them in the settings page \(leaves app\)',
[
{text: 'Cancel', onPress: () => {Mixpanel.track('Decline change notifications from settings alert'); scheduleNotifications(); navigateForward()}},
{text: 'Settings', onPress: () => {configurePushNotification(); scheduleNotifications(); navigateForward(); Linking.openURL('app-settings:')}},
]
)
}
To listen to the user's decision.
PushNotification.requestPermissions().then((response: any) => {
if (response && response.alert !== 0) {
// Allow
return;
}
// Decline
});
Credit - jose920405

Resources