Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- android custom view
- ktor client
- llm
- android
- ExoPlayer
- kotlin list
- exoplayer cache
- android ktor
- AWS EC2
- 안드로이드
- ListAdapter
- getChangePayload
- list map
- video caching
- doc2vec
- android exoplayer
- DiffUtil.ItemCallback
- map
- ListAdapter DiffUtil
- build with ai
- 유튜브
- ChatGPT
- FastAPI
- 시행착오
- Zsh
- ktor api call
- kotlin collection
- 독서
- Python
- 스피너
Archives
- Today
- Total
버튼 수집상
[안드로이드] 웹크롬클라이언트로 웹뷰 새 창 처리하기 WebChromeClient onCreateWindow 본문
TIL - 안드로이드
[안드로이드] 웹크롬클라이언트로 웹뷰 새 창 처리하기 WebChromeClient onCreateWindow
cocokaribou 2024. 4. 1. 10:35안드로이드 웹뷰에서 setSupportMultipleWindows를 true로 세팅하면
웹에서 window.open()로 이동할 때 WebChromeClient의 onCreateWindow 함수를 타게 된다.
웹뷰 설정을 알고자 간단한 웹페이지와 앱을 만들어 테스트해봤다.
웹페이지의 구조는 이렇다.
① =새창=> ② => ③ => ① =새창=> ② => ③ => ① =새창=> ② => ③ ...
기본웹뷰 세팅
BaseWebview.kt
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.webkit.CookieManager
import android.webkit.WebSettings
import android.webkit.WebView
@SuppressLint("SetJavaScriptEnabled")
class BaseWebView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : WebView(context, attrs, defStyleAttr) {
init {
settings.setSupportMultipleWindows(true) // 새 창 허용
settings.javaScriptCanOpenWindowsAutomatically = true
settings.javaScriptEnabled = true
settings.setSupportZoom(true)
settings.builtInZoomControls = false
settings.useWideViewPort = true
settings.domStorageEnabled = true
settings.cacheMode = WebSettings.LOAD_DEFAULT
settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
settings.textZoom = 100
val cookieManager = CookieManager.getInstance()
cookieManager.setAcceptCookie(true)
cookieManager.setAcceptThirdPartyCookies(this, true)
}
}
메인 액티비티 레이아웃
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.pionnet.new_webview_test.BaseWebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:id="@+id/sub_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:background="@drawable/border"
tools:visibility="visible"
android:visibility="gone" />
</androidx.constraintlayout.widget.ConstraintLayout>
sub_webview라는 아이디의 RelativeLayout에 새 창을 쌓을 것.
서브 창에는 하얀색 테두리를 둘렀다.
메인 액티비티
MainActivity.kt
import android.os.Bundle
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private val webview: BaseWebView by lazy { findViewById(R.id.webview) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webview.webViewClient = WebViewClient()
webview.webChromeClient = MyWebChromeClient(this, onBackPressedDispatcher)
webview.loadUrl(Config.SITE_URL)
}
}
WebViewClient는 그냥 디폴트로 붙였다.
새 창 처리하는 크롬클라이언트
MyWebChromeClient.kt
import android.app.AlertDialog
import android.content.Context
import android.os.Message
import android.view.ViewGroup
import android.webkit.JsResult
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.RelativeLayout
import androidx.activity.OnBackPressedDispatcher
import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
var counter = 10
open class MyWebChromeClient(private val mContext: Context, private val onBackCallback: OnBackPressedDispatcher) : WebChromeClient() {
private val subBaseView: RelativeLayout by lazy { (mContext as AppCompatActivity).findViewById(R.id.sub_webview) }
private val mainWebView: BaseWebView by lazy { (mContext as AppCompatActivity).findViewById(R.id.webview) }
init {
// 백 키 누를 때마다 쌓여있는 새 창 벗겨내기
onBackCallback.addCallback {
if (subBaseView.isVisible) {
val lastWebView = subBaseView.getChildAt(subBaseView.childCount - 1) as? BaseWebView
lastWebView?.let {
if (it.canGoBack()) {
// 웹뷰 히스토리가 있으면 뒤로가기
it.goBack()
} else {
// 웹뷰 히스토리 없으면 새 창 remove
subBaseView.removeView(lastWebView)
counter -= 10
val secondLastWebView = subBaseView.getChildAt(subBaseView.childCount - 1) as? BaseWebView
secondLastWebView?.let {
// 새 창 remove 했는데 아래에 새 창이 또 있을 경우
secondLastWebView.evaluateJavascript("revealed();", null);
} ?: run {
// 새 창 remove 했는데 메인 웹뷰가 나왔을 경우
counter = 10
subBaseView.removeAllViews()
subBaseView.isVisible = false
mainWebView.evaluateJavascript("revealed();", null);
}
}
}
}
}
}
override fun onCreateWindow(view: WebView, isDialog: Boolean, isUserGesture: Boolean, resultMsg: Message): Boolean {
subBaseView.isVisible = true
// subBaseView.removeAllViews() // 이러면 쌓이지 않음
val subWebView = BaseWebView(mContext).apply {
webChromeClient = this@MyWebChromeClient
webViewClient = WebViewClient() // 디폴트값 shouldOverrideUrlLoading = false
layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
// 새 창이 쌓일 때마다 margin 값을 늘려서 쌓이는 것을 잘 보이게 만듦
updateLayoutParams<ViewGroup.MarginLayoutParams> {
setMargins(counter, counter, counter, counter)
}
}
// WebViewTransport 설정 안 하면 새 창 처리 안 됨
val transport = resultMsg.obj as WebView.WebViewTransport
transport.webView = subWebView
resultMsg.sendToTarget()
subBaseView.addView(subWebView)
counter += 10
return true
}
override fun onCloseWindow(window: WebView) {
super.onCloseWindow(window)
}
override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult): Boolean {
return jsAlert(message, result)
}
override fun onJsConfirm(view: WebView, url: String, message: String, result: JsResult): Boolean {
return jsAlert(message, result)
}
private fun jsAlert(message: String, result: JsResult, hasNegativeBtn: Boolean = false): Boolean {
AlertDialog.Builder(mContext).apply {
setMessage(message)
setCancelable(false)
setPositiveButton(android.R.string.ok) { _, _ -> result.confirm() }
}.create().show()
return true
}
}
웹페이지에서 revealed(); 자바스크립트 함수를 호출하면 간단한 alert 창이 뜬다.
위처럼 구현하면 아래처럼 동작한다.
웹페이지를 이동하면서 새 창을 쌓다가 -> 안드로이드 백키를 눌러서 새 창을 하나씩 remove할 때마다 웹페이지의 revealed(); 함수 호출.
setSupportMultipleWindows 값을 false로 설정하면, window.open()으로 이동시켜도 WebChromeClient를 타지 않는다.
728x90
'TIL - 안드로이드' 카테고리의 다른 글
[안드로이드] 검색어 자동완성 커스텀 뷰 만들기 Custom Auto Complete View (0) | 2024.03.28 |
---|---|
[안드로이드] 모서리가 둥근 뷰파인더 만들기 rounded square transparent mask for zxing barcode reader UI (0) | 2023.12.14 |
[안드로이드] Retrofit 대신 Ktor로 Api 호출해보기 - 2 (0) | 2023.12.11 |
[안드로이드] Retrofit 대신 Ktor로 Api 호출해보기 - 1 (0) | 2023.12.11 |
[안드로이드] TextView 원하는 글자만 남기고 말줄임표 보여주기 Custom Ellipsis (1) | 2023.12.07 |