상품 상세에서 Column안에 Native와 상품정보 WebView Component를 같이 사용해서 표시하는 구조로 되어있는데, 특정 상품에서 스크롤을 하게되면 Fatal signal 11 (SIGSEGV) 오류가 발생하면서 앱이 종료되는 이슈가 있었다.
해당 상품은 WebView컨텐츠에 이미지가 유독 많은 상품이였는데, 단순히 이미지가 많아서 Crash가 발생했다고 하기에는 다른 웹뷰로만 구성된 컨텐츠에는 더 많은 이미지가 리스트로 구성되어있는 케이스가 많았기 때문에 단순히 이미지 개수의 문제라고 생각되진 않았다.
Fatal signal 11 오류가 뭔지 먼저 찾아보았다.
"Segmentation Fault 오류로, 메모리를 잘못 참조한 경우에 발생합니다." 라고 설명한다.
일반적인 WebView와는 다른점을 비교해봤다.
뭔가 위 상황들때문에 WebView 길이가 길어지면서 로드시간이 늘어나고 스크롤시 WebView가 reload되면서 메모리에 올라간 WebView를 찾지 못해 메모리를 잘못 참조해 Crash가 발생한게 아닌가 추측했고, 처음에 WebView를 AndroidView를 Box로 감싸기도 해보고
검색해본 여러 해결 방안들을 시도(largeHeap 설정, WebViewSetting, 하드웨어 가속등)했지만 이슈가 해소되지 않았다.
그러던 중 아래 글
https://wbrawner.com/2024/08/28/android-webview-crash-in-jetpack-compose/
을 찾아 해결하게 되었는데
WebView에 FrameLayout을 씌워 해결하는 방법이었다.
기존 코드는 아래와 같이 되어있었는데
AndroidView(
modifier = modifier,
factory = {
WebView(it).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
settings.run {
javaScriptEnabled = true
useWideViewPort = true
loadWithOverviewMode = true
loadsImagesAutomatically = true
allowContentAccess = true
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
cacheMode = WebSettings.LOAD_NO_CACHE
overScrollMode = View.OVER_SCROLL_NEVER
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
setLayerType(View.LAYER_TYPE_HARDWARE, null)
}
textZoom = 100
}
webViewClient = object : WebViewClient() {...}
webChromeClient = object : WebChromeClient() {...}
loadUrl(url)
}
},
update = {
it.loadUrl(url)
}
)
다음과 같이 변경해 주었다.
AndroidView(
modifier = modifier,
factory = {
FrameLayout(it).apply {
addView(
WebView(it).apply {
tag = "webView" //framelayout에서 구분할 이름
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
settings.run {
javaScriptEnabled = true
useWideViewPort = true
loadWithOverviewMode = true
loadsImagesAutomatically = true
allowContentAccess = true
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
cacheMode = WebSettings.LOAD_NO_CACHE
overScrollMode = View.OVER_SCROLL_NEVER
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
setLayerType(View.LAYER_TYPE_HARDWARE, null)
}
textZoom = 100
}
webViewClient = object : WebViewClient() {...}
webChromeClient = object : WebChromeClient() {...},
update = {
it.findViewWithTag<WebView>("webView").apply {
loadUrl(url)
}
}
이렇게 FrameLayout으로 감싸서 WebView를 구성해주니 컨텐츠가 커도 정상적인 동작을 할 수 있었다.
아직 정확한 내부 메커니즘이 어떻게 동작해서 FrameLayout으로 감쌀경우 오류가 발생하지 않는지 모르겠다.(댓글로 알려주시면 감사드립니다)
Compose WebView는 사용할때마다 다양한 오류가 발생하는데 2년이 넘도록 사용했지만 아직 알아야할게 더 많은 것 같다.
같은 이슈를 겪고있는 분들이 있으시다면 도움이 되셨길 바랍니다. 감사합니다.