How do I integrate payments in a mobile app?
How to integrate payments in a mobile app using WebView
"I tapped Pay — nothing happened."
It's one of the most common pain points when integrating a PG into a mobile app.
"I tapped the ISP payment button and nothing happens." "Tapping KakaoPay doesn't open the app."
Payments that work fine in a desktop browser and mobile Chrome break silently inside an in-app WebView. The code is identical — so why does WebView behave differently?
The culprit is how App Schemes are handled.
This article covers why payments break in WebView and exactly what you need to fix it.
What is an App Scheme?
http:// and https:// tell the browser to open a web page. Addresses like ispmobile:// or kakaotalk:// mean something different: "launch this specific app." These are called App Schemes.
- Mobile browsers (Chrome, Safari): When they encounter
ispmobile://, they automatically recognize it as an app launch instruction and open the corresponding app. - WebView: By default, it only knows how to handle
httpandhttps. When it sees an unfamiliar scheme likeispmobile://, it throws an error and ignores it.
You need to explicitly tell WebView how to handle these URLs.
Android Setup
On Android, you need to configure app query permissions, URL handling, and core WebView settings together.
1. Permissions (AndroidManifest.xml)
Starting with Android 11 (API 30), if your app needs to launch other apps (card issuer apps, etc.), you must declare them upfront. Register the package names for apps your payment flow will call inside the <queries> tag. Refer to the App Scheme list at the bottom of this article for the package names you need.
<!-- AndroidManifest.xml -->
<manifest ...>
<queries>
<!-- KakaoTalk -->
<package android:name="com.kakao.talk" />
<!-- ISP/PayBook -->
<package android:name="kvp.jjy.MispAndroid320" />
<!-- Add package names for the card issuers / banks your integration uses -->
</queries>
</manifest>
2. Implementation (WebViewClient)
Override shouldOverrideUrlLoading to intercept non-http/https URLs and launch the corresponding app via Intent. If you already have a WebViewClient, merge this logic into your existing shouldOverrideUrlLoading implementation rather than setting a new one.
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;
// Add external app launch URL handling to your WebViewClient.
webView.setWebViewClient(new WebViewClient() {
// URL handling method called on Android N (API 24) and above.
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();
return handlePaymentUrl(view, url);
}
// Implement this as well if you need to support devices below 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;
}
// Return false for http, https, and javascript URLs so WebView handles them normally.
if (URLUtil.isNetworkUrl(url) || URLUtil.isJavaScriptUrl(url)) {
return false;
}
final Uri uri;
try {
uri = Uri.parse(url);
} catch (Exception e) {
return false;
}
// Parse and launch intent:// URLs according to the Android Intent URI spec.
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) {
// If the intent URL includes a package and the app isn't installed, redirect to the Play Store.
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;
}
}
// Forward standard App Scheme URLs (ispmobile://, kftc-bankpay://, etc.) to the appropriate app.
try {
Intent schemeIntent = new Intent(Intent.ACTION_VIEW, uri);
view.getContext().startActivity(schemeIntent);
return true;
} catch (Exception e) {
// The app is not installed or no Activity can handle this URL.
// If you need to redirect to the Play Store, use the Package Name from the App Scheme list below.
return false;
}
}
});
Caution
3. Core WebView Settings
Payment windows frequently rely on JavaScript, local storage, and cookies. Verify these WebView settings before loading the payment window.
import android.os.Build;
import android.webkit.CookieManager;
import android.webkit.WebSettings;
WebSettings settings = webView.getSettings();
// Allow JavaScript so payment window scripts can execute.
settings.setJavaScriptEnabled(true);
// Enable DOM Storage so the payment window can use Local Storage.
settings.setDomStorageEnabled(true);
// Use the default cache policy.
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Allow mixed content in case the payment/authentication flow loads http resources.
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
// Allow cookies needed during the payment authentication flow.
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.setAcceptThirdPartyCookies(webView, true);
}
If the payment window uses alert or confirm, configure WebChromeClient so your app can display those dialogs natively. If you already have a WebChromeClient, merge the following logic into your existing implementation.
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
webView.setWebChromeClient(new WebChromeClient() {
// Display JavaScript alert() calls as a native dialog.
@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;
}
// Pass the user's confirm/cancel choice back to the payment window for JavaScript confirm() calls.
@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 Setup
iOS follows the same pattern: register an allowlist, implement the delegate callback, and verify your cookie policy.
1. Allowlist (Info.plist)
Register every app scheme you need to open in the LSApplicationQueriesSchemes key. App scheme lists can change as card issuers and payment apps update their policies, so cross-reference the list at the bottom of this article.
<!-- Info.plist -->
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kakaotalk</string> <!-- KakaoTalk -->
<string>ispmobile</string> <!-- ISP -->
<string>kb-acp</string> <!-- KB Kookmin Card -->
<!-- Add other card issuer schemes -->
</array>
Caution
2. Implementation (WKNavigationDelegate)
Intercept non-http/https schemes in decidePolicyFor and route them to the appropriate app.
// ViewController.swift
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
// Non-http/https URLs are app schemes
if url.scheme != "http" && url.scheme != "https" {
// Check if the app is installed and open it
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
decisionHandler(.cancel) // Cancel WebView navigation
return
}
}
}
decisionHandler(.allow) // Allow normal web page navigation
}
3. Cookie Policy
On iOS 6 and later, Safari's cookie settings can cause session errors during payment authentication. Set your app to always accept cookies at launch if needed.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[NSHTTPCookieStorage sharedHTTPCookieStorage]
setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
return YES;
}
App Scheme Reference
Common schemes for financial and payment apps. Use this list when registering entries in LSApplicationQueriesSchemes (iOS Info.plist) and <queries> (Android AndroidManifest.xml). Package Names are used on Android when redirecting to the Play Store for uninstalled apps.
AOS AppScheme
| App | Scheme | Package Name |
|---|---|---|
| ISP Mobile | ispmobile | kvp.jjy.MispAndroid320 |
| KB APP Card | kb-acp | com.kbcard.cxh.appcard |
| KB Star Banking | kbbank | com.kbstar.kbbank |
| L.POINT | com.lottemembers.android | |
| L.pay | lpayapp | com.lotte.lpay |
| LG Pay | callonlinepay | com.lge.lgpay |
| LiiV (KB Kookmin Bank) | liivbank | com.kbstar.liivbank |
| NH APP Card | nhappcardansimclick | nh.smart.mobilecard |
| NH All One Pay | nhallonepayansimclick | nh.smart.nhallonepay |
| PAYCO | payco | com.nhnent.payapp |
| SSGPAY | com.ssg.serviceapp.android.egiftcertificate | |
| V3 | ahnlabv3mobileplus | com.ahnlab.v3mobileplus |
| VG Web Vaccine | kr.co.shiftworks.vguardweb | |
| mVaccine | mvaccinestart | com.TouchEn.mVaccine.webs |
| Bank Transfer | kftc-bankpay | com.kftc.bankpay.android |
| Naver Pay | com.nhn.android.search | |
| Lotte APP Card | lotteappcard | com.lcacApp |
| Lotte Smart Pay | lottesmartpay | com.lotte.lottesmartpay |
| Liiv Next | newliiv | com.kbstar.reboot |
| Samsung APP Card | mpocket.online.ansimclick | kr.co.samsungcard.mpocket |
| Samsung Pay | samsungpay | com.samsung.android.spay |
| Samsung Pay (Mini) | com.samsung.android.spaylite | |
| Monimo Pay | net.ib.android.smcard | |
| Shinhan PayFan (Certificate) | com.shinhancard.smartshinhan | |
| Shinhan SOL Bank | com.shinhan.sbanking | |
| Shinhan APP Card | shinhan-sr-ansimclick | com.shcard.smartpay |
| Shinhan Super SOL | com.shinhan.smartcaremgr | |
| Shinhan Card Travel Wallet | com.mobiletoong.travelwallet | |
| Citi (Certificate / Simple Pay) | smartpay | kr.co.citibank.citimobile |
| Citi Mobile App | citimobile | kr.co.citibank.citimobile |
| Citi App Certificate | citicardapp | com.citibank.cardapp |
| Citi App Simple Pay | citispay | com.citibank.cardapp |
| Woori WON Banking | wooribank | com.wooribank.smart.npib |
| Woori WON Card | com.wooricard.smartapp | com.wooricard.smartapp |
| Woori App Card | wooripay | com.wooricard.wpay |
| KakaoPay | com.kakao.talk | |
| Kona Gimpo Pay | gov.gimpo.gpay | |
| Toss | supertoss | viva.republica.toss |
| T-money Damdam | com.tmoney.nfc_pay | |
| T-money In-App | com.tmoney.inapp | |
| PayPin | paypin | com.skp.android.paypin |
| Hana (MobiPay) | cloudpay | com.hanaskcard.paycla |
| Hana Card | com.hanaskcard.rocomo.potal | |
| Hana Members | kr.co.hanamembers.hmscustomer | |
| Hana Members Wallet | hanawalletmembers | com.hanaskcard.paycla |
| Hyundai APP Card | hdcardappcardansimclick | com.hyundaicard.appcard |
| Hyundai Card (Certificate) | com.lumensoft.touchenappfree | |
| Pay Now | com.lguplus.paynow | |
| Kakao Bank | kakaobank | com.kakaobank.channel |
iOS AppScheme
| App | Scheme |
|---|---|
| ISP Mobile | ispmobile |
| KB APP Card | kb-acp |
| LiiV (KB Kookmin Bank) | liivbank |
| Liiv Next | newliiv |
| KB Star Banking | kbbank |
| Lotte APP Card | lotteappcard |
| Lotte Smart Pay | lottesmartpay |
| Monimo Pay | monimopay |
| Monimo Pay Auth | monimopayauth |
| Hyundai APP Card | hdcardappcardansimclick |
| Hyundai Certificate App | smhyundaiansimclick |
| Samsung APP Card | mpocket.online.ansimclick |
| Samsung Card AnsimClick | ansimclickscard |
| ISP Collection | ansimclickipcollect |
| V-Guard | vguardstart |
| Samsung Pay | samsungpay |
| Samsung Certificate App | scardcertiapp |
| Shinhan APP Card | shinhan-sr-ansimclick |
| Shinhan Certificate App | smshinhanansimclick |
| NH APP Card | nhappcardansimclick |
| NH All One Pay | nhallonepayansimclick |
| NH Certificate App | nonghyupcardansimclick |
| Hana (MobiPay) | cloudpay |
| Citi APP Card | citispay |
| Citi Certificate App | citicardappkr |
| Citi Certificate / Simple Pay (New) | citimobileapp |
| mVaccine | NA |
| Bank Transfer | kftc-bankpay |
| KB Bank Transfer | kb-bankpay |
| PayPin | paypin |
| PAYCO | payco, paycoapplogin (both required) |
| Syrup APP Card | tswansimclick |
| Bank Wallet | bankwallet |
| UnionPay | uppay |
| Hana Card | hanaskcardmobileportal |
| LG Pay | Callonlinepay |
| L.pay | lpayapp |
| L.pay LMS | lmslpay |
| Woori App Card | wooripay |
| Hana Members Wallet | hanawalletmembers |
| Woori WON Card | com.wooricard.wcard |
| Hana Moa Sign | hanamopmoasign |
| Woori WON Banking | newsmartpib |
| Liiv (KB Kookmin Bank) | liivbank |
| Shinsegae Easy Pay | shinsegaeeasypayment |
| T Authentication | tauthlink |
| KT Authentication | ktauthexternalcall |
| U+ Authentication | upluscorporation |
| KakaoTalk | kakaotalk |
| Naver Pay | naversearchthirdlogin |
| Toss | supertoss |
| Kakao Bank | kakaobank |
Three things to get right for WebView payments
WebView isn't as smart as a browser — you have to spell everything out.
- Android: Register packages in
AndroidManifest.xml+ implementshouldOverrideUrlLoading - iOS: Register schemes in
Info.plist+ implementdecidePolicyFor - Both: Know the Scheme and Package Name for every card issuer and bank your integration needs, and register them upfront
Get these three right, and your WebView payment experience will be just as smooth as the browser.
For questions during integration, contact our technical support team at .
Need technical support?
Code Samples
HectoFinancial GitHub