Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
6423b12
iOS - customStyle 대응
fogbar Apr 25, 2025
a4f42d9
Android - customStyle 대응
fogbar Apr 25, 2025
177ae6b
[Chore] new readme test.
note11g May 10, 2025
84c03ea
[Chore] new readme draft
note11g May 10, 2025
56b08c0
[Chore] readme update (add migration notice)
note11g May 10, 2025
f35578e
[Update, iOS] change InfoWindow ui match with android and fix #229
note11g May 11, 2025
ec2a5be
[Update] add support dynamic widget image(automatically detecting wid…
note11g May 11, 2025
36175c2
[Add] add `onMapLoaded` on `NaverMap` widget. and `_NaverMapControlHa…
note11g May 18, 2025
57f1b09
[Impl, iOS] impl `onMapLoaded` on iOS Platform (`NaverMapControlSende…
note11g May 18, 2025
a8512bc
[Impl, Android] impl `onMapLoaded` on Android Platform (`NaverMapCont…
note11g May 18, 2025
208a3ee
[Change] change `onMapLoaded` calling time when after `onMapReady` ca…
note11g May 18, 2025
f77cb6c
[Chore] add example to use `onMapLoaded`
note11g May 18, 2025
635622d
Add `NaverMap.onMapLoaded` (#315)
note11g May 18, 2025
337080b
[Add] add `onMapLongTapped` on `NaverMap` widget. and `_NaverMapContr…
note11g May 29, 2025
305f834
[Impl, iOS] impl `onMapLongTapped` on iOS Platform (`NaverMapControlS…
note11g May 29, 2025
b58b203
[Impl, Android] impl `onMapLongTapped` on Android Platform (`NaverMap…
note11g May 29, 2025
da34d37
[Chore] add example onMapLongTapped with snackbar
note11g May 29, 2025
a55b580
[Chore] add example display on tap listeners(`onMapTapped`, `onSymbol…
note11g May 29, 2025
0406ffe
[Add] add NPolygonOverlay.outlinePattern feature.
note11g May 29, 2025
c0e3ec8
[Impl, Android] impl `NPolygonOverlay.outlinePattern` feature on Andr…
note11g May 29, 2025
a660493
[Impl, iOS] impl `NPolygonOverlay.outlinePattern` feature on iOS Plat…
note11g May 29, 2025
7e46f81
[Fix, iOS] fix to use px on `NPolygonOverlay.outlinePattern` (diff wi…
note11g May 29, 2025
4c96f96
[Change, iOS] change getting display scale method to DisplayUtil with…
note11g May 29, 2025
51e7117
[Change, iOS] remove unnecessary cast with round
note11g May 29, 2025
a19f240
[Change, iOS] change `CalcUtil` to struct
note11g May 29, 2025
c859b3f
[Change, Android] remove unnecessary cast
note11g May 29, 2025
14e2e45
[Chore] example add snackbar theme
note11g May 29, 2025
efb0ea8
Merge pull request #1 from fogbar/feature-custom-style
fogbar Jun 8, 2025
5580467
iOS - customStyle 대응
fogbar Apr 25, 2025
c81a789
Android - customStyle 대응
fogbar Apr 25, 2025
7197811
Merge branch 'feature-custom-style' of https://github.com/fogbar/flut…
fogbar Jun 8, 2025
98b8ce6
onCustomStyleLoaded, onCustomStyleLoadFailed 이벤트 리스너 추가 중
fogbar Jun 15, 2025
2693319
Android 정상적으로 Load 시 onCustomStyleLoaded 출력되는 것 확인
fogbar Jun 15, 2025
c5137f8
Merge branch 'feature-custom-style' into main
fogbar Jun 15, 2025
2e1a5c9
Merge pull request #2 from fogbar/main
fogbar Jun 15, 2025
ffdf021
Revert "onCustomStyleLoaded, onCustomStyleLoadFailed 이벤트 리스너 추가"
fogbar Jun 15, 2025
17bb472
Merge pull request #3 from fogbar/revert-2-main
fogbar Jun 15, 2025
d0e0bda
Revert "Revert "onCustomStyleLoaded, onCustomStyleLoadFailed 이벤트 리스너 …
fogbar Jun 15, 2025
706f1cf
Merge pull request #4 from fogbar/revert-3-revert-2-main
fogbar Jun 15, 2025
fec516d
Revert "Merge branch 'feature-custom-style' into main"
fogbar Jun 15, 2025
eaa8e2f
Merge pull request #5 from fogbar/main
fogbar Jun 15, 2025
a591c7b
[Add] add common code and message type `_NRawNativeException`, add s…
note11g Jun 20, 2025
e0999da
[Update] using `NAuthFailedException._fromMessageable` when parse arg…
note11g Jun 20, 2025
c4a1ee9
[Change] change type of `_NaverMapControlHandler.onCustomStyleLoadFa…
note11g Jun 20, 2025
51db556
[Add, iOS] add common native exception type `NFlutterException`
note11g Jun 20, 2025
9b89821
[Add, Android] add common native exception type `NFlutterException`
note11g Jun 20, 2025
d8b88b3
[Update, iOS] using common native exception type `NFlutterException` …
note11g Jun 20, 2025
8a0a0df
[Update, Android] using common native exception type `NFlutterExcepti…
note11g Jun 20, 2025
f0c1dec
[Update, iOS] using common native exception type `NFlutterException` …
note11g Jun 20, 2025
0c56a8a
[Update, Android] using common native exception type `NFlutterExcepti…
note11g Jun 20, 2025
69d2ed4
kotlin/DefaultTypeConverter asString 관련 삭제
fogbar Jun 22, 2025
6f40c99
[Update, Android] Support nullable options in map configuration
note11g Jul 13, 2025
4fea3d8
[Update] Support sending nullable value on `NPayload.make` constructor.
note11g Jul 13, 2025
ad8fcf0
[Update] Support sending to native(with NPayload) nullable value on `…
note11g Jul 13, 2025
f285005
[Update, iOS] Support nullable options in map configuration
note11g Jul 13, 2025
12465ac
Merge remote-tracking branch 'fogbar/feature-custom-style' into featu…
note11g Jul 13, 2025
7ca084e
[Chore, Android] add `NaverMapControlSender.dispose` and migrate `Nav…
note11g Jul 13, 2025
b2a4d7b
[Fix, Android] Preserve customStyleCallback when updating customStyle…
note11g Jul 13, 2025
c1ddc1f
[Fix, iOS] Preserve customStyleCallback when updating customStyleId d…
note11g Jul 13, 2025
5d18d31
[Chore, iOS] add `NaverMapControlSender.dispose` and migrate `NaverMa…
note11g Jul 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@ import dev.note11.flutter_naver_map.flutter_naver_map.applier.option.NaverMapOpt
import dev.note11.flutter_naver_map.flutter_naver_map.view.NaverMapView

internal object ApplyUtil {
internal fun <A : NaverMapOptionApplier> A.applyOptions(args: Map<String, Any>): A {
internal fun <A : NaverMapOptionApplier> A.applyOptions(args: Map<String, Any?>): A {
for ((funcName, arg) in args) {
try {
val func = optionApplyFuncMap[funcName]?.invoke(this)
func?.invoke(arg)
} catch (e: NullPointerException) {
val func = optionApplyFuncMap[funcName]?.invoke(this)
if (func != null) {
try {
func.invoke(arg)
} catch (e: NullPointerException) {
throw IllegalArgumentException(
"Invalid argument for \"$funcName\". " +
"Please check the type of the argument: $arg. this option really can be null?"
)
} catch (e: Exception) {
throw RuntimeException(
"Failed to apply option \"$funcName\" with argument: $arg",
e
)
}
} else {
throw NoSuchMethodException(
"No such method \"$funcName\". " +
"Please check the handling of this method."
Expand All @@ -19,40 +31,50 @@ internal object ApplyUtil {
return this
}

private val optionApplyFuncMap: Map<String, ((NaverMapOptionApplier) -> ((Any) -> Unit))> =
private val optionApplyFuncMap: Map<String, ((NaverMapOptionApplier) -> ((Any?) -> Unit))> =
mapOf(
"initialCameraPosition" to { it::setInitialCameraPosition },
"initialCameraPosition" to nonNullFunc { it::setInitialCameraPosition },
"extent" to { it::setExtent },
"mapType" to { it::setMapType },
"liteModeEnable" to { it::setLiteModeEnable },
"nightModeEnable" to { it::setNightModeEnable },
"indoorEnable" to { it::setIndoorEnable },
"activeLayerGroups" to { it::setActiveLayerGroups },
"buildingHeight" to { it::setBuildingHeight },
"lightness" to { it::setLightness },
"symbolScale" to { it::setSymbolScale },
"symbolPerspectiveRatio" to { it::setSymbolPerspectiveRatio },
"indoorFocusRadius" to { it::setIndoorFocusRadius },
"pickTolerance" to { it::setPickTolerance },
"rotationGesturesEnable" to { it::setRotationGesturesEnable },
"scrollGesturesEnable" to { it::setScrollGesturesEnable },
"tiltGesturesEnable" to { it::setTiltGesturesEnable },
"zoomGesturesEnable" to { it::setZoomGesturesEnable },
"stopGesturesEnable" to { it::setStopGesturesEnable },
"scrollGesturesFriction" to { it::setScrollGesturesFriction },
"zoomGesturesFriction" to { it::setZoomGesturesFriction },
"rotationGesturesFriction" to { it::setRotationGesturesFriction },
"mapType" to nonNullFunc { it::setMapType },
"liteModeEnable" to nonNullFunc { it::setLiteModeEnable },
"nightModeEnable" to nonNullFunc { it::setNightModeEnable },
"indoorEnable" to nonNullFunc { it::setIndoorEnable },
"activeLayerGroups" to nonNullFunc { it::setActiveLayerGroups },
"buildingHeight" to nonNullFunc { it::setBuildingHeight },
"lightness" to nonNullFunc { it::setLightness },
"symbolScale" to nonNullFunc { it::setSymbolScale },
"symbolPerspectiveRatio" to nonNullFunc { it::setSymbolPerspectiveRatio },
"indoorFocusRadius" to nonNullFunc { it::setIndoorFocusRadius },
"pickTolerance" to nonNullFunc { it::setPickTolerance },
"rotationGesturesEnable" to nonNullFunc { it::setRotationGesturesEnable },
"scrollGesturesEnable" to nonNullFunc { it::setScrollGesturesEnable },
"tiltGesturesEnable" to nonNullFunc { it::setTiltGesturesEnable },
"zoomGesturesEnable" to nonNullFunc { it::setZoomGesturesEnable },
"stopGesturesEnable" to nonNullFunc { it::setStopGesturesEnable },
"scrollGesturesFriction" to nonNullFunc { it::setScrollGesturesFriction },
"zoomGesturesFriction" to nonNullFunc { it::setZoomGesturesFriction },
"rotationGesturesFriction" to nonNullFunc { it::setRotationGesturesFriction },
"consumeSymbolTapEvents" to { { /** @see NaverMapView.setMapTapListener method */ } },
"scaleBarEnable" to { it::setScaleBarEnable },
"indoorLevelPickerEnable" to { it::setIndoorLevelPickerEnable },
"locationButtonEnable" to { it::setLocationButtonEnable },
"logoClickEnable" to { it::setLogoClickEnable },
"logoAlign" to { it::setLogoAlign },
"logoMargin" to { it::setLogoMargin },
"contentPadding" to { it::setContentPadding },
"minZoom" to { it::setMinZoom },
"maxZoom" to { it::setMaxZoom },
"maxTilt" to { it::setMaxTilt },
"locale" to { it::setLocale },
"scaleBarEnable" to nonNullFunc { it::setScaleBarEnable },
"indoorLevelPickerEnable" to nonNullFunc { it::setIndoorLevelPickerEnable },
"locationButtonEnable" to nonNullFunc { it::setLocationButtonEnable },
"logoClickEnable" to nonNullFunc { it::setLogoClickEnable },
"logoAlign" to nonNullFunc { it::setLogoAlign },
"logoMargin" to nonNullFunc { it::setLogoMargin },
"contentPadding" to nonNullFunc { it::setContentPadding },
"minZoom" to nonNullFunc { it::setMinZoom },
"maxZoom" to nonNullFunc { it::setMaxZoom },
"maxTilt" to nonNullFunc { it::setMaxTilt },
"locale" to nonNullFunc { it::setLocale },
"customStyleId" to { it::setCustomStyleId },
)

private fun nonNullFunc(ev: ((NaverMapOptionApplier) -> ((Any) -> Unit))): ((NaverMapOptionApplier) -> ((Any?) -> Unit)) {
return { applier ->
{ arg ->
if (arg == null) throw NullPointerException("Argument cannot be null for this option.")
ev.invoke(applier).invoke(arg)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ import dev.note11.flutter_naver_map.flutter_naver_map.util.DisplayUtil

class NaverMapApplierImpl(
private val naverMap: NaverMap,
private val customStyleCallback: NaverMap.OnCustomStyleLoadCallback? = null,
) : NaverMapOptionApplier {

override fun setInitialCameraPosition(rawPosition: Any) = Unit

override fun setExtent(rawLatLngBounds: Any) {
naverMap.extent = rawLatLngBounds.asLatLngBounds()
override fun setExtent(rawLatLngBounds: Any?) {
naverMap.extent = rawLatLngBounds?.asLatLngBounds()
}

override fun setMapType(rawMapType: Any) {
Expand Down Expand Up @@ -154,4 +155,8 @@ class NaverMapApplierImpl(
val nLocale = NLocale.fromMessageable(rawLocale)
naverMap.locale = nLocale?.toLocale()
}

override fun setCustomStyleId(rawCustomStyleId: Any?) {
naverMap.setCustomStyleId(rawCustomStyleId?.toString(), customStyleCallback)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package dev.note11.flutter_naver_map.flutter_naver_map.applier.option

internal interface NaverMapOptionApplier {
fun setInitialCameraPosition(rawPosition: Any)
fun setExtent(rawLatLngBounds: Any)
fun setExtent(rawLatLngBounds: Any?)
fun setMapType(rawMapType: Any)
fun setLiteModeEnable(rawEnable: Any)
fun setNightModeEnable(rawEnable: Any)
Expand Down Expand Up @@ -33,4 +33,5 @@ internal interface NaverMapOptionApplier {
fun setMaxZoom(rawLevel: Any)
fun setMaxTilt(rawTilt: Any)
fun setLocale(rawLocale: Any)
fun setCustomStyleId(rawCustomStyleId: Any?)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class NaverMapOptionApplierImpl(
options.camera(cameraPosition)
}

override fun setExtent(rawLatLngBounds: Any) {
options.extent(rawLatLngBounds.asLatLngBounds())
override fun setExtent(rawLatLngBounds: Any?) {
options.extent(rawLatLngBounds?.asLatLngBounds())
}

override fun setMapType(rawMapType: Any) {
Expand Down Expand Up @@ -155,4 +155,8 @@ class NaverMapOptionApplierImpl(
val nLocale = NLocale.fromMessageable(rawLocale)
options.locale(nLocale?.toLocale())
}

override fun setCustomStyleId(rawCustomStyleId: Any?) {
options.customStyleId(rawCustomStyleId?.toString())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ internal interface NaverMapControlHandler {

fun forceRefresh(onSuccess: () -> Unit)

fun updateOptions(rawOptions: Map<String, Any>, onSuccess: () -> Unit)
fun updateOptions(rawOptions: Map<String, Any?>, onSuccess: () -> Unit)

fun updateClusteringOptions(rawOptions: Map<String, Any>, onSuccess: () -> Unit)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@ internal interface NaverMapControlSender {
fun onCameraIdle()

fun onSelectedIndoorChanged(selectedIndoor: IndoorSelection?)

fun onCustomStyleLoaded()

fun onCustomStyleLoadFailed(exception: Exception)

fun dispose()
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.naver.maps.geometry.LatLng
import com.naver.maps.map.CameraUpdate
import com.naver.maps.map.LocationTrackingMode
import com.naver.maps.map.NaverMap
import com.naver.maps.map.NaverMapSdk
import com.naver.maps.map.Projection
import com.naver.maps.map.Symbol
import com.naver.maps.map.app.LegalNoticeActivity
Expand All @@ -20,8 +21,8 @@ import dev.note11.flutter_naver_map.flutter_naver_map.converter.MapTypeConverter
import dev.note11.flutter_naver_map.flutter_naver_map.converter.MapTypeConverter.toMessageableString
import dev.note11.flutter_naver_map.flutter_naver_map.model.enum.NOverlayType
import dev.note11.flutter_naver_map.flutter_naver_map.model.base.NPoint
import dev.note11.flutter_naver_map.flutter_naver_map.model.exception.NFlutterException
import dev.note11.flutter_naver_map.flutter_naver_map.model.map.NaverMapViewOptions
import dev.note11.flutter_naver_map.flutter_naver_map.model.map.info.NClusterableMarkerInfo
import dev.note11.flutter_naver_map.flutter_naver_map.model.map.info.NOverlayInfo
import dev.note11.flutter_naver_map.flutter_naver_map.model.map.info.NPickableInfo
import dev.note11.flutter_naver_map.flutter_naver_map.model.map.info.NSymbolInfo
Expand Down Expand Up @@ -230,9 +231,10 @@ internal class NaverMapController(
onSuccess()
}

override fun updateOptions(rawOptions: Map<String, Any>, onSuccess: () -> Unit) {
naverMapViewOptions =
NaverMapViewOptions.updateNaverMapFromMessageable(naverMap, rawOptions)
override fun updateOptions(rawOptions: Map<String, Any?>, onSuccess: () -> Unit) {
naverMapViewOptions = NaverMapViewOptions.updateNaverMapFromMessageable(
naverMap, rawOptions, getCustomStyleCallback()
)
onSuccess()
}

Expand Down Expand Up @@ -307,11 +309,32 @@ internal class NaverMapController(
channel.invokeMethod("onSelectedIndoorChanged", selectedIndoor?.toMessageable())
}

override fun onCustomStyleLoaded() {
channel.invokeMethod("onCustomStyleLoaded", null)
}

override fun onCustomStyleLoadFailed(exception: Exception) {
val flutterError = when (exception) {
is NaverMapSdk.AuthFailedException ->
if (exception.errorCode == "400") NFlutterException(
code = "400",
message = "Invalid custom style ID: ${exception.message}"
)
else NFlutterException(
code = exception.errorCode,
message = "Custom style load failed: ${exception.message}"
)
/// in iOS, 900 is no handling error code, so we use 900 here too
else -> NFlutterException(code = "900", message = exception.message)
}
channel.invokeMethod("onCustomStyleLoadFailed", flutterError.toMessageable())
}

/*
--- remove ---
*/

fun remove() {
override fun dispose() {
channel.setMethodCallHandler(null)
clusteringController.dispose()
overlayController.remove()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dev.note11.flutter_naver_map.flutter_naver_map.controller

import com.naver.maps.map.NaverMap.OnCustomStyleLoadCallback

internal fun NaverMapControlSender.getCustomStyleCallback(): OnCustomStyleLoadCallback =
object : OnCustomStyleLoadCallback {
override fun onCustomStyleLoaded() = this@getCustomStyleCallback.onCustomStyleLoaded()

override fun onCustomStyleLoadFailed(exception: Exception) =
this@getCustomStyleCallback.onCustomStyleLoadFailed(exception)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ internal object DefaultTypeConverter {
fun Any.asFloat(): Float = if (this is Double) toFloat() else this as Float
fun Any.asInt(): Int = if (this is Long) toInt() else this as Int
fun Any.asLong(): Long = if (this is Int) toLong() else this as Long

@Suppress("UNCHECKED_CAST")
fun Any.asMap(): Map<String, Any> = this as Map<String, Any>

@Suppress("UNCHECKED_CAST")
fun Any.asNullableMap(): Map<String, Any?> = this as Map<String, Any?>

@Suppress("UNCHECKED_CAST")
fun Any.asStringMap(): Map<String, String> = this as Map<String, String>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dev.note11.flutter_naver_map.flutter_naver_map.model.exception

data class NFlutterException(
val code: String,
val message: String?,
) {
fun toMessageable(): Map<String, Any?> {
return mapOf(
"code" to code,
"message" to message,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal data class NaverMapViewOptions(
companion object {
// factory constructor
fun fromMessageable(
args: Map<String, Any>,
args: Map<String, Any?>,
convertNaverMapOptions: Boolean = true,
): NaverMapViewOptions {
val options = if (convertNaverMapOptions) naverMapOptionFromMessageable(args) else null
Expand All @@ -40,15 +40,16 @@ internal data class NaverMapViewOptions(

fun updateNaverMapFromMessageable(
naverMap: NaverMap,
args: Map<String, Any>,
args: Map<String, Any?>,
customStyleCallback: NaverMap.OnCustomStyleLoadCallback? = null,
): NaverMapViewOptions {
val applier = NaverMapApplierImpl(naverMap)
val applier = NaverMapApplierImpl(naverMap, customStyleCallback)
applier.applyOptions(args)
return fromMessageable(args, false)
}

private fun naverMapOptionFromMessageable(
args: Map<String, Any>,
args: Map<String, Any?>,
): NaverMapOptions {
val options = NaverMapOptions().apply {
compassEnabled(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.naver.maps.map.NaverMapSdk.NcpKeyClient
import com.naver.maps.map.NaverMapSdk.OnAuthFailedListener
import dev.note11.flutter_naver_map.flutter_naver_map.converter.DefaultTypeConverter.asBoolean
import dev.note11.flutter_naver_map.flutter_naver_map.converter.DefaultTypeConverter.asMap
import dev.note11.flutter_naver_map.flutter_naver_map.model.exception.NFlutterException
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel

Expand All @@ -21,9 +22,7 @@ internal class SdkInitializer(
private fun handle(call: MethodCall, result: MethodChannel.Result) {
if (call.method == "initializeNcp") {
initializeWithNcp(
call.arguments.asMap(),
onSuccess = result::success,
onFailure = {
call.arguments.asMap(), onSuccess = result::success, onFailure = {
result.error(
if (it is NaverMapSdk.AuthFailedException) it.errorCode else it.javaClass.name,
it.message,
Expand All @@ -39,9 +38,7 @@ internal class SdkInitializer(
}

private fun initializeWithNcp(
args: Map<String, Any>,
onSuccess: (Any?) -> Unit,
onFailure: (Exception) -> Unit
args: Map<String, Any>, onSuccess: (Any?) -> Unit, onFailure: (Exception) -> Unit
) {
val clientId = args["clientId"]?.toString()
val hasAuthFailedListener = args["setAuthFailedListener"]?.asBoolean() ?: false
Expand Down Expand Up @@ -96,10 +93,8 @@ internal class SdkInitializer(

private fun onAuthFailedListener(ex: NaverMapSdk.AuthFailedException) {
channel.invokeMethod(
"onAuthFailed", mapOf(
"code" to ex.errorCode,
"message" to ex.message,
)
"onAuthFailed",
NFlutterException(code = ex.errorCode, message = ex.message).toMessageable()
)
}
}
Loading