Skip to content

fix(Android): remove the internal glsurface key before option parsing — forceGLSurfaceView currently breaks the map - #366

Open
kyhyeok wants to merge 1 commit into
note11g:mainfrom
kyhyeok:fix/glsurface-key-strip
Open

fix(Android): remove the internal glsurface key before option parsing — forceGLSurfaceView currently breaks the map#366
kyhyeok wants to merge 1 commit into
note11g:mainfrom
kyhyeok:fix/glsurface-key-strip

Conversation

@kyhyeok

@kyhyeok kyhyeok commented Aug 27, 2026

Copy link
Copy Markdown

한국어 요약NaverMap.forceGLSurfaceView를 넘기면 안드로이드에서 플랫폼 뷰 생성이 예외로 죽어 지도가 빈 화면이 됩니다. platform_view.dart가 창조 파라미터에 넣는 glsurface 키를 팩토리가 옵션 파서에 그대로 넘기고, ApplyUtil.applyOptions가 모르는 키에 NoSuchMethodException을 던지기 때문입니다(그 키는 optionApplyFuncMap에 없습니다). 즉 플러그인이 자기가 넣은 키에 자기가 걸립니다.

고침은 옵션 파서 앞에서 그 키를 떼어내는 3줄 순서 변경입니다. 갤럭시 A12(API 31) release 빌드에서 전/후를 확인했습니다 — 전: 빈 화면 + NoSuchMethodException, 후: 정상 렌더 + 예외 0건.

⚠️ 한계: 기기 한 대(API 31) 확인이고, android/src/에 테스트 소스셋이 없어 회귀 테스트는 넣지 않았습니다(원하시면 소스셋까지 함께 넣겠습니다).


Problem

Passing NaverMap.forceGLSurfaceView on Android makes the platform view fail to be created. The map area renders blank (the Flutter overlays — logo, scale bar, controls — still draw, so it is easy to mistake for a styling problem) and logcat shows:

E DartMessenger: Uncaught exception in binary message listener
E DartMessenger: java.lang.NoSuchMethodException: No such method "glsurface".
                 Please check the handling of this method.
        at io.flutter.plugin.platform.<PlatformViewsController>.<createPlatformView>

NaverMapView's own log line (Installing custom TextureView driven invalidator. / No TextureView found. Likely using the LEGACY renderer.) never appears — init is not reached.

So the parameter does not work in production at all, not just in tests.

Cause

The plugin injects its own key into the creation params:

// lib/src/widget/platform_view.dart:38
rawCreationParameters.addAll({"glsurface": forceGLSurfaceView});

and the factory hands the whole map to the option parser before reading that key back:

// android/src/main/kotlin/.../view/NaverMapViewFactory.kt
val convertedArgs = args!!.asNullableMap()
val options = NaverMapViewOptions.fromMessageable(convertedArgs)   // consumes the whole map
val usingGLSurfaceView = convertedArgs["glsurface"] as? Boolean?   // never reached

NaverMapViewOptions.fromMessageablenaverMapOptionFromMessageableApplyUtil.applyOptions iterates every entry and throws NoSuchMethodException for keys it does not recognise:

// android/src/main/kotlin/.../applier/ApplyUtil.kt
} else {
    throw NoSuchMethodException("No such method \"$funcName\". Please check the handling of this method.")
}

and optionApplyFuncMap has no "glsurface" entry. The plugin therefore trips on a key it added itself, on every NaverMap that passes forceGLSurfaceView.

Fix

Read and remove the key before the option parser runs. Same three lines, reordered:

val convertedArgs = args!!.asNullableMap().toMutableMap()
val usingGLSurfaceView = convertedArgs.remove("glsurface") as? Boolean?
val options = NaverMapViewOptions.fromMessageable(convertedArgs)

Types line up: asNullableMap() returns Map<String, Any?>, and fromMessageable(args: Map<String, Any?>) accepts the resulting MutableMap.

Verification

Built and run on a Samsung Galaxy A12 (Android 12 / API 31), Flutter 3.44.4, release build:

  • before — map area blank, NoSuchMethodException in logcat, zero NaverMapView log lines;
  • afterI NaverMapView: Installing custom TextureView driven invalidator., no exception, map renders normally (tiles, clusters, my-location marker, labels), and 12 open/close cycles are flat on native heap.

I did not add a regression test: android/src/ contains only a main source set, so there is no Kotlin test target to put one in. I'd be glad to add one together with the test source set if you want it in this PR.

Why this matters beyond the parameter itself

forceGLSurfaceView is currently the only in-plugin way to opt out of the GLSurfaceView render view, and on API 30–32 that render path leaks the map's whole View tree and ~18 MB of native heap per open/close. Measurements, bytecode trace and the TextureView comparison are in #365.

Thanks for maintaining this plugin — happy to adjust anything here (including the comment wording or dropping the comment entirely).

platform_view.dart injects a "glsurface" entry into the platform view's
creation params when NaverMap.forceGLSurfaceView is set, but the factory
passed the whole map to NaverMapViewOptions.fromMessageable before reading
that entry back. ApplyUtil.applyOptions iterates every key and throws
NoSuchMethodException for keys it does not know, and optionApplyFuncMap has
no "glsurface" entry — so the platform view failed to be created and the map
rendered blank whenever forceGLSurfaceView was used.

Read and remove the key before the option parser runs.

Verified on a Galaxy A12 (Android 12 / API 31), Flutter 3.44.4, release
build: before, the map area was blank with NoSuchMethodException in logcat
and no NaverMapView log line; after, the map renders normally and no
exception is thrown.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants