project link: https://exp.host/@chuanshuoge/expo-location
standalone apk: https://github.com/chuanshuoge6/expo-location/blob/master/expo-location-6a2380c18118466d88e1dbb510e776b9-signed.apk
stop record after recording for a while
press show record
press export
txt file is in download folder
open it up
//gps.js
import { Clipboard, ShadowPropTypesIOS } from 'react-native';
import {
Container, Header, Title, Content, Footer,
FooterTab, Button, Left, Right, Body, Icon, Text,
Accordion, Card, CardItem, Thumbnail, ListItem,
CheckBox, DatePicker, DeckSwiper, Fab, View,
Badge, Form, Item, Input, Label, Picker, Textarea,
Switch, Radio, Spinner, Tab, Tabs, TabHeading,
ScrollableTab, H1, H2, H3, Drawer,
} from 'native-base';
import * as Font from 'expo-font'
import * as Location from 'expo-location'
import * as TaskManager from 'expo-task-manager'
import useInterval from 'react-useinterval'
import openMap from 'react-native-open-maps'
import { connect } from 'react-redux';
import { addLocations, deleteLocations } from './Redux/locationActions'
import * as MediaLibrary from 'expo-media-library'
import * as FileSystem from 'expo-file-system'
const LOCATION_TASK_NAME = 'background-location-task';
let background_location = null
function GPS(props) {
const [loadfont, setloadfont] = useState(true)
const [permission_status, setpermission_status] = useState('undetermined')
const [acc, setacc] = useState(-1)
const [altitude, setaltitude] = useState(-1)
const [heading, setheading] = useState(-1)
const [latitude, setlatitude] = useState(-1)
const [longitude, setlonggitude] = useState(-1)
const [speed, setspeed] = useState(-1)
const [time, settime] = useState('')
const [updatePeriod, setupdatePeriod] = useState(null)
const [address, setaddress] = useState(null)
const [card_collapse1, setcard_collapse1] = useState(false)
const [card_collapse2, setcard_collapse2] = useState(false)
const [record, setrecord] = useState(false)
const [storagePermission, setstoragePermission] = useState('denied')
useEffect(() => {
initializeApp()
return () => stop_update_location()
}, [])
initializeApp = async () => {
const { status } = await Location.requestPermissionsAsync()
setpermission_status(status)
const grantStorage = await MediaLibrary.requestPermissionsAsync()
setstoragePermission(grantStorage.status)
await Font.loadAsync({
Roboto: require("native-base/Fonts/Roboto.ttf"),
Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf")
})
setloadfont(false)
}
useInterval(() => {
update_location()
if (record && time !== '') {
props.dispatch(addLocations({
latitude: latitude,
longitude: longitude,
time: time,
}))
}
}, updatePeriod);
update_location = async () => {
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
accuracy: Location.Accuracy.High,
})
if (background_location) {
const e = background_location.coords
setacc(e.accuracy)
setaltitude(e.altitude)
setheading(e.heading)
setlatitude(e.latitude)
setlonggitude(e.longitude)
setspeed(e.speed)
settime(Date(background_location.timestamp).toLocaleString())
}
}
stop_update_location = async () => {
setupdatePeriod(null)
const taskRegistered = await TaskManager.isTaskRegisteredAsync(LOCATION_TASK_NAME)
if (taskRegistered) {
await TaskManager.unregisterTaskAsync(LOCATION_TASK_NAME)
}
}
search_address = async () => {
if (background_location) {
const _address = await Location.reverseGeocodeAsync(background_location.coords)
setaddress(_address[0])
}
}
open_map = () => {
if (background_location) {
const e = background_location.coords
openMap({ latitude: e.latitude, longitude: e.longitude })
}
}
write_to_clipboard = (text) => {
Clipboard.setString(text);
}
display_record = () => {
let text = ''
props.locations_store.map(item => {
text = text + item.time + ',' + item.latitude.toString() + ',' + item.longitude.toString() + '\n'
})
alert(text)
}
export_locations = async () => {
let text = ''
props.locations_store.map(item => {
text = text + item.time + ',' + item.latitude.toString() + ',' + item.longitude.toString() + '\n'
})
const fileUri = FileSystem.cacheDirectory + "location.txt";
await FileSystem.writeAsStringAsync(fileUri, text, { encoding: FileSystem.EncodingType.UTF8 });
const asset = await MediaLibrary.createAssetAsync(fileUri)
await MediaLibrary.createAlbumAsync("Download", asset, false)
alert('file exported to download folder')
}
if (permission_status !== 'granted' || storagePermission !== 'granted') {
<Container style={{ backgroundColor: '#1C2833' }}>
<Text>App needs location and storage permission granted</Text>
</Container>
}
if (loadfont) {
return <Container style={{ backgroundColor: '#1C2833' }}><Spinner /></Container>
}
return (
<Container style={{ backgroundColor: '#1C2833' }}>
<Content style={{ marginTop: 25 }}>
<Card style={{ backgroundColor: '#1C2833' }}>
<CardItem header bordered button style={{ backgroundColor: "#1C2833" }}
onPress={() => setcard_collapse1(!card_collapse1)}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
<H3 style={{ color: '#D0D3D4' }}>Realtime GPS</H3>
<H3 style={{ color: "#D0D3D4" }}>+</H3>
</View>
</CardItem>
{card_collapse1 ? null :
<CardItem bordered style={{ backgroundColor: '#1C2833' }}>
<Text style={{ color: "#D0D3D4", fontStyle: 'italic' }}>
Accuracy: {acc} Meters{'\n'}
Altitude: {altitude} Meters{'\n'}
Heading: {heading} Degree{'\n'}
Latitude: {latitude} Degree{'\n'}
Longitude: {longitude} Degree{'\n'}
Speed: {speed} M/S{'\n'}
Time: {time}
</Text>
<Button light small bordered icon style={{ position: 'absolute', right: 10, top: 10 }}
onPress={() => { write_to_clipboard(latitude + ',' + longitude) }}>
<Icon name='copy'></Icon>
</Button>
</CardItem>
}
<CardItem header bordered button style={{ backgroundColor: '#1C2833' }}
onPress={() => setcard_collapse2(!card_collapse2)}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
<H3 style={{ color: '#D0D3D4' }}>Address (update location first)</H3>
<H3 style={{ color: '#D0D3D4' }}>+</H3>
</View>
</CardItem>
{card_collapse2 ? null :
<CardItem style={{ backgroundColor: '#1C2833' }}>
{address ?
<Text style={{ color: '#D0D3D4' }}>
{address.name} {address.street} {'\n'}
{address.city} {address.region} {address.country} {address.postalCode}
</Text>
: <Text style={{ color: '#D0D3D4' }}>Waiting for GPS location</Text>}
<Button light small bordered icon style={{ position: 'absolute', right: 10, top: 10 }}
onPress={() => {
write_to_clipboard(address.name + ' ' + address.street + ' ' +
address.city + ' ' + address.region + ' ' + address.country + ' ' + address.postalCode)
}}>
<Icon name='copy'></Icon>
</Button>
</CardItem>
}
</Card>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => setupdatePeriod(1000)}>
<Text>Update Location</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => stop_update_location()}>
<Text>Stop Update</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => search_address()}>
<Text>Search Address</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => open_map()}>
<Text>Open Map</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }} onPress={() => {
props.dispatch(deleteLocations()); setupdatePeriod(1000); setrecord(true)
}}>
<Text>New Record</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => { setupdatePeriod(1000); setrecord(true) }}>
<Text>Continue Record</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => { stop_update_location(); setrecord(false) }}>
<Text>Stop Record</Text>
</Button>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => display_record()}>
<Text>Show Record</Text>
</Button>
</View>
<View style={{ flexDirection: 'row', justifyContent: "space-around", marginTop: 10 }}>
<Button small style={{ width: 150, justifyContent: "center" }}
onPress={() => { export_locations() }}>
<Text>Export Locations</Text>
</Button>
</View>
</Content>
</Container>
);
}
TaskManager.defineTask(LOCATION_TASK_NAME, ({ data, error }) => {
if (error) {
// Error occurred - check `error.message` for more details.
console.log(error.message)
return;
}
if (data) {
const { locations } = data;
// do something with the locations captured in the background
background_location = locations[locations.length - 1]
}
});
export default connect(
(store) => {
return {
locations_store: store.locationReducer.locations,
};
}
)(GPS);
reference:
http://chuanshuoge2.blogspot.com/2020/03/expo-gps2-redux-persist.html
No comments:
Post a Comment