관리 메뉴

나만을 위한 블로그

[Android] 웹뷰에서 인텐트 호출 시 net::ERR_UNKNOWN_URL_SCHEME 에러 해결 본문

Android

[Android] 웹뷰에서 인텐트 호출 시 net::ERR_UNKNOWN_URL_SCHEME 에러 해결

참깨빵위에참깨빵 2023. 8. 29. 21:42
728x90
반응형

웹뷰를 사용하다 보면 인텐트 스킴(scheme)을 써서 다른 앱을 실행해야 하는 경우가 있다.

그러다 매니페스트 또는 앱에 정의되지 않은 스킴이나 잘못된 스킴을 호출하면 웹뷰가 해당 스킴을 인식하지 못해 아래 화면이 표시된다.

 

 

이 에러가 발생할 경우 shouldOverrideUrlLoading()으로 받는 URL을 로그로 확인해 보면 "intent://"로 시작한다.

 

왜 이런 에러가 발생하는 건가? 그 이유는 안드로이드 4.4부터 웹뷰가 Chromium 기반으로 바뀌었는데, 이 과정에서 IntentURI를 지원하지 않게 되었다. 때문에 안드로이드 개발자가 URL을 처리하는 로직을 직접 구현해야 한다.

대신 아래 로직만 추가하면 웹뷰에서 결제 시 V3 백신 앱을 실행하거나 V3 앱이 설치돼 있지 않으면 스토어로 이동하기, 또는 다른 외부 앱 다운로드를 위한 스토어 이동이나 외부 앱 실행이 모두 가능해진다.

아래 코드는 스토어 이동을 하지 않는 코드다. 스토어 이동도 해야 한다면 더 밑의 코드를 참고한다.

 

webView.webViewClient = object : WebViewClient() {
    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        url?.let {
            if (it.startsWith("intent://")) {
                try {
                    val intent = Intent.parseUri(it, Intent.URI_INTENT_SCHEME)
                    intent?.let {
                        view?.context?.startActivity(it)
                        return true
                    }
                } catch (e: URISyntaxException) {
                    // 오류 처리
                }
            }
        }
        return super.shouldOverrideUrlLoading(view, url)
    }
}

 

웹뷰로부터 전달받은 URL을 null 체크한 다음 "intent://"로 시작하는지 검사한다. "intent://"로 시작한다면 parseUri()를 써서 앱에서 받은 인텐트 스킴을 바탕으로 인텐트 객체를 생성한다. 이후 웹뷰의 컨텍스트를 가져와서 startActivity()로 인텐트를 실행한다.

이 코드에서 눈여겨봐야 할 곳은 두 곳이다.

 

  • parseUri() : 문자열 형태의 URI를 인텐트 객체로 변환하는 함수
  • Intent.URI_INTENT_SCHEME : URI 형식을 지정하는 플래그. 이걸 써야 "intent://"로 시작하는 인텐트 스킴 URI를 받아서 인텐트 객체로 만들 수 있다

 

마지막 리턴문에선 필요하다면 true 또는 false를 사용할 수도 있다.

 

  • true 리턴 : 해당 URL 로딩 중지. 외부 브라우저 or 외부 앱으로 보내야 할 경우 true를 리턴시킨다
  • false 리턴 : 계속해서 해당 URL 로딩. 현재 보고 있는 웹뷰에서 후속 페이지를 불러오게 해야 할 경우 false를 리턴시킨다
  • super.shouldOverrideUrlLoading() 리턴 : super를 썼기 때문에 상위 클래스의 shouldOverrideUrlLoading()의 구현을 호출한다. 상위 클래스의 구현은 기본적으로 false를 리턴하기 때문에 false를 리턴하는 것과 같은 효과를 낸다.

 

각자 프로젝트의 성격에 맞춰 적절한 값을 리턴시키면 완료된다. 만약 스토어로 이동시키는 로직도 같이 사용해야 한다면 아래 코드를 사용하면 된다.

 

webView.webViewClient = object : WebViewClient() {
    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        url?.let {
            if (it.startsWith("intent://")) {
                try {
                    val intent = Intent.parseUri(it, Intent.URI_INTENT_SCHEME)
                    view?.context?.startActivity(intent)
                    return true
                } catch (e: URISyntaxException) {
                    // URI 구문 오류 처리
                } catch (e: ActivityNotFoundException) {
                    // 앱이 설치돼 있지 않으면 스토어 이동
                    val packageName = intent.getPackage()
                    if (packageName != null) {
                        view?.context?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$packageName")))
                        return true
                    }
                }
            }
        }
        return super.shouldOverrideUrlLoading(view, url)
    }
}

 

코드 형태를 보면 알겠지만 예시 코드기 때문에 실제로 사용하려면 충분한 리팩토링이 필요하다.

만약 결제 프로세스가 웹뷰를 통해 진행된다면 아래 링크를 참고해서 매니페스트에 필요한 카드앱, 은행앱 스킴들을 등록했는지 한 번 확인하는 것도 좋다.

 

https://docs.tosspayments.com/guides/webview

 

웹뷰(WebView) 연동하기 | 토스페이먼츠 개발자센터

브라우저가 아닌 모바일 웹뷰로 결제창을 띄울 때 카드사별 결제수단을 인증하려면 외부 앱(3rd-party 앱)을 연동해야 합니다. 연동에 필요한 외부 앱 스킴(App URL Scheme)목록과 추가 로직을 살펴보

docs.tosspayments.com

 

참고한 사이트)

 

https://medium.com/@bootpay.co.kr/android-webview-err-unknown-url-scheme-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC-84c9c3e69967

 

Android Webview err-unknown-url-scheme 에러 처리

문제 현상

medium.com

 

반응형
Comments