웹뷰에서 외부 앱 열기

가맹점의 모바일 앱에서 결제를 할 때 구매자가 선택한 카드사 또는 간편결제 앱으로 이동해 결제를 진행합니다. 가맹점의 모바일 앱에서 카드사 또는 간편결제 앱으로 이동하는 과정이 앱투앱 이동입니다. 이러한 이동을 위해서는 이동하려는 앱의 스킴을 미리 등록해야 문제 없이 이동이 가능합니다. 연동에 필요한 외부 앱 스킴(App URL Scheme) 목록과 방법을 확인하세요 .

웹뷰에서 외부 앱을 열려면 엑심베이 결제창을 띄울 때 call_from_appY를 포함해야 하며, 엑심베이 결제창에서 결제 완료 후 가맹점 앱으로 돌아가기 위해 call_from_scheme에 가맹점 앱 스킴을 추가해야 합니다.

외부 앱 스킴 리스트

웹뷰에서 이동할 수 있는 외부 앱(3rd party)는 ISP 앱, 국내 카드사 앱카드, 국내 간편결제 앱, 해외 간편결제 앱 등이 있습니다.

국내 카드 및 간편결제

결제사 앱 스킴
ISP(BC/국민) ispmobile://
국민카드 kb-acp://, newliiv://, kbbank://, liivbank://
롯데카드 lotteappcard://
삼성카드 mpocket.online.ansimclick://, monimopay://, monimopayauth://
신한카드 shinhan-sr-ansimclick://, com.shinhan.smartcaremgr://
현대카드 hdcardappcardansimclick://
농협카드 nhallonepayansimclick://
하나카드 cloudpay://
씨티카드 citimobileapp://
우리카드 com.wooricard.wcard:// NewSmartPib://

국내 간편결제

결제사 앱 스킴
네이버페이 naversearchthirdlogin://
카카오페이 kakaotalk://
토스페이 supertoss://
페이코 payco://
스마일페이 smilepayapp://

해외 간편결제

결제사 앱 스킴
라인페이 line://
알리페이 플러스 alipays://
위챗 weixin://

IOS

웹뷰에서 실행할 외부 앱 스킴의 리스트를 추가한 뒤 앱 스킴 실행을 위한 코드를 추가하세요.

1. 가맹점 앱 URL Scheme을 설정하세요.

가맹점 앱에 URL Scheme을 등록해야 합니다. 엑심베이 결제창을 열기 위해 JS SDK를 호출할 때 call_from_scheme 필드 값으로 가맹점 앱 URL Scheme을 사용해야 합니다.

2. 외부 앱(3rd party 앱) URL Scheme을 등록하세요.

Info.plist에 LSApplicationQueriesSchemes를 추가하고 결제수단의 앱 스킴을 아래와 같이 배열로 추가해야 합니다.

                    
//Info.plist
<key>LSApplicationQueriesSchemes</key>
<array>
  <!-- 국내 결제 --> 
  <string> ispmobile </string>  <!--ISP 모바일-->
  <string> lotteappcard </string>  <!--롯데카드 앱카드--> 
  <string> online.ansimclick </string>  <!--삼성카드 앱카드-->
  <string> monimopay </string>  <!--삼성카드 monimo-->
  <string> shinhan sr ansimclick </string>  <!--신한카드 앱카드-->
  <string> com.shinhan.smartcaremgr </string>  <!--신한카드 슈퍼SOL-->
  <string> hdcardappcardansimclick </string>  <!--현대카드 앱카드-->
  <string> nhallonepayansimclick </string>  <!--농협카드올원페이-->
  <string> cloudpay </string>  <!--하나카드 앱카드-->
  <string> citimobileapp </string>  <!--씨티모바일 앱카드-->
  <string> scom.wooricard.wcard </string>  <!--우리WON 카드앱-->
  <string> NewSmartPib </string>  <!--우리WON 뱅킹앱-->
  <string> kakaotalk </string>  <!--카카오페이-->
  <string> payco </string>  <!--페이코-->
  <string> smilepayapp </string>  <!--스마일페이-->
  <string> supertoss </string>  <!--토스-->
  <string> naversearchthirdlog in </string>  <!-- 네이버페이-->

  <!-- 해외 결제--> 
  <string> line </string>  <!--LINEPAY--> 
  <string> alipays </string>  <!--Alipay+-->
  <string> weixin </string>  <!--Wechat-->
</array>
                    
                  

3. 네트워크 보안 예외를 설정하세요.

웹뷰로 들어오는 HTTPS 요청의 보안 제한을 허용하기 위해 아래와 같이 ATS(App Transport Security)를 설정하세요.

                    
<key>NSAppTransportSecurity</key> 
<dict> 
<key>NSAllowsArbitraryLoadsInWebContent</key> 
<true/> 
<key>NSAllowsArbitraryLoads</key>
<true/> 
</dict>
                    
                  

Android

앱스킴 추가 샘플코드

Android 운영체제는 웹뷰에서 외부 앱을 호출하려면 shouldOverriderUrlLoading부분에 카드사, 결제사 앱을 호출하기 위한 로직 추가가 필요합니다.

Java
                      
국내 결제

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (!URLUtil.isNetworkUrl(url) && !URLUti l.isJavaScriptUrl(url)) {
        final Uri uri;
        Intent intent = null;
        
        try {
                uri = Uri.parse(url);
                intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);

        } catch (Exception e){
            return false;
        }

        if ("intent".equals(uri.getScheme())) {
                try {
                        Log.d("LOG", "intent startActivity");
                        startActivity(intent);
                        return true;
                } catch (ActivityNotFoundExce ption e) {
                        final String packageName = intent.getPackage();
                        Log.d("LOG", "ActivityNotFoundException packageName :" + packageName);
                        if (!TextUtils.isEmpty(packageName)) {
                        startActivity(new Intent(Intent.ACTION_VIEW,
                        Uri.parse("market://details?id=" + packageName)));
                        return true;
                        }
                }
            } else if ("supertoss".equals(uri.getScheme())) {//TOSS
                      try {
                            Log.d("LOG", "TOSS startActivity");
                            startActivity(new Intent(Intent.ACTION_VIEW, uri));
                            return true;
                      } catch (ActivityNotFoundException e)
                              Log.d("LOG", "Activi tyNotFoundException TOSS");
                              startActivity( new Intent (Intent.ACTION_VIEW,
                      Uri.parse("market://details?id=viva.republica.toss")));
                                return true;
                            } catch (Exception e) {
                                return false;
                            }
                      } else if("nidlogin".equals(uri.getScheme())) {//NAVERPAY
                              try {
                                      Log.d("LOG", "NAVERPAY startActivity");
                                      startActivity(new Intent(Intent.ACTION_VIEW, uri));
                                      return true;
                              } catch (ActivityNotFoundException e) {
                                        Log.d("LOG", "ActivityNotFoundException NAVERPAY");
                                        startActivity(new Intent(Intent.ACTION_VIEW,
                      Uri.parse("market://details?id=com.nhn.android.search")));
                                        return true;
                                    }
                                    catch (Exception e) {
                                    return false;
                                    }
                        } else {
                                  try {
                                        Log.d("LOG", "else startActivity");
                                        startActivity(new Intent(Intent.ACTION_VIEW, uri));
                                        return true;
                                  } catch (ActivityNotFoundException e) {
                                            final String packageName = intent.getPackage();
                                            Log.d("LOG", "4091_else startActivity ActivityNotFoundException 
                        packageName :" + packageName);
                                            if (!TextUtils.isEmpty(pack ageName)) {
                                            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id="
                        + packageName)));
                                          return true;
                                          }
                                      } catch (Exception e) {
                                                return false;
                                      }
                              }
                      }
                      return false;
                }
                      
                  
Java
                                
          해외 결제
          
          @Override
          public boolean shouldOverrideUrlLoading(WebView view, String url) {
            
              if (!URLUtil.isNetworkUrl(url) && !URLUtil.isJavaScriptUrl(url)) {
                    final Uri uri;
                    Intent intent = null;
                    
                    try {
                          uri = Uri.parse(url);
                          intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
                    
                      } catch (Exception e) {
                            return false;
                    }
                    
                    if ("intent".equals(uri.getScheme())) {
                          try {
                                Log.d("LOG", "intent startActivity");
                                startActivity(intent);
                                return true;
                            } catch (ActivityNotFoundException e) {
                                      final String packageName = intent.getPackage();
                                      Log.d("LOG", "ActivityNotFoundException packageName :" + packageName);
                                      if (!TextUtils.isEmpty(packageName)) {
                                              startActivity(new Intent(Intent.ACTION_VIEW,
                                              Uri.parse("market://details?id=" + packageName)));
                                              return true;
                                              }

                            } else if ("alipays".equals(uri.getScheme())) { //Alipay+
                                        try {
                                              Log.d("LOG", "alipays startA ctivity");
                                              startActivity(new Intent(Intent.ACTION_VIEW, uri));
                                              return true;
                                        } catch (ActivityNotFoundException e) {
                                              Log.d("LOG", "ActivityNotFoundException alipays");
                                              startActivity(new Intent(Intent.ACTION_VIEW,
                                              Uri.parse("market://details?id=com.eg.android.AlipayGphone")));
                                              return true;
                                        
                                        } catch (Exception e) {
                                              return false;
                                        }

                            } else if ("line".equals(uri.getScheme())) { //LINEPAY
                                        try {
                                              Log.d("LOG", "line startActivity");
                                              startActivity(new Intent(Intent.ACTION_VIEW, uri));
                                              return true;
                                        } catch (ActivityNotFoundException e) {
                                              Log.d("LOG", "ActivityNo tFoundException line");
                                              startActivity(new Intent(Intent.ACTION_VIEW,
                                              Uri.parse("market://details?id=jp.naver.line.android")));
                                              return true;
                                        } catch (Exception e) {
                                              return false;
                                        }
                              } else if ("weixin".equals(uri.getScheme())) { //Wechat
                                        try {
                                              Log.d("LOG", "weixin startActivity");
                                              startActivity(new Intent(Intent.ACTION_VIEW, uri));
                                              return true;
                                        } catch (ActivityNotFoundException e) {
                                              Log.d("LOG", "ActivityNo tFoundException weixin");
                                              startActivity(new Intent(Intent.ACTION_VIEW,
                                              Uri.parse("market://details?id=com.tencent.mm")));
                                              return true;
                                        } catch (Exception e) {
                                              return false;
                                        }

                              } else {
                                        try {
                                            Log.d("LOG", "else startActivity");
                                            startActivity(new Intent(Intent.ACTION_VIEW, uri));
                                            return true;
                                        } catch (ActivityNotFoundException e) {
                                            final String packageName = intent.getPacka ge();
                                            Log.d("LOG", "4091_else startActivity ActivityNotFoundException packageName :" + packageName);
                                            
                                            if (!TextUtils.isEmpty(packageName)) {
                                                  startActivity(new Intent(Intent.ACTION_VIEW,
                                                  Uri.parse("market://details?id=" + packageName)));
                                                  return true;
                                              }
                                          } catch (Exception e) {
                                              return false;
                                          }
                                }
                        }
                        return false;
                }                                
                                
                                          
                            

Alipay+ 예외

해외 결제 수단인 Alipay+를 호출하기 위해서는 아래 파라미터를 웹뷰 설정 부분에 추가해야 합니다.

                    
//Enable javascript 
webSettings.setJavaScriptEnabled(true); 

//Enable scaling 
webSettings.setSupportZoom(true); 

//Enable scaling controls (buttons) 
webSettings.setBuiltInZoomControls(true); 

//2 cache mode for WebView (web and WAP). Load no cache here. 
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); 

//Allow JavaScript to open new windows. (false by default) 
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); 

//Allow JavaScript to load the local cache. 
webSettings.setDomStorageEnabled(true); 

//WAP cache size (No need to manually set) 

//webSettings.setAppCacheMaxSize(1024 * 1024 * 8); 

//WAP cache path 
String absolutePath = getApplicationContext().getCacheDir().getAbsolutePath(); 

//WAP cache size 
webSettings.setAppCachePath(absolutePath); 

//Whether allow WebView to access files (true by default) 
webSettings.setAllowFileAccess(true); 

//Enable to save WAP cache 
webSettings.setAppCacheEnabled(true); 

//When using overview mode, if the the page width exceeds WebView dispaly, scale the page to adapt to the WebView (false by default) 
webSettings.setLoadWithOverviewMode(true); 

// support for the viewport HTML meta tag 
webSettings.setUseWideViewPort(true);
                    
                  

WeChat H5

앱에서 Eximbay 결제창을 호출하여 WeChat H5 결제가 가능합니다. H5 결제를 위해 안드로이드 환경에서는 사이트 검증을 위해 Referer를 https://secureapi.eximbay.com으로 헤더에 추가해야 합니다. Referrer 설정이 되어 있지 않으면 위챗 앱 내에서 결제창이 정상적으로 호출되지 않으니 아래 샘플 코드를 참조해 추가해주시면 됩니다.

                              
      mWebView.setWebViewClient(new WebViewClient() {
          @SuppressLint("LongLogTag")
          @Override
          public boolean shouldOverrideUrlLoading(WebView view, String url) {
              Log.d("LOG", "shouldOverrideUrlLoading url : " + url);
              Log.d("LOG", "URLUtil.isNetworkUrl(url) : " + URLUtil.isNetworkUrl(url) + ", URLUtil.isJavaScriptUrl(url) : " + URLUtil.isJavaScriptUrl(url));
              
              if (!URLUtil.isNetworkUrl(url) && !URLUtil.isJavaScriptUrl(url)) {
                  final Uri uri;
                  Intent intent = null;
                  try {
                        uri = Uri.parse(url);
                        intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
                      
                      } catch (Exception e) {
                          return false;
                      }
                      if ("weixin".equals(uri.getScheme())) {
                            try {
                                  Log.d("LOG", "weixin startActivity");
                                  intent = new Intent(Intent.ACTION_VIEW, uri);
                                  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                  // use startActivity function redirect to wallet app
                                  startActivity(intent);
                                  return true;
                                
                                } catch (ActivityNotFoundException e) {
                                  startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.tencent.mm")));
                                  return true;
                                
                                } catch (Exception e) {
                                  return false;
                                }
                        }
                  } else if (url.startsWith("https://wx.tenpay.com")) {
                      Map extraHeaders = new HashMap();
                      extraHeaders.put("Referer", "https://secureapi.eximbay.com");
                      view.loadUrl(url, extraHeaders);
                      return true;
                  } else {
                      view.loadUrl(url);
                      return false;
                  }
                    return false;
                     
              }
          });