Naver Map for React Native - Bring Naver Map to Your React Fingertips
MIT License
[!NOTE] The code comments and Documentation are unfortunately all written in Korean. However, you can use a translator or infer the meaning of the props' names and default values to easily understand and use them, even without knowing Korean.
Always remember that you can refer to the Naver Map SDK's English Official Documentation to get a general idea of how to use it.
Support Table
React Native Naver Map | React Native | Note |
---|---|---|
≥2.1.0
|
≥ 0.74
|
Drop Bridge Support & 0.74 required |
≥2.x
|
New Architecture Only | Drop Old Architecture Support, You should turn off bridgeless if want to render http web image marker |
<2.x
|
Old Architecture + New Architecture |
[!IMPORTANT] The
1.x
version supports the Old Architecture (Bridge), but starting from the2.x
version, support for it will be discontinued. If your project has not transitioned to the New Architecture, please use the1.x
version.
We have structured the API Docs which describe almost all types.
We have maximized readability and you can check the usage of the desired component types, Prop
, and Ref
on the component
side.
Using the expo config plugin, you can easily build in the Expo environment regardless of the architecture.
While it cannot be used in Expo Go or Snack, it can easily be used in the development build and production environments.
[!IMPORTANT]
[iOS, Android] x [new arch, old arch] x [debug, release]
We have tested that it renders correctly under all 8 conditions.
symbol
)children
We support the latest version of the SDK, and you can manipulate the latest features of Naver Map using Props and Commands.
# npm
npm install --save @mj-studio/react-native-naver-map
# yarn
yarn add @mj-studio/react-native-naver-map
# expo
npx expo install @mj-studio/react-native-naver-map
For iOS, you should install pods
For more detailed settings, please refer to the Official Documentation.
Import Naver SDK Maven Repository to android/build.gradle
.
allprojects {
repositories {
maven {
url "https://repository.map.naver.com/archive/maven"
}
}
}
AndroidManifest.xml
<manifest>
<application>
<meta-data
android:name="com.naver.maps.map.CLIENT_ID"
android:value="YOUR_CLIENT_ID_HERE" />
</application>
</manifest>
AndroidManifest.xml
Currently, this package will request location permission for showing user's current location.
<manifest>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
# optional for background location
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</manifest>
Detailed information related to permissions is listed below.
For more detailed settings, please refer to the Official Documentation.
info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NMFClientId</key>
<string>YOUR_CLIENT_ID_HERE</string>
<dict>
<plist>
info.plist
Currently, this package will request location permission for showing user's current location.
<plist version="1.0">
<dict>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>{{usage description}}</string>
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>{{your purpose key}}</key>
<string>{{usage description}}</string>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>{{usage description}}</string>
</dict>
</plist>
Detailed information related to permissions is listed below.
expo-build-properties
packageThis is for inject naver maven repository.
npx expo install expo-build-properties
app.json
{
...
"plugins": [
[
"@mj-studio/react-native-naver-map",
{
"client_id": "{{Naver Map Client Key}}",
// (optional, you can set with expo-location instead of this package)
"android": {
"ACCESS_FINE_LOCATION": true,
"ACCESS_COARSE_LOCATION": true,
"ACCESS_BACKGROUND_LOCATION": true
},
// (optional, you can set with expo-location instead of this package)
"ios": {
"NSLocationAlwaysAndWhenInUseUsageDescription": "{{ your location usage description }}",
"NSLocationWhenInUseUsageDescription": "{{ your location usage description }}",
"NSLocationTemporaryUsageDescriptionDictionary": {
"purposeKey": "{{ your purpose key }}",
"usageDescription": "{{ your location usage description }}"
}
}
}
],
[
"expo-build-properties",
{
"android": {
"extraMavenRepos": ["https://repository.map.naver.com/archive/maven"]
}
}
],
...
]
}
Expo does not require the setup methods for Android and iOS described above.
Detailed information related to permissions is listed below.
const jejuRegion: Region = {
latitude: 33.20530773,
longitude: 126.14656715029,
latitudeDelta: 0.38,
longitudeDelta: 0.8,
};
...
<NaverMapView
ref={ref}
style={{ flex: 1 }}
mapType={mapType}
layerGroups={{
BUILDING: true,
BICYCLE: false,
CADASTRAL: false,
MOUNTAIN: false,
TRAFFIC: false,
TRANSIT: false,
}}
initialRegion={jejuRegion}
isIndoorEnabled={indoor}
symbolScale={symbolScale}
lightness={lightness}
isNightModeEnabled={nightMode}
isShowCompass={compass}
isShowIndoorLevelPicker={indoorLevelPicker}
isShowScaleBar={scaleBar}
isShowZoomControls={zoomControls}
isShowLocationButton={myLocation}
isExtentBoundedInKorea
logoAlign={'TopRight'}
locale={'ja'}
onInitialized={() => console.log('initialized!')}
onOptionChanged={() => console.log('Option Changed!')}
onCameraChanged={(args) => console.log(`Camera Changed: ${formatJson(args)}`)}
onTapMap={(args) => console.log(`Map Tapped: ${formatJson(args)}`)}
>
<NaverMapMarkerOverlay
latitude={33.3565607356}
longitude={126.48599018}
onTap={() => console.log(1)}
anchor={{ x: 0.5, y: 1 }}
caption={{
key: '1',
text: 'hello',
}}
subCaption={{
key: '1234',
text: '123',
}}
width={100}
height={100}
/>
{/* Not Working in iOS Old Architecture Yet */}
<NaverMapMarkerOverlay*
latitude={33.4165607356}
longitude={126.48599018}
onTap={() => console.log(1)}
anchor={{ x: 0.5, y: 1 }}
caption={{
key: '1',
text: 'hello',
}}
subCaption={{
key: '1234',
text: '123',
}}
width={100}
height={100}
>
<View style={{ width: 100, height: 100, backgroundColor: 'red' }} />
</NaverMapMarkerOverlay>
<NaverMapMarkerOverlay
latitude={33.2565607356}
longitude={127.8599018}
onTap={() => console.log(1)}
anchor={{ x: 0.5, y: 1 }}
caption={{
key: '1',
text: 'hello',
}}
subCaption={{
key: '1234',
text: '123',
}}
width={100}
height={100}
image={{ uri: 'https://picsum.photos/100/100' }}
/>
<NaverMapCircleOverlay
latitude={33.17827398}
longitude={126.349895729}
radius={50000}
color={'#f2f1'}
outlineColor={'#aaa'}
outlineWidth={2}
onTap={() => console.log('hi')}
/>
<NaverMapPolygonOverlay
outlineWidth={5}
outlineColor={'#f2f2'}
color={'#0068'}
coords={[
{ latitude: 33.2249594, longitude: 126.54180047 },
{ latitude: 33.25683311547, longitude: 126.18193 },
{ latitude: 33.3332807, longitude: 126.838389399 },
]}
/>
<NaverMapPathOverlay
coords={[
{ latitude: 33.5249594, longitude: 126.24180047 },
{ latitude: 33.25683311547, longitude: 126.18193 },
{ latitude: 33.3332807, longitude: 126.838389399 },
]}
width={8}
color={'red'}
progress={-0.6}
passedColor={'green'}
/>
</NaverMapView>
All codes have JSDoc comments inserted, so you can start developing without Documentation.
However, if you want to check exactly what types exist and what properties they mean, please refer to the Documentation.
Permissions should be managed directly within the app by default.
We will look at an example of using the react-native-permissions library to manage this.
[!TIP] If you are an Expo user, you can indicate that you will be using permissions by referring to expo-location. Therefore, most of the content below is not necessary, and after examining what permissions are needed and how to specify them, you should follow the usage at expo-location.
First, install and set up the package:
yarn add react-native-permissions
Please refer to the Usage directly for the platform-specific setup method for react-native-permission
and properly modify Podfile(iOS)
, AndroidManifest.xml(Android)
.
iOS is involved with three types of permissions:
NSLocationAlwaysAndWhenInUseUsageDescription(>= iOS 11)
NSLocationWhenInUseUsageDescription
NSLocationTemporaryUsageDescriptionDictionary(>= iOS 14)
[!TIP] If your app does not support devices below iOS 11, you do not need to list
NSLocationAlwaysUsageDescription
. If it does support, then you should set it as well.
Then, in the Podfile
, you allow the following three permissions:
setup_permissions([
'LocationAccuracy',
'LocationAlways',
'LocationWhenInUse',
...
])
Activate the Background Modes
tab in the app target in Xcode and select the Location updates
option.
This is necessary for receiving location in the background, so it does not need to be set if it is not required.
The FusedLocationSource
used internally by the Naver Map SDK automatically makes a permission request the moment the user sets the isShowLocationButton prop to true
.
Android can implement permissions relatively simply.
Just specify the following permissions in AndroidManifest.xml
:
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_BACKGROUND_LOCATION
If you have completed the configuration up to this point, you can request permissions in screens that require a map as follows:
For Bare RN Project or ejected Expo (react-native-permissions
)
// useEffect is simply used to be called when the component mounts..
useEffect(() => {
if (Platform.OS === 'ios') {
request(PERMISSIONS.IOS.LOCATION_ALWAYS).then((status) => {
console.log(`Location request status: ${status}`);
if (status === 'granted') {
requestLocationAccuracy({
purposeKey: 'common-purpose', // replace your purposeKey of Info.plist
})
.then((accuracy) => {
console.log(`Location accuracy is: ${accuracy}`);
})
.catch((e) => {
console.error(`Location accuracy request has been failed: ${e}`);
});
}
});
}
if (Platform.OS === 'android') {
requestMultiple([
PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
PERMISSIONS.ANDROID.ACCESS_BACKGROUND_LOCATION,
])
.then((status) => {
console.log(`Location request status: ${status}`);
})
.catch((e) => {
console.error(`Location request has been failed: ${e}`);
});
}
}, []);
For Expo (expo-location
)
import * as Location from 'expo-location'
...
useEffect(() => {
(async () => {
try {
const {granted} = await Location.requestForegroundPermissionsAsync();
/**
* Note: Foreground permissions should be granted before asking for the background permissions
* (your app can't obtain background permission without foreground permission).
*/
if(granted) {
await Location.requestBackgroundPermissionsAsync();
}
} catch(e) {
console.error(`Location request has been failed: ${e}`);
}
})();
}, []);
[!NOTE] Descriptions for most types and props are also written in the code comments, and this project supports TypeScript, so checking only in the code will suffice for use.
Component | iOS | Android | Description |
---|---|---|---|
NaverMapView | ✅ | ✅ | Map |
NaverMapMarkerOverlay | ✅ | ✅ | Marker Overlay |
Info Window | 📦 | 📦 | Callout Overlay, Tooltip |
NaverMapCircleOverlay | ✅ | ✅ | Circle Overlay |
NaverMapPolylineOverlay | ✅ | ✅ | Polyline Overlay |
NaverMapPolygonOverlay | ✅ | ✅ | Polygon |
NaverMapLocationOverlay | 📦 | 📦 | Custom Location Overlay |
NaverMapGroundOverlay | ✅ | ✅ | Ground Overlay |
NaverMapPathOverlay | ✅ | ✅ | Path Overlay |
NaverMapMultipartPathOverlay | 📦 | 📦 | Multipath Overlay |
NaverMapArrowPathOverlay | ✅ | ✅ | Arrow Path Overlay |
There are a total of 5 types of markers.
[!IMPORTANT]
[iOS, Android] x [new arch, old arch] x [debug, release]
Tested to render correctly under all 8 conditions.
[!TIP]
reuseIdentifier
is automatically cached even if not provided.Ideally, all markers should use the
width
,height
prop. Currently, for type 2, the size appears differently in debug/release builds withoutwidth
,height
. It appears correctly in release.
image={{symbol: 'green'}}
require
react native image file) (caching ✅)image={require('./marker.png')}
image={{assetName: 'asset_image'}}
image={{httpUri: 'https://example.com/image.png'}}
[!WARNING] Attributes like header are currently not supported.
On iOS(new arch), collapsable=false
must be set for Views to function.
[!TIP] To change the appearance of a marker, dependencies must be passed as the
key
of the topmost child.
<NaverMapMarkerOverlay width={width} height={height} ...>
<View key={`${text}/${width}/${height}`} collapsable={false} style={{width, height}}>
<Text>{text}</Text>
</View>
</NaverMapMarkerOverlay>
[!IMPORTANT] This type can significantly impact performance when created in large quantities. It is recommended to use images whenever possible or keep usage simple.
Currently, this type tracks the position of children by slightly customizing React Native’s Shadow Node on Android and inserting the actual Android View
.
On iOS, simply draw UIView
to canvas as UIImage
.
Both methods do not yet support image caching (possible in the future with attributes like reuseableIdentifier
), and each marker consumes a significant amount of resources.
NaverMapView
Prop | iOS | Android |
---|---|---|
isLogoInteractionEnabled | ❌ | ❌ |
gestureFrictions | 📦 | 📦 |
Event | iOS | Android |
---|---|---|
onTapSymbol | 📦 | 📦 |
onAuthFailed | ❌ | ❌ |
onLocationChange | 📦 | 📦 |
iOS | Android | |
---|---|---|
onLongTap | ❌ | 📦 |
NaverMapMarkerOverlay
Prop | iOS | Android |
---|---|---|
caption-fontFamily | ❓ | ❓ |
subcaption-fontFamily | ❓ | ❓ |
iOS | Android | |
---|---|---|
Bridge | ✅ | ✅ |
Fabric | ✅️ | ✅️ |
See the contributing guide to learn how to contribute to the repository and the development workflow.
MIT