영수증 미리보기

// Android Webview 클래스를 상속받아 가맹점에서 결제를 수행할 WebView 클래스 생성
private class SMPAYViewClient extends WebViewClient {
public final String INTENT_URI_START = "intent";
public final String INTENT_FALLBACK_URL = "browser_fallback_url";
public final String URI_SCHEME_MARKET = "market://details?id=";
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String uri) { // 가맹점에서 구현
Intent parsedIntent = null;
if (uri.toLowerCase().startsWith(INTENT_URI_START)) {
try {
// 실행전에 카드사 URI 체크 필요 (하단의 URI 목록 참고)
parsedIntent = Intent.parseUri(uri, 0);
startActivity(parsedIntent);
} catch(ActivityNotFoundException | URISyntaxException e) {
return doFallback(view, parsedIntent);
}
} else if(uri.startsWith("ispmobile://")) {
// 설치 체크
boolean result = true;
PackageManager pm = getPackageManager();
try {
pm.getPackageInfo("kvp.jjy.MispAndroid320",PackageManager.GET_META_DATA);
} catch(Exception e){
result = false;
}
if(result) {
parsedIntent = new Intent(Intent.ACTION_VIEW,Uri.parse(uri));
startActivity(parsedIntent);
} else {
// market 이동
Uri market = Uri.parse("market://details?id=kvp.jjy.MispAndroid320");
parsedIntent = new Intent(Intent.ACTION_VIEW,market);
startActivity(parsedIntent);
}
} else {
view.loadUrl(uri);
}
return true;
}
public boolean doFallback(WebView view, Intent parsedIntent) {
if (parsedIntent == null) {
return false;
}
String fallbackUrl = parsedIntent.getStringExtra(INTENT_FALLBACK_URL);
if (fallbackUrl != null) {
view.loadUrl(fallbackUrl);
return true;
}
String packageName = parsedIntent.getPackage();
if (packageName != null) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(URI_SCHEME_MARKET + packageName)));
return true;
}
return false;
}
}
안드로이드 11 보안정책 관련 안내
1.이슈
Android11의 패키지 가시성 정책이 변경됨에 따라,
Android11 이전 버전 OS에서는 앱이 PackageManager에서 제공하는 메소드(queryIntentActivities(), getInstalledApplications(), getInstalledApplications(), resolveActivity() 등)를 사용하여
시스템에 설치된 앱을 확인할 수 있었으나, Android11(API 30)부터 패키지 가시성 제한으로 조회할 수 없게 되어
결제창 등에서 사용하는 외부 앱(앱카드, 백신, 삼성페이, 페이코 등) 호출 시 패키지 정보로 앱 설치 여부를 확인하고 있을 경우 문제가 발생할 수 있습니다.
2.참고링크
- https://support.google.com/googleplay/android-developer/answer/10446026?hl=ko
- https://developer.android.com/about/versions/11/privacy/package-visibility?hl=ko
- https://developer.android.com/training/basics/intents/package-visibility?hl=ko#package-name
- https://developer.android.com/training/package-visibility/use-cases?hl=ko
- https://developer.android.com/training/basics/intents/package-visibility?hl=ko
3.방안
쇼핑몰 앱의 queries 요소에 패키지를 정의하거나, 재정의한 shouldOverrideUrlLoading() 메소드에서 startActivity() 호출 시 앱 미설치로 발생하는
ActivityNotFoundException(No Activity found to handle Intent)에 예외처리 로직을 추가합니다.
1안) queries 요소에 패키지 정의
AndroidManifest.xml 파일 수정
매니페스트 파일의 queries 요소에 패키지를 정의하면 패키지의 가시성이 확보됩니다.
EX) 쇼핑몰APP에서 호출할 수 있는 모든 APP의 패키지 정의 (queries tag 안에 해당 패키지 명의 정의 되어야 합니다)
장점 : 소스 수정 없이 매니페스트 파일만 수정
단점 : 패키지 목록 관리 필요 (카드사에 신규 앱 추가 시 쇼핑몰 앱에 패키지 추가 등록 필요)
2안) 쇼핑몰 앱의 WebViewClient shouldOverrideUrlLoading() 예외처리 로직 추가
* 재정의한 shouldOverrideUrlLoading() 메소드 로직 수정 필요
앱의 설치여부 확인을 위해 startActivity() 호출 전에 패키지 정보를 조회하는 경우, 설치 여부 확인 로직을 제거하고 바로 startActivity()을 호출
startActivity() 호출 시 ActivityNotFoundException(Message : No Activity found to handle Intent)이 발생한 경우 앱이 설치되지 않은 것으로 간주하고 앱 설치를 위해 마켓으로 이동하도록 처리
장점 : 패키지 목록 관리 필요 없음
단점 : 민감한 Webview 처리 로직 수정 필요
※ 2안으로 처리하고자 할 경우 각 쇼핑몰 앱 별로 구현 방식이 다양하므로 해당 사이트에 맞게 신중히 적용하시기 바라며, 반드시 각 카드사의 인증 수단 별로 결제 테스트를 진행하시기 바랍니다.
(참고) 안드로이드
기관 | 구분 | Scheme | Package | 비고 |
---|---|---|---|---|
BC | 페이북 | ispmobile:// | kvp.jjy.MispAndroid320 | |
우리 | 우리WON카드 | com.wooricard.smartapp | ||
우리페이 | com.wooricard.wpay | |||
우리WON뱅킹 | com.wooribank.smart.npib | |||
하나 | 원큐페이 | oneqpay:// | com.hanaskcard.paycla | |
하나멤버스 | hanawalletmembers:// | kr.co.hanamembers.hmscustomer | ||
신한 | 신한 페이판 | shinhan-sr-ansimclick:// | com.shcard.smartpay | |
신한 페이판-엘페이 | shinhan-sr-ansimclick-lpay:// | |||
신한 페이판-네이버페이 | shinhan-sr-ansimclick-naverpay:// | |||
신한 페이판-페이코 | shinhan-sr-ansimclick-payco:// | |||
신한 페이판-삼성페이 | shinhan-sr-ansimclick_samsungpay:// | |||
신한 페이판-LG페이 | shinhan-sr-ansimclick_lgpay:// | |||
신한 페이판-공동인증서 | smshinhanansimclick:// | com.shinhancard.smartshinhan | ||
신한 슈퍼 SOL | com.shinhan.smartcaremgr | |||
트래블월렛 App(트래블페이) | com.mobiletoong.travelwallet | |||
삼성 | 삼성 앱카드 | mpocket.online.ansimclick:// | kr.co.samsungcard.mpocket | |
삼성 앱카드-공동인증서 | mpocket.ansimclick.cert:// | |||
삼성 monimo | monimopay:// | net.ib.android.smcard | ||
monimopayauth:// | ||||
KB | KB Pay | kb-acp:// | com.kbcard.cxh.appcard | 백신 : Droid-X 백신 사용하나, KB Pay 내 라이브러리 형태라 별도 패키지명 없음 |
kb-event:// | ||||
kb-screen:// | ||||
LiiV (KB국민은행) | liivbank:// | com.kbstar.liivbank | ||
LiiV Next (KB국민은행) | newliiv:// | com.kbstar.reboot | ||
KB 스타뱅킹 (KB스타뱅킹) |
kbbank:// | com.kbstar.kbbank | ||
NH | NH 올원페이 | nhallonepayansimclick:// | nh.smart.nhallonepay | |
NH 올원페이-공동인증서 | ||||
현대 | 현대 앱카드 | hdcardappcardansimclick:// | com.hyundaicard.appcard | |
공동인증서 | appfree:// | com.lumensoft.touchenappfree | ||
롯데 | 앱카드 | lpayapp:// | com.lcacApp | |
L.Pay | com.lottemembers.android | |||
백신 | TouchEn mVaccine (신한) |
mvaccinestart:// | com.TouchEn.mVaccine.webs | |
mvaccinestartbg:// | ||||
mvaccineexit:// | ||||
mvaccinecheck:// | ||||
V-Guard (삼성) | vguardstart:// | kr.co.shiftworks.vguardweb | ||
vguardcheck:// | ||||
vguardend:// | ||||
V3 (NH, 현대, 롯데) | v3mobileplusweb:// | com.ahnlab.v3mobileplus | ||
기타 | 페이코 (삼성, NH, KB, 롯데, 하나) |
payco:// | com.nhnent.payapp | |
삼성페이 (삼성, NH, KB, 롯데, 하나) |
samsungpay:// | com.samsung.android.spay | ||
삼성페이 미니 (삼성, KB, 하나) |
samsungpay:// | com.samsung.android.spaylite | ||
엘지페이 (삼성, KB, 롯데, 하나) |
callonlinepay:// | com.lge.lgpay | ||
SSGPay (현대) |
shinsegaeeasypayment:// | com.ssg.serviceapp.android.egiftcertificate | ||
카카오 | Kakao Pay | kakaotalk:// | com.kakao.talk | |
금결원 | 뱅크페이 | kftc-bankpay:// | com.kftc.bankpay.android | (금융결제원) 계좌이체 결제시 필요 |
네이버 | 네이버페이 | com.nhn.android.search | ||
토스 | 토스 | supertoss:// | viva.republica.toss | |
티머니 페이 |
TmoneyPay | com.lgt.tmoney | ||
알리 페이 |
Alipay | alipays:// | com.eg.android.AlipayGphone | |
위쳇 페이 |
com.tencent.mm | |||
카카오 뱅크 |
Kakao Bank | kakaobank:// | com.kakaobank.channel |
IOS용 모바일 결제 구현예제
※ IOS 연동의 경우 IOS 스키마 등록이 필요합니다. (하단 스키마 목록 참조)
NSString* url = @"가맹점 초기 결제 페이지";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
// UIWebView로 구현
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *requestString = [[request URL] absoluteString];
if([requestString hasPrefix:@"ispmobile://"]) // 모바일 ISP 호출 처리
{
// tid 저장
tid = [[requestString componentsSeparatedByString:@"TID="] objectAtIndex:1];
NSURL *ispMobileAppURL = [NSURL URLWithString:requestString];
[[UIApplication sharedApplication] openURL:ispMobileAppURL options:@{} completionHandler:^(BOOL success) {
if(!success) {
// 모바일ISP 미설치시 설치 URL로 이동
NSURL *ispMobileAppDownloadURL = [NSURL URLWithString:@"http://itunes.apple.com/kr/app/id369125087?mt=8"];
[[UIApplication sharedApplication] openURL:ispMobileAppDownloadURL options:@{} completionHandler:nil];
}
}];
return NO;
}
return TRUE;
}
- (void)success {
NSLog(@"success");
}
- (void)fail {
NSLog(@"fail");
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"가맹점 StopUrl 페이지"]];
[_webView loadRequest:request];
}
기관 | 스키마 | ||
---|---|---|---|
신한카드 FAN앱 | shinhan-sr-ansimclick | ||
신한카드 공인인증 | smshinhanansimclick | ||
삼성카드 앱카드 | mpocket.online.ansimclick | ||
삼성카드 공인인증 | scardcertiapp | ||
삼성카드 monimo | monimopay monimopayauth |
||
현대카드 앱카드 | hdcardappcardansimclick | ||
현대카드 공인인증 | smhyundaiansimclick | ||
NH카드 앱카드 | nhappcardansimclick | ||
NH카드 공인인증 | nonghyupcardansimclick | ||
시럽페이 | tswansimclick | ||
페이코 | payco | ||
롯데 앱카드 | lotteappcard | ||
롯데 스마트결제 | lottesmartpay | ||
모바일 ISP | ispmobile | ||
국민 케이모션 | kb-acp | ||
KEB하나 1Q페이 | cloudpay | ||
씨티 간편결제앱 | citispay | ||
UPMP 앱 | uppay | ||
씨티카드 공인인증 | citicardappkr | ||
NH 농협카드 | nhallonepayansimclick | ||
(신규 앱)씨티 공인인증서 | citimobileapp | ||
(신규 앱)씨티 스마트 간편결제 | citimobileapp | ||
하나카드 | hanaskcardmobileportal | ||
L.pay | lpayapp | ||
우리카드 | wooripay | ||
카카오 | kakaotalk | ||
토스 | supertoss | ||
우리WON카드 앱 | com.wooricard.wcard | ||
우리WON뱅킹 앱 | NewSmartPib | ||
리브 Next | newliiv | ||
KB 스타뱅킹 | kbbank | ||
티머니페이 | tmoneypay | ||
알리 페이 | alipays | ||
계좌이체 | |||
금융결제원 | kftc-bankpay | ||
산업 | kdb-bankpay | ||
기업 | ibk-bankpay | ||
국민 | kb-bankpay | ||
KEB하나 | keb-bankpay | ||
수협 | sh-bankpay | ||
NH농협 | nhb-bankpay | ||
농축협 | nh-bankpay | ||
우리 | wr-bankpay | ||
SC | sc-bankpay | ||
신한 | s-bankpay | ||
씨티 | ct-bankpay | ||
대구 | dg-bankpay | ||
부산 | bnk-bankpay | ||
광주 | kj-bankpay | ||
제주 | jj-bankpay | ||
전북 | jb-bankpay | ||
경남 | kn-bankpay | ||
우정사업본부 | kp-bankpay | ||
신협 | cu-bankpay | ||
새마을 | mg-bankpay | ||
케이뱅크 | kbn-bankpay | ||
카카오뱅크 | kakaobank |