⌨️

【Tauri】Androidビルド時にUIがキーボードに隠れる問題

に公開

Webアプリをモバイル対応させる際,ソフトウェアキーボード(IME)の表示によってレイアウトが崩れる問題に直面することがあります.特に,ReactやTauriなどで構築したアプリをAndroid向けにビルドした際に,VisualViewportが思ったように動作しない問題に遭遇しました.

この記事では,その問題と解決策について共有します.

Visual Viewportが変化しない?

ReactなどのWebフロントエンドでは,ソフトウェアキーボードが表示されたときのレイアウト調整に window.visualViewport を使うのが一般的です.

ところが,AndroidにビルドしたTauriアプリでは,IMEが表示されても visualViewport.height が変化せず,UIがキーボードの裏に隠れてしまいました.

試したこと:adjustResizeの追加

調査したところ,同様の問題が GitHub でも報告されていました.

その中では,AndroidManifest.xml に以下のように windowSoftInputMode="adjustResize" を追加することで解決できるという報告もありました.

<application ... >
   <activity
       android:windowSoftInputMode="adjustResize" ... >
       ...
   </activity>
   ...
</application>

しかし,私の環境では この方法ではうまく動作しませんでした

解決した方法:MainActivity.ktでパディングを調整

最終的に効果があったのは,MainActivity.kt にて,IMEの表示に応じて paddingBottom を動的に設定する方法でした.

以下がそのコードです.

src-tauri/gen/android/app/src/main/java/com/[tauri_app]/app/MainActivity.kt
package com.[tauri_app].app

import android.os.Bundle
import androidx.core.view.WindowCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat

class MainActivity : TauriActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    WindowCompat.setDecorFitsSystemWindows(window, false)

    ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { view, insets ->
        val systemBarHeight = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom
        val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom

        view.setPadding(
            view.paddingLeft,
            view.paddingTop,
            view.paddingRight,
            if (imeHeight > 0) imeHeight else systemBarHeight
        )

        insets
    }
  }
}

このコードは,システムバーとIMEのインセットを取得し,IMEが表示されているときはその高さ分だけ下に余白を追加するというものです.

おわり

  • VisualViewport は Android の WebView 上で正しく動作しないことがある
  • adjustResize を指定しても解決しないケースがある
  • Kotlin 側で setOnApplyWindowInsetsListener を使ってパディングを調整することで解決できる

Tauriで,Androidアプリを開発している方の参考になれば幸いです.

Discussion