ComposeのWebViewでBasic認証を行いWebアプリを表示する(Android)
作ったWebアプリのデモを見せる機会があり、ネイティブアプリにしたときに、どのような感じなのか聞かれたら、見せられるようにしたいなと思いました。手っ取り早くBasic認証がかかったWebアプリをネイティブアプリとして動かしたいと思って、WebViewで出来ないかなと思いました。
そのときに、Basic認証でいくつか躓いたので、躓いたポイントと、その解決策を共有したいと思います。
ポイントは以下の2点です。
- アクセス先のウェブページへのBasic認証
- アクセスしたウェブページで読み込むリソース(画像など)の認証
やりたいこと
Basic認証でロックが掛かっているWebアプリをWebViewで表示、操作できるようにしたい。
Webアプリで読み込むリソース(画像など)にもBasic認証がかかっている。
WebViewの導入方法は、katzさんの記事[1]を参考にしました。
onReceivedHttpAuthRequest
をOverrideする方法
この記事を書いた当初は出来なかったのですが、ちょっと頑張れば出来ました。参考にしたのはstackoverflowの記事[2]です。
コードを示します。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent{ MyWebClient(url = "https://hogehoge.hoge")}
}
}
//https://developer.android.com/guide/webapps/webview?hl=ja
@SuppressLint("SetJavaScriptEnabled")
@Composable
fun MyWebClient(url: String) {
AndroidView(factory = ::WebView,
update = { webView ->
webView.webViewClient = MyWebViewClient()
webView.settings.javaScriptEnabled = true
webView.loadUrl(url)
})
}
// WebViewClientを継承してonReceivedHttpAuthRequestをOverrideする。
private class MyWebViewClient: WebViewClient() {
@Override
override fun onReceivedHttpAuthRequest(
view: WebView?,
handler: HttpAuthHandler?,
host: String?,
realm: String?
) {
if (handler != null) {
handler.proceed("Basic認証のユーザー名", "Basic認証のパスワード")
}
}
}
実行結果は、同様ですが以下のようになります。
アクセス先のウェブページのBasic認証
まずは、アクセス先のウェブページのBasic認証を実現します。
ネットで調べると、onReceivedHttpAuthRequest
を使用する方法[2:1]が見つかりましたが、うまく実装できませんでした。そこで、stackoverflowの記事[3]を参考に、WebViewのloadUrl
にヘッダー情報でAuthentication
の情報を入れることにしました。
入れ方は、loadUrl
の第2引数にヘッダー情報を入れます。
入れる認証情報は、ID:password
をBase64へエンコードした文字列です。例えば「ID:password」をBase64へエンコードすると「SUQ6cGFzc3dvcmQ=」になります。これを、mapOf
を使って、ヘッダー情報としてloadUrl
の第2引数へ入れます。例えばこんな感じです。
webView.loadUrl(url, mapOf("Authorization" to "Basic SUQ6cGFzc3dvcmQ="))
これを使って、コードを書くと、以下のようになります。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent{ MyWebClient(url = "https://hogehoge.hoge")}
}
}
@SuppressLint("SetJavaScriptEnabled")
@Composable
fun MyWebClient(url: String) {
AndroidView(factory = ::WebView,
update = { webView ->
webView.webViewClient = WebViewClient()
webView.settings.javaScriptEnabled = true
webView.loadUrl(url, mapOf("Authorization" to "Basic {Base64でエンコードしたID:password}"))
})
}
これを実行すると、以下のような実行結果になります。
このように、画像が読み込めていません。原因は、画像にもBasic認証でロックが掛かっているにもかかわらず、認証情報が画像の読み込み時に反映されていないことです。
アクセスしたウェブページで読み込むリソース(画像など)の認証
これを実現するのに、とても苦労しました。
やり方は、以下のようにWebViewのキャッシュの設定を書き加えることです。
これは、キャッシュを保存しない方法を書いた記事[4]を参考にしました。
webView.settings.cacheMode = WebSettings.LOAD_CACHE_ONLY
これを追加したコードが以下です。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent{ MyWebClient(url = "https://hogehoge.hoge")}
}
}
@SuppressLint("SetJavaScriptEnabled")
@Composable
fun MyWebClient(url: String) {
AndroidView(factory = ::WebView,
update = { webView ->
webView.webViewClient = WebViewClient()
webView.settings.javaScriptEnabled = true
webView.settings.cacheMode = WebSettings.LOAD_CACHE_ONLY
webView.loadUrl(url, mapOf("Authorization" to "Basic {Base64でエンコードしたID:password}"))
})
}
これを実行すると、以下のような実行結果になります。
ちょっと、コンテンツは見せられないので、ぼかしになりますが、画像も読み込まれています。
-
Jetpack Compose の AndroidView で WebView を利用する / katz https://zenn.dev/kaleidot725/articles/2021-11-13-jc-webview-detaiils (2022-06-05閲覧) ↩︎
-
Using WebView setHttpAuthUsernamePassword? / dparnas https://stackoverflow.com/questions/2585055/using-webview-sethttpauthusernamepassword (2022-06-05閲覧) ↩︎ ↩︎
-
Android WebView - JWT Authentication / Stonz2 [https://stackoverflow.com/questions/48588918/android-webview-jwt-authentication] (2022-06-05閲覧) ↩︎
-
【Android】WebView にキャッシュをさせない方法 / awacleberry https://awacleberry.hatenablog.com/entry/2017/06/28/223524 (2022-06-05閲覧) ↩︎
Discussion