Back to blog
기술

모바일 연동은 어떻게 하죠?

모바일 앱(WebView)에서 결제 연동하는 방법

헥토파이낸셜 개발팀
2025-11-21
12분
#WebView#Android#iOS
모바일 연동은 어떻게 하죠? 썸네일 이미지

"결제하기 눌렀는데... 왜 아무 반응이 없죠?"

앱에서 PG 연동을 하다 보면 자주 겪는 문제인데요.

"ISP 결제 버튼을 눌렀는데 아무 일도 안 일어나요." "카카오페이 결제하려는데 앱으로 이동을 안 해요."

PC 브라우저와 모바일 크롬에서는 잘 되던 결제가, 앱 내 웹뷰(WebView) 에서만 먹통이에요. 분명 코드는 똑같은데 왜 웹뷰에서만 이런 문제가 생길까요?

범인은 바로 App Scheme(앱 스킴) 처리 방식의 차이예요.

이번 아티클에서는 웹뷰에서 결제가 안 되는 이유와 해결 방법을 알아볼게요.

'App Scheme' 적용

우리가 흔히 쓰는 http://https://는 웹 페이지를 열라는 약속이에요. 반면 ispmobile://, kakaotalk:// 같은 주소는 "특정 앱을 실행해라"라는 약속이에요. 이걸 App Scheme 이라고 해요.

  • 모바일 브라우저 (Chrome, Safari): ispmobile:// 같은 주소를 만나면 알아서 "어? 이건 앱을 열어야겠네?" 하고 해당 앱을 실행시켜 줘요.
  • 웹뷰 (WebView): 기본적으로 http/https만 처리할 줄 알아요. 낯선 주소(ispmobile://)가 오면 "이게 뭐지? 에러!" 하고 무시해버려요.

그래서 개발자가 "이런 주소가 오면 앱을 열어줘!"라고 웹뷰에게 직접 알려줘야 해요.


Android 설정 방법

안드로이드에서는 앱 호출 권한, URL 처리, WebView 기본 설정을 함께 확인해야 해요.

1. 권한 설정 (AndroidManifest.xml)

Android 11(API 30) 이상부터는 내 앱이 다른 앱(카드사 앱 등)을 실행하려면 "나 이 앱들 부를 거야"라고 미리 선언해야 해요. <queries> 태그에 결제 과정에서 호출할 앱의 패키지를 등록해주세요. 필요한 패키지명은 하단의 주요 앱 스킴 리스트를 참고할 수 있어요.

<!-- AndroidManifest.xml -->
<manifest ...>
    <queries>
        <!-- 카카오톡 -->
        <package android:name="com.kakao.talk" />
        <!-- ISP/페이북 -->
        <package android:name="kvp.jjy.MispAndroid320" />
        <!-- 사용하는 결제수단에 따라 카드사/은행 앱 패키지명 추가 필요 -->
    </queries>
</manifest>

2. 코드 구현 (WebViewClient)

shouldOverrideUrlLoading 메서드를 오버라이딩하여, http/https가 아닌 주소가 들어왔을 때 Intent를 통해 앱을 실행하도록 처리해요. 이미 WebViewClient를 사용 중이라면 중복으로 설정하지 말고, 기존 shouldOverrideUrlLoading 구현부에 외부 앱 호출 URL 처리 로직을 병합하세요.

import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.webkit.URLUtil;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import java.net.URISyntaxException;

// WebViewClient에 외부 앱 호출 URL 처리 로직을 추가합니다.
webView.setWebViewClient(new WebViewClient() {

    // Android N(API 24) 이상에서 호출되는 URL 처리 메서드입니다.
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        String url = request.getUrl().toString();
        return handlePaymentUrl(view, url);
    }

    // Android N(API 24) 미만 단말을 지원하는 경우 함께 구현합니다.
    @SuppressWarnings("deprecation")
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            return handlePaymentUrl(view, url);
        }

        return super.shouldOverrideUrlLoading(view, url);
    }

    private boolean handlePaymentUrl(WebView view, String url) {
        if (TextUtils.isEmpty(url)) {
            return false;
        }

        // http, https, javascript URL은 WebView가 계속 처리하도록 false를 반환합니다.
        if (URLUtil.isNetworkUrl(url) || URLUtil.isJavaScriptUrl(url)) {
            return false;
        }

        final Uri uri;

        try {
            uri = Uri.parse(url);
        } catch (Exception e) {
            return false;
        }

        // intent:// 형태의 URL은 Android Intent URI 규격에 따라 파싱하여 실행합니다.
        if ("intent".equals(uri.getScheme())) {
            final Intent intent;

            try {
                intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
            } catch (URISyntaxException e) {
                return false;
            }

            try {
                view.getContext().startActivity(intent);
                return true;
            } catch (ActivityNotFoundException e) {
                // intent URL에 package 정보가 포함된 경우 앱 미설치 시 마켓으로 이동합니다.
                String packageName = intent.getPackage();

                if (!TextUtils.isEmpty(packageName)) {
                    try {
                        Intent marketIntent = new Intent(
                            Intent.ACTION_VIEW,
                            Uri.parse("market://details?id=" + packageName)
                        );
                        view.getContext().startActivity(marketIntent);
                        return true;
                    } catch (Exception marketException) {
                        return false;
                    }
                }

                return false;
            } catch (Exception e) {
                return false;
            }
        }

        // ispmobile://, kftc-bankpay:// 등 일반 App Scheme URL은 외부 앱으로 전달합니다.
        try {
            Intent schemeIntent = new Intent(Intent.ACTION_VIEW, uri);
            view.getContext().startActivity(schemeIntent);
            return true;
        } catch (Exception e) {
            // 앱이 설치되어 있지 않거나 처리 가능한 Activity가 없는 경우입니다.
            // 마켓 이동이 필요한 경우 하단 App Scheme 리스트의 Package Name을 참고해 처리하세요.
            return false;
        }
    }
});

주의

net::ERR_UNKNOWN_URL_SCHEME 에러가 뜬다면 이 코드가 제대로 동작하지 않고 있는 것이에요.

3. WebView 기본 설정

결제창은 JavaScript, 로컬 저장소, 쿠키를 사용하는 경우가 많아요. 결제창을 로드하기 전에 WebView 설정을 확인해주세요.

import android.os.Build;
import android.webkit.CookieManager;
import android.webkit.WebSettings;

WebSettings settings = webView.getSettings();

// 결제창 스크립트 실행을 위해 JavaScript 사용을 허용합니다.
settings.setJavaScriptEnabled(true);

// 결제창에서 Local Storage를 사용할 수 있도록 DOM Storage를 허용합니다.
settings.setDomStorageEnabled(true);

// 기본 캐시 정책을 사용합니다.
settings.setCacheMode(WebSettings.LOAD_DEFAULT);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    // 결제/인증 과정에서 http 리소스가 포함될 수 있는 경우를 대비합니다.
    settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

    // 결제 인증 흐름에서 필요한 쿠키를 허용합니다.
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.setAcceptCookie(true);
    cookieManager.setAcceptThirdPartyCookies(webView, true);
}

결제창에서 alert 또는 confirm을 사용하는 경우, 앱에서 팝업을 표시할 수 있도록 WebChromeClient도 함께 설정해요. 이미 WebChromeClient를 사용 중이라면 기존 구현에 아래 로직을 병합하세요.

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;

webView.setWebChromeClient(new WebChromeClient() {

    // JavaScript alert 호출 시 앱 네이티브 다이얼로그로 표시합니다.
    @Override
    public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
        new AlertDialog.Builder(view.getContext())
            .setMessage(message)
            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    result.confirm();
                }
            })
            .setCancelable(false)
            .create()
            .show();
        return true;
    }

    // JavaScript confirm 호출 시 확인/취소 선택 결과를 결제창에 전달합니다.
    @Override
    public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
        new AlertDialog.Builder(view.getContext())
            .setMessage(message)
            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    result.confirm();
                }
            })
            .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    result.cancel();
                }
            })
            .create()
            .show();
        return true;
    }
});

iOS 설정 방법

iOS도 비슷해요. 허용 목록을 등록하고, 코드와 쿠키 정책을 함께 확인해야 해요.

1. 허용 목록 등록 (Info.plist)

LSApplicationQueriesSchemes 키에 실행을 허용할 앱 스킴들을 배열로 등록해야 해요. 앱 스킴 목록은 카드사/결제앱 제공 정책에 따라 추가되거나 변경될 수 있으므로, 하단의 주요 앱 스킴 리스트를 함께 확인해주세요.

<!-- Info.plist -->
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>kakaotalk</string> <!-- 카카오톡 -->
    <string>ispmobile</string> <!-- ISP -->
    <string>kb-acp</string>    <!-- KB국민카드 -->
    <!-- 기타 카드사 스킴 추가 -->
</array>

주의

이 목록에 없으면 앱이 설치되어 있어도 canOpenURL이 false를 반환하여 앱을 열 수 없어요.

2. 코드 구현 (WKNavigationDelegate)

decidePolicyFor 메서드에서 http/https가 아닌 스킴을 감지하여 처리해요.

// ViewController.swift
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    if let url = navigationAction.request.url {
        // http, https가 아닌 경우 (앱 스킴)
        if url.scheme != "http" && url.scheme != "https" {
            // 앱 설치 여부 확인 및 실행
            if UIApplication.shared.canOpenURL(url) {
                UIApplication.shared.open(url)
                decisionHandler(.cancel) // 웹뷰 이동 취소
                return
            }
        }
    }
    decisionHandler(.allow) // 일반 웹 페이지는 이동 허용
}

3. 쿠키 허용

iOS 6 이상에서는 Safari 쿠키 설정에 따라 결제 인증 과정에서 세션 관련 오류가 발생할 수 있어요. 필요한 경우 앱 실행 시 쿠키를 항상 허용하도록 설정해요.

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[NSHTTPCookieStorage sharedHTTPCookieStorage]
        setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];

    return YES;
}

주요 앱 스킴(App Scheme) 리스트

자주 사용되는 금융/결제 앱들의 스킴이에요. iOS는 Info.plistLSApplicationQueriesSchemes, Android는 AndroidManifest.xml<queries>에 등록할 때 참고하세요. Android에서 앱 미설치 시 마켓 이동 처리를 추가하는 경우 Package Name을 사용할 수 있어요.

AOS AppScheme

AppSchemePackage Name
ISP모바일ispmobilekvp.jjy.MispAndroid320
KBAPP카드kb-acpcom.kbcard.cxh.appcard
KB스타뱅킹kbbankcom.kbstar.kbbank
L.POINTcom.lottemembers.android
L.paylpayappcom.lotte.lpay
LG페이callonlinepaycom.lge.lgpay
LiiV(국민은행)liivbankcom.kbstar.liivbank
NHAPP카드nhappcardansimclicknh.smart.mobilecard
NH올원페이nhallonepayansimclicknh.smart.nhallonepay
PAYCO간편결제paycocom.nhnent.payapp
SSGPAYcom.ssg.serviceapp.android.egiftcertificate
V3ahnlabv3mobilepluscom.ahnlab.v3mobileplus
VG웹백신kr.co.shiftworks.vguardweb
mVaccinemvaccinestartcom.TouchEn.mVaccine.webs
계좌이체kftc-bankpaycom.kftc.bankpay.android
네이버페이com.nhn.android.search
롯데APP카드lotteappcardcom.lcacApp
롯데모바일결제lottesmartpaycom.lotte.lottesmartpay
리브Nextnewliivcom.kbstar.reboot
삼성APP카드mpocket.online.ansimclickkr.co.samsungcard.mpocket
삼성페이samsungpaycom.samsung.android.spay
삼성페이(미니)com.samsung.android.spaylite
모니모페이net.ib.android.smcard
신한페이판(공동인증서)com.shinhancard.smartshinhan
신한 SOL뱅크com.shinhan.sbanking
신한APP카드shinhan-sr-ansimclickcom.shcard.smartpay
신한 슈퍼 SOLcom.shinhan.smartcaremgr
신한카드 트래블월렛com.mobiletoong.travelwallet
씨티공인인증서/스마트간편결제smartpaykr.co.citibank.citimobile
씨티모바일앱citimobilekr.co.citibank.citimobile
씨티앱공인인증서citicardappcom.citibank.cardapp
씨티앱스마트간편결제citispaycom.citibank.cardapp
우리WON뱅킹wooribankcom.wooribank.smart.npib
우리WON카드com.wooricard.smartappcom.wooricard.smartapp
우리앱카드wooripaycom.wooricard.wpay
카카오페이com.kakao.talk
코나김포페이gov.gimpo.gpay
토스supertossviva.republica.toss
티머니댐댐com.tmoney.nfc_pay
티머니인앱com.tmoney.inapp
페이핀paypincom.skp.android.paypin
하나(모비페이)cloudpaycom.hanaskcard.paycla
하나카드com.hanaskcard.rocomo.potal
하나멤버스kr.co.hanamembers.hmscustomer
하나멤버스월렛hanawalletmemberscom.hanaskcard.paycla
현대APP카드hdcardappcardansimclickcom.hyundaicard.appcard
현대카드(공동인증서)com.lumensoft.touchenappfree
페이나우com.lguplus.paynow
카카오뱅크kakaobankcom.kakaobank.channel

iOS AppScheme

AppScheme
ISP 모바일ispmobile
KB APP 카드kb-acp
LiiV(국민은행)liivbank
리브 Nextnewliiv
KB스타뱅킹kbbank
롯데 APP 카드lotteappcard
롯데 스마트 페이lottesmartpay
모니모페이monimopay
모니모페이 인증monimopayauth
현대 APP 카드hdcardappcardansimclick
현대 공인인증 앱smhyundaiansimclick
삼성APP카드mpocket.online.ansimclick
삼성카드 안심클릭ansimclickscard
ISP 수집ansimclickipcollect
V-Guardvguardstart
삼성페이samsungpay
삼성 공인인증 앱scardcertiapp
신한APP카드shinhan-sr-ansimclick
신한 공인인증 앱smshinhanansimclick
NH APP카드nhappcardansimclick
NH 올원페이nhallonepayansimclick
NH 공인인증 앱nonghyupcardansimclick
하나(모비페이)cloudpay
씨티 APP 카드citispay
씨티 공인인증 앱citicardappkr
씨티공인인증서/스마트간편결제(신규)citimobileapp
mVaccineNA
계좌이체kftc-bankpay
KB 계좌이체kb-bankpay
페이핀paypin
PAYCO 간편결제payco, paycoapplogin (2개 모두)
시럽 APP카드tswansimclick
뱅크월렛bankwallet
은련카드uppay
하나카드hanaskcardmobileportal
LG페이Callonlinepay
L.paylpayapp
L.pay LMSlmslpay
우리앱카드wooripay
하나멤버스월렛hanawalletmembers
우리WON카드com.wooricard.wcard
하나모아사인hanamopmoasign
우리WON뱅킹newsmartpib
Liiv(KB국민은행)liivbank
신세계간편결제shinsegaeeasypayment
T 인증tauthlink
KT 인증ktauthexternalcall
U+ 인증upluscorporation
카카오톡kakaotalk
네이버페이naversearchthirdlogin
토스supertoss
카카오뱅크kakaobank

웹뷰 결제, 세 가지만 챙기세요

웹뷰는 브라우저처럼 똑똑하지 않아요. 하나하나 알려줘야 하죠.

  1. Android: AndroidManifest.xml에 패키지 등록 + shouldOverrideUrlLoading 구현
  2. iOS: Info.plist에 스킴 등록 + decidePolicyFor 구현
  3. 공통: 각 카드사/은행 앱의 SchemePackage Name 을 미리 파악해서 등록해두기

이 세 가지만 기억하면, 웹뷰에서도 매끄러운 결제 경험을 제공할 수 있어요.

연동 중 문의사항은 기술지원팀()으로 연락 주세요.

❓

더 궁금한 내용이 있나요?

FAQ
💬

기술지원이 필요한가요?