프롤로그
-
여러가지 안드로이드 프로젝트를 진행하다가 결국 마주하게 되었다.. WebView에 대한 문제를… 발단은 평소 문제없이 진행되던 메드나 서비스의 PASS앱을 통한 사용자 인증 절차 가 웹뷰 내부에서 intent:// 로 시작하는 url로 redirect 될 시 먹통이 되었다.
-
평소 웹뷰라는 뷰에 대한 학습을 소홀이 했던 것을 후회하며 천천히 문제점을 찾아 본 결과, ShouldOverrideUrlLoading 함수에서, 웹뷰 내에서 처리되는 url에 대한 예외처리를 해 주지 않아서 발생한 오류였다.
ShouldOverrideUrlLoading
- 쉽게 말해서 현재 내가 사용하고 있는 웹뷰 내에서 다른 url을 호출하며 돌아다닐 때 제어권(?)을 요청하는 함수이다. 처음 액티비티에 로드 될 때는 문제가 없지만 웹뷰 상에서 페이지 이동이 일어날 경우 디바이스 브라우저로 실행되거나 나처럼 특정 앱의 스키마를 사용해야하는 경우는 페이지를 로드할 수 없다는 에러를 뱉게될 수 있다.
- 기존에 사용되고 있었던 ShouldOverrideUrlLoading 은 deprecated 되었다. 하지만 업데이트 된 새로운 함수를 찾아보니 기존 함수와 동일한 이름의 함수였고, 차이점이라 하면 매개변수로 받고있는 String 형식의 url이 WebResourceRequest 형식의 request 로 바뀌었다는 점이다. 기존에 매개변수의 url을 직접 사용했던 부분은 request.url 을 통해서 가져올 수 있다.
문제가 됐던 기존 형식
- 문제가 되었던 기존 코드의 형태이다. 보이는 것과 같이 shouldOverrideUrlLoading 함수 내에서 request.url 로 url을 호출하고 있지만 해당 url에 대한 예외처리 등을 처리해주는 부분이 없던 것이다.
- PASS 앱을 통한 사용자 인증 절차가 수행되는 url의 형식은 intent:// 로 시작된다. 웹뷰 내에서 또 다른 앱을 불러오는 형식이다. http, https 형식이라면 새로운 브라우저 창을 실행시키던가 해서 어떻게든 실행이 되겠지만 전화 기능과 연결시키는 tel:, 또는 mailTo:, sms: 와 같이 새로운 앱 또는 기능을 띄워주는 형식은 shouldOverrideUrlLoading 에서 각각의 url에 대한 처리를 진행 해 주어야 한다.
intent://의 행동 처리
- 다음과 같이 intent:// 로 시작하는 url에 대한 예외 처리를 진행 해 주었고 설치되어있지 않을 시 package name 을 추출하여 market으로 이동하는 로직을 구현 해 주었다.
override fun shouldOverrideUrlLoading(
view: WebView,
request: WebResourceRequest?
): Boolean {
val url: String = request?.url.toString()
if (url.startsWith("intent://")) {
var intent: Intent? = null
return try {
intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME)
val uri = Uri.parse(intent.dataString)
startActivity(Intent(Intent.ACTION_VIEW, uri))
true
} catch (ex: URISyntaxException) {
false
} catch (e: ActivityNotFoundException) {
if (intent == null) return false
val packageName = intent.getPackage()
if (packageName != null) {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("market://details?id=$packageName")
)
)
return true
}
false
}
}
view.loadUrl(url)
return false
}