리액트 네이티브에서 네이버 맵 사용 방법
react-native-nmap 을 통해 쉽게 네이버 맵을 React-Native 모바일 앱에 붙일 수 있다.
선행 조건 1: 네이버 클라우드 콘솔 API 키 발급
네이버 클라우드 콘솔에서 API 키를 발급받아야 한다.
클라이언트 API 키 입력하기
<meta-data
android:name="com.naver.maps.map.CLIENT_ID"
android:value="myClientKey" />
android/app/src/main/AndroidManifest.xml
파일에 위와 같이 키를 입력해주면 된다.
선행 조건 2: Gradle 의존성 추가
android/build.gradle
파일에 아래와 같은 의존성을 추가해주어야 한다.
allprojects {
repositories {
// 다른 maven 의존성들 ...
google()
jcenter()
// 네이버 지도 저장소
maven {
url 'https://naver.jfrog.io/artifactory/maven/'
}
}
}
실제 코드 예제
<View
style={{
width: Dimensions.get("window").width - 30,
height: 200,
marginTop: 10,
}}
>
<NaverMapView
style={{ width: "100%", height: "100%" }}
zoomControl={false}
center={{
zoom: 10,
tilt: 50,
latitude: (start.latitude + end.latitude) / 2,
longitude: (start.longitude + end.longitude) / 2,
}}
>
<Marker
coordinate={{
latitude: start.latitude,
longitude: start.longitude,
}}
pinColor="blue"
/>
<Path
coordinates={[
{
latitude: start.latitude,
longitude: start.longitude,
},
{ latitude: end.latitude, longitude: end.longitude },
]}
/>
<Marker
coordinate={{
latitude: end.latitude,
longitude: end.longitude,
}}
/>
</NaverMapView>
</View>
마커 찍기
마커란 맵에 동그란 점 같은 것으로 특정 위치를 콕 집는 것이다. 위 소스코드 중 <Marker />
태그로 이용하는 것을 볼 수 있다.
<Marker
coordinate={{
latitude: end.latitude,
longitude: end.longitude,
}}
/>
내 위치 가져오기
useEffect(() => {
// watchPosition() 도 가능
Geolocation.getCurrentPosition(
(info) => {
setMyPosition({
latitude: info.coords.latitude,
longitude: info.coords.longitude,
});
},
console.error,
{
enableHighAccuracy: true,
timeout: 20000,
// distanceFilter: 50
}
);
}, []);
Geolocation.getCurrentPosition()
메서드는 위치 권한을 받았을 때 이용 가능하다. 받아온 위치를 상태에 담아서 이용하면 된다.
만일 위치가 계속 변한다면, Geolocation.watchPosition()
메서드를 이용하면 된다. 단, watchPosition()
메서드를 지속적으로 실행하면, 배터리 소모가 크다.
distanceFilter: 50
과 같은 옵션으로 내가 몇 미터를 움직였을 때 위치를 재확인할지 등을 설정 가능하다.
추가 : 위도, 경도 차이를 km 단위로 변환하기
function getDistanceFromLatLonInKm(
lat1: number,
lon1: number,
lat2: number,
lon2: number
) {
const R = 6371; // Radius of the earth in km
const dLat = deg2rad(lat2 - lat1); // deg2rad below
const dLon = deg2rad(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(lat1)) *
Math.cos(deg2rad(lat2)) *
Math.sin(dLon / 2) *
Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const d = R * c; // Distance in km
return d;
}
function deg2rad(deg: number) {
return deg * (Math.PI / 180);
}
export default getDistanceFromLatLonInKm;
유용하게 사용될 수 있는 유틸 함수이다.
레퍼런스
[제로초 배달 앱 리액트 네이티브 강의](## 리액트 네이티브 권한
리액트 네이티브에서 권한을 받는 코드는 보통 react-native-permissions 라는 의존성을 통해 구현한다.
그 이유는 안드로이드와 IOS 의 권한 체계가 다른데 그것을 각자 코딩하려면 너무 공수가 많이 들기 때문이다.
그럼에도 네이티브에서 수정해야되는 내용들이 꽤 있다.
IOS 네이티브 권한 설정
어떤 권한을 쓸지 명시해주기
ios/Podfile
내부에 아래와 같은 내용을 추가해주면 된다.
target 'FoodDeliveryApp' do
config = use_native_modules!
# Flags change depending on the env values.
flags = get_default_flags()
permissions_path = '../node_modules/react-native-permissions/ios'
pod 'Permission-AppTrackingTransparency', :path => "#{permissions_path}/AppTrackingTransparency"
pod 'Permission-BluetoothPeripheral', :path => "#{permissions_path}/BluetoothPeripheral"
pod 'Permission-Calendars', :path => "#{permissions_path}/Calendars"
pod 'Permission-Camera', :path => "#{permissions_path}/Camera"
pod 'Permission-Contacts', :path => "#{permissions_path}/Contacts"
pod 'Permission-FaceID', :path => "#{permissions_path}/FaceID"
pod 'Permission-LocationAccuracy', :path => "#{permissions_path}/LocationAccuracy"
pod 'Permission-LocationAlways', :path => "#{permissions_path}/LocationAlways"
pod 'Permission-LocationWhenInUse', :path => "#{permissions_path}/LocationWhenInUse"
pod 'Permission-MediaLibrary', :path => "#{permissions_path}/MediaLibrary"
pod 'Permission-Microphone', :path => "#{permissions_path}/Microphone"
pod 'Permission-Motion', :path => "#{permissions_path}/Motion"
pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications"
pod 'Permission-PhotoLibrary', :path => "#{permissions_path}/PhotoLibrary"
pod 'Permission-PhotoLibraryAddOnly', :path => "#{permissions_path}/PhotoLibraryAddOnly"
pod 'Permission-Reminders', :path => "#{permissions_path}/Reminders"
pod 'Permission-Siri', :path => "#{permissions_path}/Siri"
pod 'Permission-SpeechRecognition', :path => "#{permissions_path}/SpeechRecognition"
pod 'Permission-StoreKit', :path => "#{permissions_path}/StoreKit"
권한을 얻을 때 메세지 설정하기
<key>NSCameraUsageDescription</key>
<string>배송완료 사진 촬영을 위해 카메라 권한이 필요합니다.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>배송중 위치 확인을 위해서 위치 권한이 필요합니다.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>배송중 위치 확인을 위해서 위치 권한이 필요합니다.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>배송중 위치 확인을 위해서 위치 권한이 필요합니다.</string>
<key>NSMotionUsageDescription</key>
<string>배송중 위치 확인을 위해서 위치 권한이 필요합니다.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>배송완료 사진 선택을 위해 라이브러리 접근 권한이 필요합니다.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>배송완료 사진 선택을 위해 라이브러리 접근 권한이 필요합니다.</string>
<key>CFBundleDevelopmentRegion</key>
안드로이드 네이티브 권한 설정
어떤 권한을 줄지 명시해주기
android/app/src/main/AndroidManifest.xml
에 작성해주면 된다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.n00nietzsche.fooddeliveryapp">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.VIBRATE"/>
</manifest>
권한 받기 관련 Hooks 작성
import { useEffect } from "react";
import { Alert, Linking, Platform } from "react-native";
import { check, PERMISSIONS, request, RESULTS } from "react-native-permissions";
function usePermissions() {
// 권한 관련
// 파일명을 usePermissions.android.ts, usePermissions.ios.ts 와 같은 형식으로 디바이스별로 나누어도 되긴 한다.
useEffect(() => {
if (Platform.OS === "android") {
check(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION)
.then((result) => {
console.log("check location", result);
if (result === RESULTS.BLOCKED || result === RESULTS.DENIED) {
Alert.alert(
"이 앱은 위치 권한 허용이 필요합니다.",
"앱 설정 화면을 열어서 항상 허용으로 바꿔주세요.",
[
{
text: "네",
// 여기서는 설정을 이용하지만, url 의 스킴을 이용해서 다른 앱으로 이동하는 것도 가능하다.
// ex) tel://01000000000 혹은 sms://01000000000
onPress: () => Linking.openSettings(),
},
{
text: "아니오",
onPress: () => console.log("No Pressed"),
style: "cancel",
},
]
);
}
})
.catch(console.error);
} else if (Platform.OS === "ios") {
check(PERMISSIONS.IOS.LOCATION_ALWAYS)
.then((result) => {
if (result === RESULTS.BLOCKED || result === RESULTS.DENIED) {
Alert.alert(
"이 앱은 백그라운드 위치 권한 허용이 필요합니다.",
"앱 설정 화면을 열어서 항상 허용으로 바꿔주세요.",
[
{
text: "네",
onPress: () => Linking.openSettings(),
},
{
text: "아니오",
onPress: () => console.log("No Pressed"),
style: "cancel",
},
]
);
}
})
.catch(console.error);
}
if (Platform.OS === "android") {
check(PERMISSIONS.ANDROID.CAMERA)
.then((result) => {
// GRANTED 를 넣은 이유는 ELSE 문으로 가지 않게 하기 위해서 넣었음.
// TODO: 사실 깔끔하게 만들기 위해서는 분리할 필요가 있음 if (alreadyGranted) return 과 같이...
if (result === RESULTS.DENIED || result === RESULTS.GRANTED) {
return request(PERMISSIONS.ANDROID.CAMERA);
} else {
console.log(result);
throw new Error("카메라 지원 안 함");
}
})
.catch(console.error);
} else {
check(PERMISSIONS.IOS.CAMERA)
.then((result) => {
if (
result === RESULTS.DENIED ||
result === RESULTS.LIMITED ||
result === RESULTS.GRANTED
) {
return request(PERMISSIONS.IOS.CAMERA);
} else {
console.log(result);
throw new Error("카메라 지원 안 함");
}
})
.catch(console.error);
}
}, []);
}
export default usePermissions;
앱 메인에서 사이드이펙트로 작동하도록 두면 된다.
기존 코드 출처
'리액트 네이티브 (React Native)' 카테고리의 다른 글
리액트 네이티브 이미지 첨부하기 (카메라, 갤러리) (0) | 2022.10.21 |
---|---|
리액트 네이티브 클라이언트에게 권한 받기 (3) | 2022.10.19 |
React-Native 리덕스 리액트 실무 사용 패턴 (0) | 2022.10.19 |
리액트 네이티브(React Native) 에서 사용하는 스토리지 저장소 알아보기 (0) | 2022.10.12 |
react-native-config 란? + 안드로이드 세팅 방법 (0) | 2022.10.12 |