이슈 배경

간편로그인 탑재 중 네이버 앱이 깔려있음에도 앱을 찾지 못하고 앱 내부에서 SafariViewController로만 간편 로그인이 동작하는 이슈를 파악하다가 알게되었습니다.

Queried URL Schemes가 50개의 한도를 가진다면 기존 51번 이후의 스킴은 작동하지 않는 것인지에 대한 파악이 필요해 조사하여 문서를 작성하게 되었습니다.

해당 서비스에는 Queried URL Schemes에 70여개의 스킴이 등록되어 있었으며 이 중 12~70까지는 결제 관련 스킴이었습니다.

네이버 로그인

공식 문서에 따르면 iOS 9 이후에 canOpenURL은 앱이 설치되어 있더라도 Queried URL Schemes(LSApplicationQueriesSchemes)에 정의된 50개 이내의 스킴에 대해서만 true를 return해 줍니다.

canOpenURL에서 해당 URL을 열 수 있는지 확인하고 true가 return되면 open(_: options: completionHandler:) 에서 동일 URL을 열 수 있음을 보장받을 수 있습니다.

네이버 로그인의 경우 싱글톤으로 구현된 네이버 로그인 인스턴스와 메서드로 로그인을 사용하도록 되어 있습니다.

네이버 로그인 API가 오래되었고 공식 문서도 ObjC로 작성된 점을 감안하여 볼 때 네이버 로그인 API에서 네이버 앱 설치 여부를 canOpenURL로 확인하는 것으로 예상해 볼 수 있습니다.

대안

1. Queried URL Schemes를 두 개로 나누기

info.plist가 리스트의 형태일 때는 “The key you entered ("Queried URL Schemes") is already present in the dictionary.  Do you want to replace the existing key/value pair?” 팝업이 노출되며 같은 항목을 두 개 추가할 수 없다는 안내를 확인할 수 있습니다.

Source Code의 형태로 변환해서 Queried URL Schemes(LSApplicationQueriesSchemes)를 추가한다면 두 Queried URL Schemes(LSApplicationQueriesSchemes)중 한 가지만 인식됩니다.

따라서 두 개로 나누는 방법으로 이슈를 해결할 수 없었습니다.

2. canOpenURL 없이 앱 오픈 시도

언파의 Queried URL Schems상 51에서 70번째에 작성된 결제사들도 앱이 잘 실행되고 있었던 이유는 앱 오픈시 canOpenURL을 사용하고 있지 않았기 때문입니다.

결제창에서 카드사 앱 오픈하기를 클릭시 CashDealWebViewController의 아래 함수에서 URL 변경이 감지되고 함수 내부에서 open(_: options: completionHandler:)을 바로 호출하며 앱을 열 수 없을 경우 토스트를 보여주도록 동작하고 있습니다.

**func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)** {
    guard let url = navigationAction.request.url else {
        decisionHandler(.allow) // URL이 없는 경우, 탐색 허용
        return
    }
    let urlString = url.absoluteString

    if urlString.hasPrefix("http://") || urlString.hasPrefix("https://") {
        decisionHandler(.allow)
    } else if url.scheme == "cwapp" {
        DeepLinkManager.openSchemeURL(urlstring: urlString)
        decisionHandler(.cancel) // 해당 URL에 대한 웹뷰 탐색 취소
    } else {
        decisionHandler(.cancel)
        **UIApplication.shared.open(url, options: [:], completionHandler: {
            if !$0 {
                self.view.makeToast("앱이 설치되어 있지 않거나 앱을 불러올 수 없습니다.")
                Log.e("Error in handling Default Scheme")
            }
        })**
    }
}

3. 그 외의 해결 방안