[Android] WebView 주요 설정 및 백그라운드에서 음악 재생하기
by Yena Choi
Study Note
네이티브 앱 개발을 하면서도 웹뷰를 이용해야 하는 경우가 종종 생긴다. 다행히도 안드로이드에서는 코드 몇 줄만 추가해주면 간단하게 웹뷰를 띄워줄 수 있다.
얼마 전, 브라우저 내에서 실행되는 미디어를 백그라운드에서 재생하는 웹뷰를 만들어야 했는데, 겸사겸사 웹뷰의 세부적인 옵션에 대해서도 정리해봤다.
사전 준비
네트워크 권한 추가
새 프로젝트 만들 때마다 첫 빌드 하고 아차! 하는 작업이다.
매니페스트 AndroidManifest.xml
파일을 열어 manifest
태그 사이에 인터넷 허용을 위한 코드를 넣어준다.
<uses-permission android:name="android.permission.INTERNET"/>
화면 구성
웹뷰만 띄워줄 예정이므로 아무것도 없이 심플하게 웹뷰로만 구성했다.
<!-- activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<WebView
android:id="@+id/myWebView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
또, 앱 기본 액션바를 없애 웹 사용에만 최적화되도록 만들었다.
스타일 테마를 NoActionBar
로 교체해주었다.
<!-- styles.xml -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
WebView 실행하기
정말정말 기능 없고 간단한 웹뷰만 띄우려면 코드 한 줄이면 된다.
/* MainActivity.kt */
myWebView.loadUrl("https://www.google.com")
WebSettings 설정
하지만 위의 예제처럼만 만들면 원하는 대로 화면이 만들어지지 않거나, 일부 웹 기능을 사용할 수 없을 것이다. WebSettings
클래스는 웹에서 사용 할만한 기능을 쉽게 On, Off 할 수 있도록 도와준다.
자바 스크립트 실행 여부, 새 창, 메타태그, 화면 줌, 캐싱 등의 설정을 할 수 있다.
myWebView.settings.apply {
javaScriptEnabled = true // 자바스크립트 실행 허용
javaScriptCanOpenWindowsAutomatically = false // 자바스크립트에서 새창 실 행 허용
setSupportMultipleWindows(false) // 새 창 실행 허용
loadWithOverviewMode = true // 메타 태그 허용
useWideViewPort = true // 화면 사이즈 맞추기 허용
setSupportZoom(false) // 화면 줌 허용
builtInZoomControls = false // 화면 확대 축소 허용 여부
cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK // 브라우저 캐시 허용 여부
domStorageEnabled = true // 로컬저장소 허용
}
WebViewClient 로 현재 웹뷰에서 URL 이동하기
MainActivity 에서 성공적으로 구글 홈페이지를 불러왔다고 해도, 검색어를 입력한 후 검색을 누르면 외부 브라우저로 검색 결과 페이지가 열리며 앱이 백그라운드로 이동할 것이다.
현재 창에서 다른 url로 연결되게 하고 싶으면 WebViewClient
를 하나 연결해준 후 url 로딩을 해당 웹뷰 안에서 실행해주어야 한다. 그러면 화면 전환 없이 내부에서 다음 url로 이동할 것이다.
정확히는 웹뷰 클라이언트의 shouldOverrideUrlLoading
함수를 오버라이드해 url을 현재 웹뷰에서 로드해주는 방식이다.
myWebView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
view.loadUrl(url)
return true
}
}
이 외에도, WebViewClient에서 Override 할 수 있는 함수에는 여러 가지가 있다.
/* 페이지 로딩이 시작될 때 */
fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?)
/* 페이지 로딩이 끝났을 때 */
fun onPageFinished(view: WebView?, url: String?)
/* Request 재정의 - 헤더 추가 등의 요청을 커스텀할 수 있다 */
fun shouldInterceptRequest(
view: WebView?,
request: WebResourceRequest?
): WebResourceResponse?
/* 에러가 발생했을 때 - 에러 코드 별로 when 조건문을 사용할 수 있다 */
fun onReceivedError(
view: WebView?,
errorCode: Int,
description: String?,
failingUrl: String?
){
super.onReceivedError(view, errorCode, description, failingUrl)
when (errorCode) {
ERROR_AUTHENTICATION -> {
}
ERROR_BAD_URL -> {
}
ERROR_CONNECT -> {
}
ERROR_FILE_NOT_FOUND -> {
}
...
}
}
/* 잘못된 키 입력이 있는 경우 */
fun shouldOverrideKeyEvent(view: WebView?, event: KeyEvent?): Boolean
...
Background 에서 WebView 사용
모바일 Youtube 페이지를 실행하는 웹뷰를 띄우는 코드를 적어 보았다.
class MainActivity : AppCompatActivity() {
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
myWebView.apply {
settings.javaScriptEnabled = true
webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
view.loadUrl(url)
return true
}
}
}.run {
loadUrl(URL_M_YOUTUBE)
}
}
companion object {
const val URL_M_YOUTUBE = "https://m.youtube.com/"
}
}
자바 스크립트를 실행할 수 있게 하고, 다른 url로 이동할 때 내부 웹뷰에서 처리되도록 설정했다.
이 코드로 원하는 동영상을 재생한 후, 시간이 지나 디바이스의 화면이 꺼지면 영상과 소리도 재생이 중단된다. 웹뷰에서 화면(Window)의 visibility 상태 변화를 감지하기 때문이다.
사용자 커스텀 웹뷰를 만들어서, 화면의 visibility 를 View.VISIBLE
로 세팅하면 앱이 백그라운드 태스크로 이동하거나 화면이 꺼져도 계속 미디어를 실행시키도록 할 수 있다.
CustomWebView 생성
기본 WebView 를 상속받는 웹뷰 클래스를 만든다. 이 예제에서는 BackgroundWebView
라는 이름의 웹뷰를 만들었다. 생성자를 각각 만들어주고, 무엇보다 중요한 onWindowVisibilityChanged
함수를 재정의한다.
class BackgroundWebView : WebView {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
override fun onWindowVisibilityChanged(visibility: Int) {
if (visibility != View.GONE) super.onWindowVisibilityChanged(View.VISIBLE)
}
}
그리고 레이아웃도 기존 WebView -> BackgroundWebView 로 변경해준다.
<!-- activity_main.xml -->
...
<io.yena.webviewexample.BackgroundWebView
android:id="@+id/myWebView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
새로운 웹뷰 클래스로 교체했으면 앱을 재빌드해 실행해보자. 화면을 꺼도 내가 재생한 유튜브 영상의 소리가 나오는 것을 들을 수 있다! 물론 유튜브 음악 재생만이 목적이라면 유튜브 프리미엄을 구독하면 되겠지만, 미디어는 다양한 곳에서 사용되므로 백그라운드에서 실행되는 방법을 알아 두어도 나쁘지 않아 보인다.
References
- https://developer.android.com/reference/android/webkit/WebView
- https://web-inf.tistory.com/34
- https://stackoverflow.com/questions/52028940/how-can-i-make-webview-keep-a-video-or-audio-playing-in-the-background
- https://cofs.tistory.com/186