WebView 알아보기

두리두두·2024년 7월 5일
0

Android

목록 보기
25/25
  • 회사에서... PIP모드를 제공하는 웹뷰 화면을 띄워야할 일이 생겼다. 근데 iOS는 OS에서 지원이 되는데 안드로이드는 안돼서 PIP 가 가능하게 셋팅을 따로 해줘야한다. 심지어 이것도 Oreo 버전 이상부터 지원한다.
  • 한참 헤매다가 알아낸 사실 정리...
  • 우리 웹뷰는 Webview를 상속받은 MyWebview 객체를 WebView.java에서 생성해서 사용한다. 여기서 웹뷰 셋팅도 함.
  • 업체에서 가이드 준 PIP 방법은 PictureInPictureParams 사용. 가이드 코드를 보니 아래와 같았다.
package com.android.pictureinpicture

import android.annotation.SuppressLint
import android.app.PictureInPictureParams
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.util.Rational
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebSettings
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import android.webkit.WebView
import android.webkit.WebViewClient

class VideoActivity : AppCompatActivity() {

    private val TAG:String = "PIP_TAG"
    private var pictureInPictureParamsBuilder:PictureInPictureParams.Builder? = null
    private lateinit var webView: WebView

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //init PictureInPictureParams, requires Android O and above
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
        }

        webView = findViewById(R.id.webView)
        // Load web page in WebView
        webView.webViewClient = WebViewClient()
        this.setupWebView()
        webView.loadUrl("https://dev-player.charlla.io/shoplayer/list/QFuoEZxk1AJ?l=grid")
    }

    @SuppressLint("SetJavaScriptEnabled")
    private fun setupWebView() {
        val webSettings: WebSettings = webView.settings;
        webSettings.javaScriptEnabled = true
        webSettings.mediaPlaybackRequiresUserGesture = false
        webSettings.loadWithOverviewMode = true
        webSettings.useWideViewPort = true
        webSettings.domStorageEnabled = true

        webView.webViewClient = WebViewClient()
        webView.webChromeClient = object : WebChromeClient() {
            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
                super.onShowCustomView(view, callback)
                pictureInPictureMode()
            }
        }
    }

    private fun pictureInPictureMode(){
        //Requires Android O and higher
        Log.d(TAG, "pictureInPictureMode: Try to enter in PIP mode")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            Log.d(TAG, "pictureInPictureMode: Supports PIP")
            //setup PIP height width
            val aspectRatio = Rational(webView.width, webView.height)
            pictureInPictureParamsBuilder!!.setAspectRatio(aspectRatio).build()
            enterPictureInPictureMode(pictureInPictureParamsBuilder!!.build())
        }
        else{
            Log.d(TAG, "pictureInPictureMode: Doesn't supports PIP")
            Toast.makeText(this, "Your device doesn't supports PIP", Toast.LENGTH_LONG).show()
        }
    }

    override fun onUserLeaveHint() {
        super.onUserLeaveHint()
        //when user presses home button, if not in PIP mode, enter in PIP, requires Android N and above
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            Log.d(TAG, "onUserLeaveHint: was not in PIP")
            pictureInPictureMode()
        }
        else{
            Log.d(TAG, "onUserLeaveHint: Already in PIP")
        }
    }

    override fun onBackPressed() {
        onUserLeaveHint()
    }

    override fun onPictureInPictureModeChanged(
        isInPictureInPictureMode: Boolean,
        newConfig: Configuration?
    ) {
        super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
        if (isInPictureInPictureMode){
            Log.d(TAG, "onPictureInPictureModeChanged: Entered PIP")
        }
        else{
            Log.d(TAG, "onPictureInPictureModeChanged: Exited PIP")
        }
    }

    override fun onStop() {
        super.onStop()
    }
}
  • 중요한건 여기다.
webView.webViewClient = WebViewClient()
        webView.webChromeClient = object : WebChromeClient() {
            override fun onShowCustomView(view: View?, callback: CustomViewCallback?) {
                super.onShowCustomView(view, callback)
                pictureInPictureMode()
            }
        }
  • 웹뷰 속성을 지정해주는 부분에 webViewClient가 있다. 여기서 커스텀 설정을 해주면 되는데 onShowCustomView를 오버라이드해서 PIP가 가능하게 고쳐주면 된다. 밑의 PIP 활용 부분은 복붙하면 될듯하다.
  • WebView.java 파일에서 이 설정을 해두면 되지않을까 한다 ,,,
    => 알고보니 PictureInPictureParams는 Activity에서만 작동가능해서 메인액티비티 함수 모아두는 파일에 작성하였다.
  • 안드로이드는 애초에 pip 동작이 있어야 할 때 이 함수를 타야할것같다 ;;
    => WebView.java에 함수 하나 뚫어서 화면에서 사용 가능하게 처리하였다.
public class MyWebView extends WebView {
    // ... (기타 코드 생략)

    public void enterPIPMode() {
        // PIP 모드로 전환하는 로직 추가
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            PictureInPictureParams.Builder pipBuilder = new PictureInPictureParams.Builder();
            Rational aspectRatio = new Rational(getWidth(), getHeight());
            pipBuilder.setAspectRatio(aspectRatio);
            enterPictureInPictureMode(pipBuilder.build());
        } else {
            Toast.makeText(getContext(), "Your device doesn't support PIP", Toast.LENGTH_SHORT).show();
        }
    }
}
  • 이걸 화면에서 Webview0.enterPIPMode() 고고

  • 정리하자면

  1. WebChromeClient 셋팅하는 부분에 onShowCustomView 오버라이드하여 PIP 빌더 생성셋팅해둠
  2. 근데 생각해보니 위처럼 enterPIPMode()를 만들어서 여기서 바로 만들면 안되는건가?

webViewSettings

  • 웹뷰 전반적인 셋팅
  • Javascript 활성화, 캐시 설정, 이미지 자동 로드 등의 설정
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); // 캐시 사용
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); // 캐시 사용 안 함
webView.getSettings().setLoadsImagesAutomatically(true);

webViewClient

  • 자주 쓰는 메소드
    1) shouldOverringUrlLoading : 웹뷰에서 url이 로딩될 때 호출되며 앱에서 제어할 수 있다. 반환 default는 false이며 로딩 제어시 true를 반환해주어야 한다.
    2) onPageStarted : 페이지가 로딩이 시작되는 시점에 호출됨
    3) onPageFinished : 페이지가 로딩이 완료되는 시점에 호출됨
    4) onReceivedSslError : 수신받은 SSL에러가 발생한 경우 호출되며 분기로직을 통해 처리 해줌

webViewChromeClient

  • 자주 쓰는 메소드
    1) 비디오 설정
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
    // 비디오가 전체 화면으로 표시될 때 처리
}

@Override
public void onHideCustomView() {
    // 비디오가 전체 화면에서 사라질 때 처리
}

2) JavaScript 설정

  • onJsAlert / onJsConfirm / onJsPrompt: JavaScript에서 alert(), confirm(), prompt() 함수를 호출할 때 처리 가능
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    // JavaScript alert 처리
    return true;
}

@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
    // JavaScript confirm 처리
    return true;
}

@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
    // JavaScript prompt 처리
    return true;
}

  • 여자처자 하여 회사 소스로 테스트를 완료했다. 모든 예제가 다 액티비티에서 이루어져서 웹뷰를 따로 파일로 빼서 쓰는 우리 소스에서 실행이 안되어 오래 삽질을 했다.
  • 풀사이즈, 비율 등 설정을 추가하면 될 것 같다! 회사 앱 소스는 많이 못봤는데 조금 더 구조를 이해할 수 있게 된 조금 뿌듯한 업무였다 ~

참고

https://velog.io/@pachuho/Android-WebView-%EC%95%8C%EA%B3%A0-%EC%93%B0%EA%B8%B0#-webview-settings

https://docs.shoplive.kr/docs/android-sdk-mobile-webview

https://velog.io/@tlsgks48/%EC%BD%94%ED%8B%80%EB%A6%B0-WebView%EB%A1%9C-%ED%8E%98%EC%9D%B4%EC%A7%80-%EB%9D%84%EC%9A%B0%EA%B8%B0-%EB%B9%84%EB%94%94%EC%98%A4-%EC%A0%84%EC%B2%B4%ED%99%94%EB%A9%B4-%EC%9E%AC%EC%83%9D

profile
야금야금 앱 개발자

0개의 댓글