Jetpack ComposeでWebViewを使いたい場合はaccompanistのWebViewなどを使った方が楽かもしれませんがandroid.webkit.WebViewで実装してみました
accompanistのWebViewは以下を参照
https://google.github.io/accompanist/web/
WebView
とりあえず最低限と思われる実装
android.webkit.WebViewの使い方についての詳細は省きます
onProgressChangeイベントはUIスレッドに返すようにしてます
// AndroidManifestに以下の権限を追加してください
// <uses-permission android:name="android.permission.INTERNET" />
@Composable
fun WebView(
url:String,
modifier: Modifier = Modifier,
onProgressChange: (progress:Int, url: String) -> Unit = { i: Int, s: String -> },
onReceivedError: (error: WebResourceError?) -> Unit = {},
): WebView? {
var progress by remember { mutableStateOf(100) }
val webViewChromeClient = object: WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
// 同じイベントを発生させない
if (newProgress > progress) {
progress = newProgress
CoroutineScope(Dispatchers.Main).launch {
onProgressChange(progress, view?.url.toString())
}
}
}
}
val webViewClient = object: WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
progress = 0
CoroutineScope(Dispatchers.Main).launch {
onProgressChange(progress, url ?: "")
}
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
// 同じイベントを発生させない
if (progress < 100) {
progress = 100
CoroutineScope(Dispatchers.Main).launch {
onProgressChange(progress, url ?: "")
}
}
}
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
if (request?.url == null) return false
val showOverrideUrl = request.url.toString()
try {
if (!showOverrideUrl.startsWith("http://")
&& !showOverrideUrl.startsWith("https://")) {
Intent(Intent.ACTION_VIEW, Uri.parse(showOverrideUrl)).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
view?.context?.applicationContext?.startActivity(this)
}
return true
}
} catch (e:Exception) {
return true
}
return super.shouldOverrideUrlLoading(view, request)
}
override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
super.onReceivedError(view, request, error)
onReceivedError(error)
}
}
var webView by remember { mutableStateOf<WebView?>(null) }
AndroidView(
modifier = modifier,
factory = { context ->
WebView(context).apply {
this.webViewClient = webViewClient
this.webChromeClient = webViewChromeClient
webView = this
loadUrl(url)
}
}
)
return webView
}
<manifest>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
使い方
url入力用のTextFieldの実装もありますが最低限の実装はWebVew([URL])だけで表示されます
var webView: WebView? = null
var text by remember { mutableStateOf("https://google.com") }
val keyboard = LocalSoftwareKeyboardController.current
Column(Modifier.fillMaxSize()) {
TextField(
value = text,
onValueChange = { text = it },
modifier = Modifier.fillMaxWidth(),
singleLine = true,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Go),
keyboardActions = KeyboardActions(onGo = {
keyboard?.hide()
webView?.apply { loadUrl(text) } }
),
leadingIcon = {
IconButton(onClick = {
webView?.apply { if (canGoBack()) goBack() }
}) {
Icon(Icons.Default.ArrowBack, null)
}
},
trailingIcon = {
IconButton(onClick = {
webView?.apply { reload() }
}) {
Icon(Icons.Default.Refresh, null)
}
}
)
webView = WebView(
text,
Modifier.fillMaxSize(),
onProgressChange = { progress, url ->
if (progress == 100 && url.isNotEmpty()) {
text = url
}
},
)
}
Android Studio Giraffe 2022.3.1 built on June 29, 2023