본문 바로가기

Android/WebView

[WebView] Compose 환경에서 WebView로 Youtube를 넣어보자.

728x90

필자가 Compose 환경에서 WebView를 통해 Youtube를 넣는 작업을 하면서 만났던 이슈와 해결 방법을 기술해보고자 한다.

WebView를 보여줄 때 생각지도 못한 부분에서 이슈가 생겼었고, 생각보다 UX 면에서 크리티컬 하다고 느꼈던 이슈들이기 때문에 추후에도 도움이 될 것이라고 생각이 된다.


우선,

Compose 환경에서 Webview를 사용하기 위해서는 Gradle에 다음과 같은 라이브러리를 포함시켜줘야 한다.

 

implementation "com.google.accompanist:accompanist-webview:$version"

 

 

Compose 환경에서 Webview를 사용할 때,
기본적으로 세팅해야하는 부분은 Compose가 아닌 케이스에서 Webview를 사용하는 것과 일치한다.

 

2022.04.06 - [Android/WebView] - [WebView] WebView 사용 방법 - 1. WebView 적용 및 JavaScriptInterface의 사용.

2022.04.09 - [Android/WebView] - [WebView] WebView 사용 방법 - 2. WebClient 및 다중 JavaScriptInterface 사용.

 

위의 두 글을 읽어보면 세팅에 대한 설명이 기술되어있으니 참고하길 바란다.

 

@Composable
fun WebViewYoutubePlayer(youtubeUrl: String) {
    val webViewState = rememberWebViewState(url = youtubeUrl)
    val webViewClient = AccompanistWebViewClient()
    val webChromeClient = AccompanistWebChromeClient()
    val configuration = LocalConfiguration.current
    val screenWidth = configuration.screenWidthDp.toFloat()
    val screenHeight = (screenWidth * 9 / 16).dp

    WebView(
        modifier = Modifier
            .height(screenHeight)
            .background(color = Color.Transparent)
            .fillMaxWidth(),
        state = webViewState,
        client = webViewClient,
        chromeClient = webChromeClient,
        onCreated = { webView ->
            with(webView) {
                settings.run {
                    javaScriptEnabled = true
                    domStorageEnabled = true
                    javaScriptCanOpenWindowsAutomatically = false
                    mediaPlaybackRequiresUserGesture = false
                }
                
                setBackgroundColor(0)
            }
        }
    )
}

 

configuration과 screenWidth는 화면 비율을 맞추기 위해서 설정한 부분이므로 다르게 설정해도 상관없다.

 

위와 같이 선언 후 youtube 링크를 넣어주면 다음과 같이 완성이 된다.

 

 

화면의 크기를 고정했기 때문에, 위와 같은 화면에서 스크롤이 정상적으로 동작하지 않는다.

게다가 필자는 저런 화면이 아닌, 영상에 대한 디스크립션이 포함된 것이 아닌 영상만 보는 것을 원했다.

 

https://support.google.com/youtube/answer/171780?hl=en

 

해당 가이드 페이지에서 내용을 읽어보면 필자가 원하는 UI로 보이기 위해서는 URL을 바꿔야 한다는 것을 확인할 수 있다.

 

https://www.youtube.com/embed/

 

Webview에 들어가는 URL이 위와 같은 형식으로 되어있으면 된다.

 

따라서, URL을 위와 같은 형태로 만들어 준 후에 Webview에 넣어주도록 한다.

 

 

이처럼 필자가 원하는 대로 나오게 되었다.

 

작업을 하다가 알게된 부분이 있는데, 공유할 수 있는 Youtube URL은 2가지 케이스가 존재한다.

 

youtube.com
youtu.be

 

이 2가지 케이스에서, embed 시킬 youtube Link를 만들 때 필요한 영상의 키 값은 다르게 구해야 한다.

 

fun getEmbedYoutubeUrl(youtubeUrl: String): String {
    val youTubeTypeURL = "www.youtube.com"
    val youTubeTypeURL2 = "youtu.be"
    val youTubeLoadUrl = "https://www.youtube.com/embed/"

    return youTubeLoadUrl +
            if (youtubeUrl.contains(youTubeTypeURL)) {
                youtubeUrl.split("watch?v=")[1]
            } else if (youtubeUrl.contains(youTubeTypeURL2)) {
                youtubeUrl.split("youtu.be/")[1]
            } else {
                ""
            }
}

 

따라서 필자는 아주 간단하게 split 하는 함수를 만들어서 사용하였다.


위와 같이 원하는대로 UI를 만들어 보았는데, 여기서 끝이 아니다.

 

 

영상에서 확인할 수 있듯이, 전체화면이 정상적으로 되지 않는다.

 

전체화면을 지원하기 위해서는, WebChromClient에서 다음과 같은 함수를 override 하여 추가적인 구현을 해주어야 한다.

 

class YoutubeWebChromeClient(
    private val context: Context,
) : AccompanistWebChromeClient() {

    override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
        ...
    }

    override fun onHideCustomView() {
        ...
    }
}

 

onShowCustomView에서는 전체화면 버튼 눌렀을 때의 작업을, onHideCustomView에서는 전체화면을 제거할 때의 작업을 넣어주면 된다.

함수의 이름에서 알 수 있듯이, 버튼을 클릭했을 때 custom View를 새롭게 만들어서 보여주는 작업이 된다.

 

class YoutubeWebChromeClient(
    private val context: Context,
) : AccompanistWebChromeClient() {
    private var fullScreenView: View? = null
    private val windowManager: WindowManager by lazy {
        context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
    }

    override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
        if (fullScreenView != null) { // fullScreen이 떠있으면
            callback?.onCustomViewHidden() // 종료 시킨다.
            return
        }

        fullScreenView = view
        // 뷰 추가
        windowManager.addView(fullScreenView, WindowManager.LayoutParams())
    }

    override fun onHideCustomView() {
        super.onHideCustomView()
        // 뷰 제거
        windowManager.removeView(fullScreenView)
        fullScreenView = null
    }
}

 

fullScreenView라는 커스텀 뷰를 만들어서 필요한 타이밍에 설정하고 제거해 준다.

 

위처럼 정상적으로 동작하는 것을 볼 수 있다.


이와 같이 하나의 영상만 보여줄 때도 있지만, 다양한 환경에서 여러 개의 영상을 보여줄 가능성이 있다.

LazyColumn을 통해 여러개의 Webview를 선언해 youtube를 보여준다면 어떻게 될까? 

 

 

영상에서 볼 수 있듯이 스크롤을 할 때 화면 전체가 검은색으로 깜빡이는 것을 볼 수 있다.

해당 이슈는 웹뷰에서의 하드웨어 가속 옵션 때문에 발생하는 것이었다.

 

https://developer.android.com/guide/topics/graphics/hardware-accel?hl=ko

위의 문서에서 볼 수 있듯이 기본적으로 Layer를 추가할 때 3가지 옵션을 사용할 수 있다.

NONE은 default 값이므로 기존에 해당 옵션이 들어가 있다고 생각하면 된다.

 

Layer_type_software를 사용하게 되면, 해당 Webview Layer만 하드웨어 가속을 중단하게 된다.

따라서 해당 옵션을 설정하게 되면 다음과 같은 결과를 볼 수 있다.

 

 

스크롤 시 깜빡임은 없어졌지만, 재생했을 때 정상적으로 재생이 되지 않는다.

직접 확인해 보면 알 수 있겠지만, 임베드된 웹뷰에서는 검은 화면이 나오지만 영상의 소리는 정상적으로 나오며 Seekbar를 옮겼을 때 영상의 preview도 잘 나오는 것을 알 수 있다.

 

Layer_type_hardware로 설정하게 되면, 하드웨어 가속을 사용하게 된다.

따라서 필자가 원하는 대로 모든 부분이 동작하게 된다.

 

 

 


이처럼, Webview에 youtube를 embed 하는 작업을 진행하면서 필자가 만난 문제들과 해결하는 방법을 기술해 보았다.

생각보다 웹뷰로 설정하는 것에 대한 정보가 많지 않았고, 그렇기 때문에 직접 찾아가고 확인해 가면서 적용했던 부분이 많았었다.

 

사실 스크롤하는 부분에 대해서는 실무에 적용하고, 여러 가지 테스트를 해보다가 발견한 부분으로 처음 해당 이슈를 찾았을 때 적지 않게 당황했던 것 같다. 어떠한 이유로 화면이 저런 형식으로 갱신되는지는 정확하게 파악하지는 못했지만, 운이 좋게도 하드웨어 가속 문제라는 것을 우연하게 발견하게 되어 해결할 수 있었다.

 

웹뷰에 대해서는 여러모로 사용하고는 있지만, 생각보다 사용하던 것들만 사용하기 때문에 새로운 것들을 적용할 때마다 다양한 이슈를 경험하는 것 같아서 재미가 있는 것 같다.

 

이런 이슈 외에도, 다른 문제를 발견하고 해결한다면 글을 남기도록 하겠다.

 

해당 게시글에 사용한 예제는 Github에 올려두었다.

https://github.com/HeeGyeong/ComposeSample

 

GitHub - HeeGyeong/ComposeSample

Contribute to HeeGyeong/ComposeSample development by creating an account on GitHub.

github.com

 

728x90