I want to make one function for getting user coordinates and I somehow find that I am not sure my approach is good enough.
I would like to know how others write this function to work 100% sure on ios and on android.
Now I have something like this:
function getUserLocation(callback: func) {
Permissions.check('location')
.then(response => {
if (response == 'authorized') {
navigator.geolocation.getCurrentPosition(
(location) => {
callback({
latitude: location.coords.latitude,
longitude: location.coords.longitude
}, response);
},
(error) => {
callback(null);
},
Platform.OS === 'android' ? null : {enableHighAccuracy: true, timeout: 100000, maximumAge: 1000}
);
} else {
callback(null, response);
}
})
}
So you can see that I want to use this function so caller can know if locations usage is permitted and if it is get current coordinates.
What I am trying is to learn how to:
1. Make function like this to be awaitable.
2. How others make function like this (for both OS) and to work 100% same.
There are two parts to your question
1. Make function like this to be awaitable.
This answerable directly by providing you logic of how to do it. Awaitable is nothing but what is actually an async function or something that returns a promise. If you want to the async
way then you need to first make a version of getCurrentPosition
which returns a promise. That can be done like below
function getCurrentLocation(options) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, ({code, message}) =>
reject(Object.assign(new Error(message), {name: "PositionError", code})),
options);
});
};
PS: Credits to https://stackoverflow.com/a/44439358/2830850 for above code
Now you can rewrite your code like below
async function getUserLocation() {
let response = await Permissions.check('location')
let options = Platform.OS === 'android' ? null : {enableHighAccuracy: true, timeout: 100000, maximumAge: 1000}
if (response == 'authorized') {
return await getCurrentLocation(options)
}
return null;
}
In case you wan't to go the promise
way it would be like below
function getUserLocation() {
return new Promise((resolve, reject) => {
Permissions.check('location')
.then(response => {
if (response == 'authorized') {
navigator.geolocation.getCurrentPosition(
(location) => {
resolve({
latitude: location.coords.latitude,
longitude: location.coords.longitude
});
},
(error) => {
reject(error);
},
Platform.OS === 'android' ? null : { enableHighAccuracy: true, timeout: 100000, maximumAge: 1000 }
);
} else {
resolve(null);
}
})
});
}
One key thing here is unlike callbacks, promise resolve a single value, which means you need to use objects to return multiple parameters.
2. How others make function like this (for both OS) and to work 100% same.
This is where you question becomes opinionated, I may do some different approach you may do something else and another person might do totally something else. But I will still discuss few possibilities.
Split into Multiple Function
function getUserLocation() {
if (Platform.OS === 'android')
{
return getUserLocationAndroid();
} else {
return getUserLocationIOS();
}
}
Maintain key value pairs
You can have code which automatically binds function based on the OS.
Utils = {
getFunction(name) {
if ((name + Platform.OS) in this)
return this[name + Platform.OS]
return this[name];
}
getLocation: function() {}
//getLocationandroid: function() {}
}
So by default you will have getLocation
to server both OS, but in case one of OS code deviates too much you will create a new function for the same. The code would look something like below
Utils.getFunction("getLocation")(...)
One function with branching
This is what your current approach is. I would stick with this as long there functions are easy to understand and there is clear intent what part of the code does platform specific stuff
Again there may 10 more different ways one can put here, but it would in the end depend one thing, what is easier for you to maintain, understand use. Some approaches are use case specific also, where you can mix multiple approaches based on the use case
Make async version of getCurrentPosition
, you can add this function to navigator.geolocation.
async function getCurrentPosition(options) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
position => resolve(position.coords),
error => reject(error),
options
});
});
}
Next function is what you want. Better to throw exception when not authorized, because anyway you need try / catch because of getCurrentPosition
.
const locationOptions = Platform.OS === 'android' ? null :
{ enableHighAccuracy: true, timeout: 100000, maximumAge: 1000 };
async function getUserLocation() {
let permission = await Permissions.check('location');
if (permission !== 'authorized') {
throw new Error('Not authorized: ' + permission);
}
return await getCurrentPosition(locationOptions);
}
How to use:
try {
let location = await getUserLocation(); // { latitude, longitude }
} catch (error) {
Alert.alert(error.message);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With