일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 안드로이드 유닛 테스트
- 안드로이드 레트로핏 crud
- 서비스 쓰레드 차이
- Rxjava Observable
- rxjava cold observable
- 큐 자바 코드
- 플러터 설치 2022
- 스택 자바 코드
- 안드로이드 유닛테스트란
- jvm이란
- 멤버변수
- 클래스
- 2022 플러터 설치
- 안드로이드 유닛 테스트 예시
- android retrofit login
- 스택 큐 차이
- android ar 개발
- rxjava disposable
- 안드로이드 라이선스 종류
- 자바 다형성
- rxjava hot observable
- 안드로이드 os 구조
- 2022 플러터 안드로이드 스튜디오
- 안드로이드 라이선스
- ar vr 차이
- ANR이란
- 안드로이드 레트로핏 사용법
- 객체
- 서비스 vs 쓰레드
- jvm 작동 원리
- Today
- Total
나만을 위한 블로그
[Android] 웹뷰에서 인텐트 호출 시 net::ERR_UNKNOWN_URL_SCHEME 에러 해결 본문
웹뷰를 사용하다 보면 인텐트 스킴(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
참고한 사이트)
'Android' 카테고리의 다른 글
[Android] 샌드버드 SDK v4 - 그룹 채널에서 채팅 푸시 알림 받기 (0) | 2023.09.10 |
---|---|
[Android] Android 14 변경사항 미리보기 (0) | 2023.09.04 |
[Android] 라이브러리 없이 권한 요청하는 법 (0) | 2023.08.28 |
[Android] 안드로이드 13에서 Photo Picker 사용하는 법 (0) | 2023.08.27 |
[Android] StateFlow, SharedFlow Best Practices (0) | 2023.08.27 |