Help us understand the problem. What is going on with this article?

Android WebView から別アプリを開く

AndroidのWebViewではtelmailtoなどのリンクを踏んでも電話アプリやメールアプリが起動しないためそれに対応するための実装が必要です。

また暗黙的Intentに対応する場合も、そのための実装が必要です。

これらの実装方法を紹介します。

URL判定処理

URLからIntentを作成します。

class WebViewRequestValidation {
    fun isTransitionToOtherApp(url: Uri): TransitionToOtherApp {
        return when (url.scheme) {
            "tel" -> TransitionToOtherApp.Yes(Intent(Intent.ACTION_DIAL, url))
            "mailto" -> TransitionToOtherApp.Yes(Intent(Intent.ACTION_SENDTO, url))
            "intent" -> TransitionToOtherApp.Yes(Intent.parseUri(url.toString(), Intent.URI_INTENT_SCHEME))
            else -> TransitionToOtherApp.No()
        }
    }
    sealed class TransitionToOtherApp {
        class Yes(val intent: Intent):TransitionToOtherApp()
        class No():TransitionToOtherApp()
    }
}

Intent起動処理

上記で作成したIntentを起動します。処理の流れは以下の通りです。

  • 対象Activityが存在すれば、startActivityを実行する。
    • 存在しないActivityをstartActivityしてしまうと、アプリがクラッシュします。
  • intentからbrowser_fallback_urlが取得できれば、そのURLを表示する。
  • GooglePlayStoreアプリがアクティブであれば(存在すれば)、GooglePlayStoreアプリを起動する。
  • 上記全てがヒットしない場合、https://play.google.com/store/apps/details?id=$applicationIdを表示する。

最後のhttps://play.google.com/store/apps/details?id=$applicationIdは、表示してもアプリをダウンロードできないので、なにかユーザにメッセージを表示するほうが適切かもしれません。

class ImplicitIntentStarter(private val wContext: WeakReference<Context>) {

    fun startActivity(intent: Intent) {
        val context = wContext.getNullable() ?: return
        val packageManager = context.packageManager

        if (intent.resolveActivity(packageManager) != null) {
            context.startActivity(intent)
            return
        }

        val fallbackUrl = intent.getStringExtra("browser_fallback_url")
        if (fallbackUrl != null) {
            // ブラウザ起動など
            return
        }

        startGooglePlayStoreActivity(intent.`package`)
    }

    fun startGooglePlayStoreActivity(applicationId: String) {
        val context = wContext.getNullable() ?: return
        val packageManager = context.packageManager

        val marketIntent = Intent(Intent.ACTION_VIEW).setData(Uri.parse("market://details?id=$applicationId"))
        if (marketIntent.resolveActivity(packageManager) != null) {
            context.startActivity(marketIntent)
            return
        }
        context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=$applicationId")))
    }
}

// WeakReferenceから取得する値を null safe に扱うための拡張です。
fun <T> WeakReference<T>.getNullable(): T? = get()

WebViewのリクエストをインターセプト

最後に、WebViewのリクエストをインターセプトし、上記の処理を実装します。

    private val validation = WebViewRequestValidation()
    private val implicitIntentStarter = ImplicitIntentStarter(wContext)
    val webViewClient = object : WebViewClient() {
        override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {

            // WebViewの画面遷移をさせたくない場合は true を返す。
            val allowedRequest = false
            val notAllowedRequest = true

            val urlString = url ?: return notAllowedRequest
            val url = Uri.parse(urlString)

            validation.isTransitionToOtherApp(url).let {
                when (it) {
                    is WebViewRequestValidation.TransitionToOtherApp.Yes -> {
                        implicitIntentStarter.startActivity(it.intent)
                        return notAllowedRequest
                    }
                    is WebViewRequestValidation.TransitionToOtherApp.No -> {}
                }
            }

            return allowedRequest

        }
    }

    webView.setWebViewClient(webViewClient)
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away