React Native geolocation heading is always -1 on iPhone 7 - react-native

I am faced an issue that I can't solve for a weeks.
Task: I heed to watch for a device position and its direction.
Solution: I use method as described in docs
this.watcher = navigator.geolocation.watchPosition((position) => {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
const heading = position.coords.heading;
this.setState({
latitude: latitude,
longitude: longitude,
heading: heading
});
},
(error) => {
console.log(`error: ${error}`);
},
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0
});
Eevrything works fine on simulator. But on a real iOS device heading is always -1.
My project use RN 0.54. However I just created fresh project with RN 0.56 via react-native init and behavior is the same.
The thing is that in react-native-maps package user direction renders in a perfect way, so I assume that there may be some issue with React Native
Any help?

Since React Native geolocation is an extension over web geolocation (see docs),
it gets orientation(heading) as a difference between two last positions. Which is not working at low speed or when user stays (returns -1).
Which is strange, because I expected RN to get device heading from built in "compass".
Solution for ejected apps: use thirds party library react-native-heading to get device heaing even when user stays.
Solution for Expo: there should be no problem like this because Expo use built in compass instead of web geolocation.

Using Location.getHeadingAsync() I was able to get a heading direction to not be -1.
Check out this link for the expo method I am using:
https://docs.expo.io/versions/latest/sdk/location#expolocationgetheadingasync-215

Related

React-Native Expo Managed App: How do I enable sharing?

I'm using Expo SDK v. 45, iPhone 13 Pro (iOS v. 15.5), expo-sharing v. 10.1.1.
I'm currently using expo start --dev-client to test my app on my iPhone. I need to be able to share a file, created inside the app, with the outside world. I found expo-sharing to achieve this. Unfortunately, when I run
install * as Sharing from 'expo-sharing';
...
useEffect( async () => {
const canShare = await Sharing.isAvailableAsync();
if (canShare) {
console.log("available");
} else {
console.log("Not available");
}
}, []);
I get 'Not available'.
What must I do to get my app to allow sharing? I can't find anything in the Expo documentation.
Thank you.
In case anybody else has a similar issue: all I had to do was rebuild the app and reinstall it on my phone. Now it works.

React Native IAP getSubscriptions returns empty array for iOS

I am following this library to implement In App Purchase for react native project.
Project info:-
inside package.json
"dependencies": {
"react": "16.11.0",
"react-native": "0.61.5",
"react-native-iap": "^4.4.9"
},
And I am trying to get product list,
import * as RNIap from 'react-native-iap';
const itemSkus = Platform.select({
ios: [
'com.cooni.point1000',
'com.cooni.point5000', // dooboolab
],
android: [
'com.example.coins100'
]
});
try {
const result = await RNIap.initConnection();
await RNIap.consumeAllItemsAndroid();
console.log('result', result);
if(result == true){
console.log("itemSkus>>>", itemSkus)
const products = await RNIap.getSubscriptions(itemSkus);
console.log("getting_products>>>", products)
this.setState({ products });
}
} catch(err) {
console.warn(err); // standardized err.code and err.message available
}
I am getting true for initConnection but getting [] (empty array) for getSubscriptions and also for getProducts()
By the way, I am getting empty array also for project which is in testFlight for using subscription ids that I have created. Those are in "Waiting for review state"
Is it not possible to get result using above test iap ids and ids that are in "Waiting for review state"?
How can I get response either using example or real ids?
Any help should be appreciable.
These are the possible solutions please check
The products are not in the 'Ready To Submit' state (make sure you've added the screenshot).
You haven't signed your Paid Applications Agreement in App Store Connect
You're testing on an emulator instead of a physical device.
My experience with RN-IAP for iOS was that it is super-unreliable, and plagued with issues where it works differently from documentation, and differently from Android version. The best solution I found was to switch to RevenueCat service for purchase management - that works great, after about an year of use I have not encountered any issues or differences between Android and iOS.
I was having the same problem and found that it worked if I removed the bundle ID from iOS product ID.
const itemSkus = Platform.select({
ios: [
'point1000',
'point5000', // dooboolab
],
android: [
'com.example.coins100'
]
});

How to detect screenshots with React Native (both Android and iOS)

I am trying to detect if a user takes a screenshot while using a smartphone app that I have built. I am building my project with React Native.
I have been told that I can possibly prevent screenshots for Android but not for iOS. but can I still detect whether a user attempts to take a screenshot so that I can at least send a warning via Alert?
Thanks in advance
I tried react-native-screenshot-detector but it did not work
you can use this package it supports android&ios screenshot detecting react-native-detector
import {
addScreenshotListener,
removeScreenshotListener,
} from 'react-native-detector';
// ...
React.useEffect(() => {
const userDidScreenshot = () => {
console.log('User took screenshot');
};
const listener = addScreenshotListener(userDidScreenshot);
return () => {
removeScreenshotListener(listener);
};
}, []);
There is no package for it currently.

Cannot get current position without GPS on react-native with navigator.geolocation

Brief summary after discussion and answers:
using EXPO sdk you cannot get the device location without grant FINE_LOCATION in android. FINE_LOCATION is the only method to get location, so, you cannot get the hardware.network.location. That means: with android > 6 you cannot get the current location using WIFI/mobile networks, you must enable Location.
Expo github discussion: https://github.com/expo/expo/issues/1339
The initial problem:
im working on a react-native application, using expo and react-native-maps, and i need to get the latitude and longitud of the user current position.
Im using navigator.geolocation API for that
with the GPS turned on i have no problems, but i need to get the current position without GPS, based on the network provider.
The problem is that when the application runs with expo on androiod > 6 i get this error:
21:50:53: Finished building JavaScript bundle in 449ms 21:50:55:
Location services are disabled
- node_modules\react-native\Libraries\BatchedBridge\NativeModules.js:80:57
in
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:347:19
in __invokeCallback
- ... 4 more stack frames from framework internals
In IOs and android <=5 it works great.
Here is the code of the component:
class MyComponent extends Component {
componentWillMount = () => {
this.getCurrentLocation();
}
getCurrentLocation = () =>
navigator.geolocation.getCurrentPosition(
(position) => {
let currentUserPosition = position.coords;
alert(JSON.stringify(currentUserPosition));
},
(error) => {
console.log(error);
},
{
enableHighAccuracy: false,
timeout: 20000,
maximumAge: 0,
distanceFilter: 10
}
);
}
And this are my package.json depencendies:
"dependencies": {
"expo": "23.0.4",
"native-base": "^2.3.5",
"react": "16.0.0",
"react-native": "0.50.4",
"react-native-extend-indicator": "^0.1.2",
"react-native-maps": "^0.19.0",
"react-native-maps-directions": "^1.3.0",
"react-native-router-flux": "4.0.0-beta.21",
"react-navigation": "1.0.0-beta.21",
"react-navigation-redux-debouncer": "^0.0.2",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
}
I expect that navigator.geolocation get the location based on the network provider in that situation (without gps), the specification saids that..
i also tried with the Geolocation API of expo (tried this example: https://snack.expo.io/#schazers/expo-map-and-location-example) , and with the GPS turned OFF i cant get my location..
so.. is there a way to achieve what i want? i am missing something?
EDIT (EXPO CONTRIBUTOR ANSWER):
I have posted the same at expo github (https://github.com/expo/expo/issues/1339), according to them it is imposible to get the current position using navigator.geolocation without any level of Location enabled in a android device.. so .. the only thing that could happen is that android versions older than 5 has location enabled by default and you can turn on just the GPS, and the versions 6 and forward you must specify the location level ..
any ideas?
EDIT2 (IMPORTANT !!):
I have confirmed this:
this is security settings of a Android 6 device, by default it uses GPS, i think that android 5 or lower doesnt, so thats the thing.. when i use the 2nd option it gets me the location !
the fact is that forcing a user to enable Location is like "hey, use your GPS!", and there are a lot of applications that gives you a aproximated position without turning on Location (like Uber for example), so the question is, is there a way that ONLY using wifi get the location with this api?
The problem you are dealing with here is with EXPO, because the location request API has changed after Android 5(API 21).
Before API 21, you needed to add to ACCESS_FINE_LOCATION (Both Wifi/Network and GPS providers) and ACCESS_COARSE_LOCATION (only GPS permission) location permissions. However, since Android 5, the apis changes to android.hardware.location.network and android.hardware.location.gps.
When your target users include both Android 5 +/-. you need to add both permission types to your android manifest, for example:
<manifest ... >
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- for Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.location.network" />
</manifest>
However, it seems that the people in expo, only included, the new permission in the android manifest. So what you need to do is to change android manifest. However, expo only gives access to pure JS part of the program and not to native codes. As a result, you need to detach from EXPO to add native modules or changes.
In expo documentation, the detachment process is explained in this link, the procedure is simple:
install expo package globally using npm:
npm install -g exp
Inside your project directory, run detachment code, it will build android and ios folders in your project directory:
exp detach
Then you can make the changes you need in android manifest file.
Common bug in Android. Try without using the third parameter:
getCurrentLocation = () =>
navigator.geolocation.getCurrentPosition(
(position) => {
let currentUserPosition = position.coords;
alert(JSON.stringify(currentUserPosition));
},
(error) => {
console.log(error);
}
);
So, I just digged a little into the code and basically all the LocationModule does is send the request directly to Android.
It just calls this method:
https://developer.android.com/reference/android/location/LocationManager.html#getLastKnownLocation(java.lang.String)
Now, if you read that, the location says FINE_LOCATION or COARSE_LOCATION.
Usually one just add the fine location permissions, but I am thinking that maybe to access the Wifi location you need to add the coarse permissions into the app. Do you have both?
https://developer.android.com/reference/android/Manifest.permission.html#ACCESS_COARSE_LOCATION
If not, I would add that permissions into the app and try again.
I was having the same issue and tried a lot of libraries to get the user location. navigator.geolocation API did not gave me location every time on android instead it just give mostly timeout error only. So then I tried react native background geolocation that start using the gps continuously then I find react native geolocation service and the author clearly mentioned that:
Since this library was meant to be a drop-in replacement for the RN's
Geolocation API, the usage is pretty straight forward, with some extra
error cases to handle.
thats what I needed always and I think you should also try this.
Have a look on this AndroidManifest file, the author is using all type of location.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.agontuk.RNFusedLocation">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
for the test example you'll simply follow the same instruction that RN Geolocation API suggesting. Here is the simple example using react native geolocation service:
import Geolocation from 'react-native-geolocation-service';
componentDidMount() {
// Instead of navigator.geolocation, just use Geolocation.
if (hasLocationPermission) {
Geolocation.getCurrentPosition(
(position) => {
console.log(position);
},
(error) => {
// See error code charts below.
console.log(error.code, error.message);
},
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 }
);
}
}
So in the third parameter of the getCurrentPosition use enableHighAccuracy false to use network to get user location and true to get more accurate location using gps. See this option documentation.
Author of this repo also provided the example project you can try it with enableHighAccuracy false and turn location off for the first time but when you run the app it will ask for the permission of the location it will show app want to access wifi or cell network provided location.
As you are using expo you cannot use react native geolocation service for that you need to follow Mojtaba answer for detachment and get the android and iOS project so that you can configure both projects. Let me know if you need more information.
In my case, I solved my issue by adding the following in AndroidManifest.xml.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
First of all give permissions in your app
For Ios: You need to include the NSLocationWhenInUseUsageDescription key in Info.plist
For android:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
From here we get lat and longitude
CODE ==>
navigator.geolocation.getCurrentPosition(
(position) => {
const initialPosition = JSON.stringify(position);
// console.log(initialPosition);
this.setState({ initialPosition });
},
//(error) => alert(error.message),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
);
this.watchID = navigator.geolocation.watchPosition((position) => {
const lastPosition = JSON.stringify(position);
//this.setState({ longitude: position.coords.longitude, latitude: position.coords.latitude });
//this._getWheaterData();
AsyncStorage.setItem('latitude',position.coords.latitude.toString())
AsyncStorage.setItem('longitude',position.coords.longitude.toString())
},
// (error) => alert(error.message),
// console.log(error),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 });

AsyncStorage is not returning the callback

I am using redux-persist in a react native project, that runs just fine in a broad number of devices except Android 7. I am trying to debug the problem on why my local storage is nor persisting and found this:
The following code executes inside React Native component lifecycle's
componentDidMount() {
attachObservables(store)
setInterval(async () => {
console.log('Inside setInterval')
const data = await AsyncStorage.getAllKeys()
console.log('inside the getAllKeys')
data.forEach(async k => {
const value = await AsyncStorage.getItem(k)
console.group(k)
console.log(value)
console.groupEnd()
})
}, 3000)
}
Code after 'Inside setInterval' is never called. It only runs once if outside the setInterval. If I call once the code outside the setInterval it appears to run just fine. I also tried callback format vs async / await version but it does not seem to matter.
Same problem I had using firebase js library (callbacks never return after the first one). I am now looking for alternatives to workaround the problem.
Any ideas?
As of React Native 0.51 in some Android versions, the runtime can get blocked by other native modules, impeding the resolution of the mentioned methods.
It can be fixed via https://github.com/facebook/react-native/issues/14101#issuecomment-345563563, ensuring this methods use a free thread from the thread pool.
A PR has been submitted and I hope that will be released in future versions. If you want it to use this fix right now, it is available here https://github.com/netbeast/react-native
EDIT:
I am not experiencing this anymore on real devices over react-native#0.53, anyhow others have also reported, so the issue is still open.