ryuyoonju
07-29
1차커밋
@e432b931ed30e9a301c7c022f7bf66cf940bf2f6
--- android/app/src/main/assets/index.android.bundle
+++ android/app/src/main/assets/index.android.bundle
This diff is too big to display. |
--- src/api/ApiUtils.js
+++ src/api/ApiUtils.js
... | ... | @@ -52,6 +52,7 @@ |
52 | 52 |
}, |
53 | 53 |
|
54 | 54 |
sendTripLog: async (data, navigation) => { |
55 |
+ console.log(data); |
|
55 | 56 |
try { |
56 | 57 |
// AsyncStorage에서 토큰 가져오기 |
57 | 58 |
const tokenString = await AsyncStorage.getItem('token'); |
... | ... | @@ -71,7 +72,7 @@ |
71 | 72 |
const response = await apiInstance.post('/action/gps_update', data, { |
72 | 73 |
headers: { |
73 | 74 |
'Content-Type': 'application/json', |
74 |
- Authorization: `Bearer ${accessToken}`, // Bearer 스키마를 사용하도록 수정 |
|
75 |
+ Authorization: `${accessToken}`, // Bearer 스키마를 사용하도록 수정 |
|
75 | 76 |
}, |
76 | 77 |
}); |
77 | 78 |
return response.data; |
--- src/screen/GpsScreen.js
+++ src/screen/GpsScreen.js
... | ... | @@ -1,18 +1,24 @@ |
1 | 1 |
import React, { useState, useEffect } from 'react'; |
2 |
-import { View, Text, StyleSheet, Alert, TouchableOpacity } from 'react-native'; |
|
2 |
+import { View, Text, StyleSheet, Alert, TouchableOpacity, PermissionsAndroid } from 'react-native'; |
|
3 | 3 |
import AsyncStorage from '@react-native-async-storage/async-storage'; |
4 | 4 |
import crypto from 'crypto-js'; |
5 |
-import { startBackgroundTask, stopBackgroundTask, locations } from '../services/LocationService'; |
|
6 | 5 |
import Api from '../api/ApiUtils'; |
7 | 6 |
import { useNavigation } from '@react-navigation/native'; |
8 |
-import Icon from 'react-native-vector-icons/FontAwesome'; // FontAwesome 아이콘 사용 |
|
7 |
+import Icon from 'react-native-vector-icons/FontAwesome'; |
|
8 |
+import Geolocation from 'react-native-geolocation-service'; |
|
9 | 9 |
|
10 | 10 |
const GpsScreen = () => { |
11 | 11 |
const [isMeasuring, setIsMeasuring] = useState(false); |
12 |
- const [elapsedTime, setElapsedTime] = useState(0); // 초 단위의 경과 시간 |
|
13 |
- const [tripId, setTripId] = useState(''); // trip_id 상태 추가 |
|
14 |
- const [userId, setUserId] = useState(''); // user_id 상태 추가 |
|
15 |
- const navigation = useNavigation(); // useNavigation 훅으로 navigation 객체 가져오기 |
|
12 |
+ const [elapsedTime, setElapsedTime] = useState(0); |
|
13 |
+ const [tripId, setTripId] = useState(''); |
|
14 |
+ const [userId, setUserId] = useState(''); |
|
15 |
+ const [locationData, setLocationData] = useState({ |
|
16 |
+ latitude: [], |
|
17 |
+ longitude: [], |
|
18 |
+ timestamp: [] |
|
19 |
+ }); // 위치 데이터 상태 수정 |
|
20 |
+ const [watchId, setWatchId] = useState(null); |
|
21 |
+ const navigation = useNavigation(); |
|
16 | 22 |
|
17 | 23 |
useEffect(() => { |
18 | 24 |
let timer; |
... | ... | @@ -20,7 +26,7 @@ |
20 | 26 |
if (isMeasuring) { |
21 | 27 |
timer = setInterval(() => { |
22 | 28 |
setElapsedTime(prevElapsedTime => prevElapsedTime + 1); |
23 |
- }, 1000); // 1초마다 실행 |
|
29 |
+ }, 1000); |
|
24 | 30 |
} else { |
25 | 31 |
clearInterval(timer); |
26 | 32 |
} |
... | ... | @@ -31,7 +37,6 @@ |
31 | 37 |
}, [isMeasuring]); |
32 | 38 |
|
33 | 39 |
useEffect(() => { |
34 |
- // 앱이 처음 실행될 때 user_id를 AsyncStorage에서 가져옴 |
|
35 | 40 |
const fetchUserId = async () => { |
36 | 41 |
try { |
37 | 42 |
const storedUserId = await AsyncStorage.getItem('user_id'); |
... | ... | @@ -47,52 +52,70 @@ |
47 | 52 |
}, []); |
48 | 53 |
|
49 | 54 |
const generateTripId = () => { |
50 |
- // 해시 값을 생성 |
|
51 | 55 |
const rand = Math.random().toString(); |
52 | 56 |
const date = new Date(); |
53 | 57 |
const sha256Hash = crypto.SHA256(rand + ',' + date.toString()).toString(crypto.enc.Hex); |
54 | 58 |
return sha256Hash; |
55 | 59 |
}; |
56 | 60 |
|
61 |
+ const requestLocationPermission = async () => { |
|
62 |
+ try { |
|
63 |
+ const granted = await PermissionsAndroid.request( |
|
64 |
+ PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION |
|
65 |
+ ); |
|
66 |
+ return granted === PermissionsAndroid.RESULTS.GRANTED; |
|
67 |
+ } catch (err) { |
|
68 |
+ console.warn(err); |
|
69 |
+ return false; |
|
70 |
+ } |
|
71 |
+ }; |
|
72 |
+ |
|
57 | 73 |
const handleStart = async () => { |
74 |
+ const permissionGranted = await requestLocationPermission(); |
|
75 |
+ if (!permissionGranted) { |
|
76 |
+ Alert.alert('위치 권한 오류', '위치 권한을 허용해야 합니다.'); |
|
77 |
+ return; |
|
78 |
+ } |
|
79 |
+ |
|
58 | 80 |
try { |
59 | 81 |
const newTripId = generateTripId(); |
60 |
- setTripId(newTripId); // trip_id 상태 업데이트 |
|
61 |
- await startBackgroundTask(); |
|
82 |
+ setTripId(newTripId); |
|
62 | 83 |
setIsMeasuring(true); |
84 |
+ startLocationTracking(); |
|
63 | 85 |
} catch (error) { |
64 |
- console.error('Error starting background task:', error); |
|
65 |
- Alert.alert('백그라운드 작업 오류', '백그라운드 작업을 시작할 수 없습니다.'); |
|
86 |
+ console.error('Error starting location tracking:', error); |
|
87 |
+ Alert.alert('오류', '위치 추적을 시작할 수 없습니다.'); |
|
66 | 88 |
setIsMeasuring(false); |
67 | 89 |
} |
68 | 90 |
}; |
69 | 91 |
|
70 | 92 |
const handleStop = async () => { |
71 | 93 |
setIsMeasuring(false); |
72 |
- setElapsedTime(0); // 시간 초기화 |
|
73 |
- console.log('Measuring stopped.'); |
|
94 |
+ setElapsedTime(0); |
|
95 |
+ |
|
96 |
+ if (watchId !== null) { |
|
97 |
+ Geolocation.clearWatch(watchId); |
|
98 |
+ setWatchId(null); |
|
99 |
+ } |
|
74 | 100 |
|
75 | 101 |
try { |
76 |
- await stopBackgroundTask(); |
|
77 |
- |
|
78 | 102 |
const dataToSend = { |
79 |
- user_id: userId, // AsyncStorage에서 가져온 user_id 사용 |
|
80 |
- trip_id: tripId, // 상태에서 trip_id 가져오기 |
|
81 |
- trip_log: locations, |
|
103 |
+ user_id: userId, |
|
104 |
+ trip_id: tripId, |
|
105 |
+ trip_log: locationData, |
|
82 | 106 |
}; |
83 | 107 |
|
84 | 108 |
console.log('Data to send:', dataToSend); |
85 | 109 |
|
86 |
- // 서버로 전송 |
|
87 | 110 |
try { |
88 | 111 |
const response = await Api.sendTripLog(dataToSend, navigation); |
89 |
- console.log(":::::", response); |
|
112 |
+ console.log("Response:", response); |
|
90 | 113 |
} catch (error) { |
91 | 114 |
Alert.alert('로그인 실패', error.message); |
92 | 115 |
} |
93 | 116 |
|
94 | 117 |
} catch (error) { |
95 |
- console.error('Error stopping background task:', error); |
|
118 |
+ console.error('Error stopping location tracking:', error); |
|
96 | 119 |
} |
97 | 120 |
}; |
98 | 121 |
|
... | ... | @@ -107,12 +130,48 @@ |
107 | 130 |
Alert.alert('히스토리', '히스토리 화면으로 이동합니다.'); |
108 | 131 |
}; |
109 | 132 |
|
110 |
- // 시간 형식으로 변환 |
|
133 |
+ const startLocationTracking = () => { |
|
134 |
+ const id = Geolocation.watchPosition( |
|
135 |
+ (position) => { |
|
136 |
+ const { latitude, longitude } = position.coords; |
|
137 |
+ const time = new Date().toISOString(); |
|
138 |
+ const timestamp = formatDate(time); |
|
139 |
+ setLocationData(prevData => ({ |
|
140 |
+ latitude: [...prevData.latitude, latitude], |
|
141 |
+ longitude: [...prevData.longitude, longitude], |
|
142 |
+ timestamp: [...prevData.timestamp, time] |
|
143 |
+ })); |
|
144 |
+ |
|
145 |
+ console.log('위치 업데이트:', { latitude, longitude, timestamp: time }); |
|
146 |
+ }, |
|
147 |
+ (error) => { |
|
148 |
+ console.error('위치 감시 중 오류:', error); |
|
149 |
+ }, |
|
150 |
+ { enableHighAccuracy: true, distanceFilter: 0, interval: 2000 } |
|
151 |
+ ); |
|
152 |
+ |
|
153 |
+ setWatchId(id); |
|
154 |
+ }; |
|
155 |
+ |
|
111 | 156 |
const formatTime = (seconds) => { |
112 | 157 |
const hours = Math.floor(seconds / 3600); |
113 | 158 |
const minutes = Math.floor((seconds % 3600) / 60); |
114 | 159 |
const secs = seconds % 60; |
115 | 160 |
return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`; |
161 |
+ }; |
|
162 |
+ |
|
163 |
+ // 한국 시간으로 변환하는 함수 |
|
164 |
+ const formatDate = (time) => { |
|
165 |
+ const date = new Date(time); |
|
166 |
+ const year = date.getFullYear(); |
|
167 |
+ const month = `0${date.getMonth() + 1}`.slice(-2); |
|
168 |
+ const day = `0${date.getDate()}`.slice(-2); |
|
169 |
+ const hours = `0${date.getHours()}`.slice(-2); |
|
170 |
+ const minutes = `0${date.getMinutes()}`.slice(-2); |
|
171 |
+ const seconds = `0${date.getSeconds()}`.slice(-2); |
|
172 |
+ const milliseconds = `00${date.getMilliseconds()}`.slice(-3); |
|
173 |
+ |
|
174 |
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`; |
|
116 | 175 |
}; |
117 | 176 |
|
118 | 177 |
return ( |
... | ... | @@ -126,7 +185,7 @@ |
126 | 185 |
onPress={handleStart} |
127 | 186 |
disabled={isMeasuring} |
128 | 187 |
> |
129 |
- <Icon name="play" size={20} color="#FFFFFF" /> |
|
188 |
+ <Icon name="play" size={20} color="#FFFFFF" /> |
|
130 | 189 |
<Text style={styles.buttonText}>측정 시작</Text> |
131 | 190 |
</TouchableOpacity> |
132 | 191 |
<TouchableOpacity |
... | ... | @@ -224,7 +283,7 @@ |
224 | 283 |
|
225 | 284 |
}, |
226 | 285 |
fullWidthButtonText: { |
227 |
- color:'#007AFF', |
|
286 |
+ color: '#007AFF', |
|
228 | 287 |
fontWeight: 'bold', |
229 | 288 |
fontSize: 16, |
230 | 289 |
}, |
--- src/services/LocationService.js
+++ src/services/LocationService.js
... | ... | @@ -16,9 +16,9 @@ |
16 | 16 |
ios: 'best', |
17 | 17 |
android: 'mediumAccuracy', |
18 | 18 |
}[Platform.OS], |
19 |
- distanceFilter: 0, // meters |
|
19 |
+ distanceFilter: 1, // meters |
|
20 | 20 |
interval: 1000, // 1 seconds |
21 |
- fastestInterval: 1000, // 5 seconds |
|
21 |
+ fastestInterval: 5000, // 5 seconds |
|
22 | 22 |
forceRequestLocation: true |
23 | 23 |
|
24 | 24 |
}; |
... | ... | @@ -58,8 +58,7 @@ |
58 | 58 |
const timestamp = formatDate(time); |
59 | 59 |
locations.latitude.push(latitude); |
60 | 60 |
locations.longitude.push(longitude); |
61 |
- // locations.latitude.push(String(latitude)); |
|
62 |
- // locations.longitude.push(String(longitude)); |
|
61 |
+ |
|
63 | 62 |
locations.timestamp.push(timestamp); |
64 | 63 |
console.log('Location updated:', { latitude, longitude, timestamp }); |
65 | 64 |
}, |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?