[iOS] Webview Deep Link/Universal Link

2025. 1. 25. 21:12iOS

반응형

웹뷰로 구현된 결제 페이지에서 카드 결제를 선택한 뒤, 카드 앱으로 이동 후 결제가 완료되었을 때 다시 앱으로 돌아와 결제 완료를 처리하려면, 딥 링크(Deep Link) 또는 Universal Link를 활용하는 방법을 주로 사용합니다. 이와 함께 웹뷰의 네비게이션 동작과 앱 간 호출 흐름을 관리해야 합니다.


구현 단계

1. 카드 결제 연동 흐름

  1. 사용자 → 앱의 웹뷰에서 결제 페이지에 접근.
  2. 사용자 → 카드 결제를 선택하면, 카드사의 앱이 실행됨.
  3. 사용자 → 카드 앱에서 결제 완료 후 앱의 딥 링크/유니버설 링크를 통해 다시 원래 앱으로 복귀.
  4. 앱 → 복귀 시 결제 결과를 확인하여 처리.

2. 카드사 앱 연동 방식

  • 대부분의 카드사 결제 앱은 딥 링크(URL 스키마)를 지원하며, 결제 완료 후 앱으로 돌아올 수 있도록 설정할 수 있습니다.
  • 결제 요청 시 returnUrl 또는 callbackUrl을 설정하여 앱으로 복귀 경로를 지정합니다.

예시


3. 딥 링크 설정 방법

(1) Info.plist 설정

앱에서 특정 URL 스키마를 처리하려면, Info.plist 파일에 아래와 같이 설정합니다:

<key>CFBundleURLTypes</key> 
<array> 
	<dict> 
    	<key>CFBundleURLSchemes</key> 
        <array> 
        	<string>myapp</string> <!-- 딥 링크 스키마 --> 
        </array> 
        <key>CFBundleURLName</key> 
        <string>com.mycompany.myapp</string> 
    </dict> 
</array>

(2) AppDelegate에서 URL 처리

앱으로 돌아왔을 때 AppDelegate 또는 SceneDelegate에서 URL을 처리하여 결제 결과를 확인합니다.

AppDelegate Example:

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { 
	if url.scheme == "myapp", url.host == "payment-complete" { 
    	// URL에서 필요한 정보 추출 
        let queryItems = URLComponents(string: url.absoluteString)?.queryItems 
        let paymentStatus = queryItems?.first(where: { $0.name == "status" })?.value 
        
        if paymentStatus == "success" { 
        	print("결제 성공!") // 결제 성공 처리 (예: 화면 갱신, 서버 API 호출 등) 
        } else { 
        	print("결제 실패") // 결제 실패 처리 
        } 
        return true 
    }
    return false 
}

(3) SceneDelegate에서 URL 처리 (iOS 13+)

iOS 13 이상에서는 SceneDelegate의 scene(_:openURLContexts:)를 사용합니다:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { 
	guard let url = URLContexts.first?.url else { return } 
    
    if url.scheme == "myapp", url.host == "payment-complete" { 
    	// URL에서 정보 추출 및 처리 
        let queryItems = URLComponents(string: url.absoluteString)?.queryItems 
        let paymentStatus = queryItems?.first(where: { $0.name == "status" })?.value 
        
        if paymentStatus == "success" { 
        	print("결제 성공!") // 결제 성공 처리 
        } else { 
        	print("결제 실패") // 결제 실패 처리 
        }
    }
}

4. 웹뷰에서 결제 처리

WKNavigationDelegate로 URL 처리

카드 결제 후, 카드사에서 앱으로 복귀하기 전에 결제 완료를 위한 특정 URL을 처리해야 할 수 있습니다. 이를 위해 WKNavigationDelegate를 활용합니다.

class PaymentViewController: UIViewController, WKNavigationDelegate { 
	var webView: WKWebView! 
    
    override func viewDidLoad() { 
    	super.viewDidLoad() 
        let config = WKWebViewConfiguration() 
        webView = WKWebView(frame: self.view.frame, configuration: config) 
        webView.navigationDelegate = self 
        self.view.addSubview(webView) // 결제 페이지 로드 
        
        if let url = URL(string: "https://payment.gateway.com/initiate") { 
        	webView.load(URLRequest(url: url)) 
        }
    }
    
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { 
    	let url = navigationAction.request.url 
        
        if url?.scheme == "myapp" { 
        	// 앱으로 돌아가기 전 URL 처리 
            if url?.host == "payment-complete" { 
            	print("결제 완료 URL 감지") 
                let queryItems = URLComponents(url: url!, resolvingAgainstBaseURL: false)?.queryItems 
                let status = queryItems?.first(where: { $0.name == "status" })?.value 
                if status == "success" { 
                	print("결제 성공!") // 성공 처리 로직 
                } else { 
                	print("결제 실패") // 실패 처리 로직
                }
            } 
            decisionHandler(.cancel) // URL 열기를 중단하고 앱 내에서 처리 
            return 
        }
        decisionHandler(.allow) // 기타 URL은 정상 처리
    }
}

5. 서버와의 결제 상태 확인 (옵션)

앱이 결제 완료 상태를 신뢰할 수 있도록 서버와 상태를 확인하는 과정을 추가합니다.

  • 카드 앱이 returnUrl로 결제 결과를 전달하면, 앱에서 해당 결과를 서버로 보내고 확인 후 UI를 업데이트합니다.

6. Universal Link 사용

딥 링크 대신 Universal Link를 사용하면 HTTP/HTTPS 기반 URL로 앱을 호출할 수 있습니다. 이 경우:

  1. Associated Domains를 설정 (apple-app-site-association 파일 필요).
  2. 앱 내에서 application(_:continue:restorationHandler:) 또는 scene(_:continue:)를 사용.

결론

위 과정을 통해 웹뷰 기반 결제와 카드 앱 연동을 구현할 수 있습니다. 딥 링크와 Universal Link 설정, 그리고 WKNavigationDelegate와 AppDelegate/SceneDelegate의 URL 처리를 적절히 활용하세요.

반응형