안드로이드 Kotlin Web-view 연동

  1. 환경설정

      AndroidManifast.xml 파일에 권한 및 네트워크 보안 예외 설정을 합니다.

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="kr.co.nicepay.nicepayappsample">
    
        <uses-permission android:name="android.permission.INTERNET" /> // 네트워크 사용 권한 허용
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme"
            android:usesCleartextTraffic="true"> // 네트워크 TLS 기본값 변경으로 인해 일반 텍스트 사용 시 설정 (Android 9.0 이상)
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <activity
                android:name=".WebViewActivity"
                android:label="NicePay Smart"
                android:configChanges="orientation"
                android:screenOrientation="portrait">
                <intent-filter>
                    <action android:name="android.intent.action.VIEW" />
                </intent-filter>
            </activity>
    
        </application>
    
    </manifest>
    
  2. 웹뷰 연동

      웹뷰에서 자바스크립트 실행 가능하도록 설정

    class WebViewActivity : AppCompatActivity() {
        companion object {
            const val MERCHANT_URL = "https://web.nicepay.co.kr/demo/v3/mobileReq.jsp"
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_webview)
    
            webview.webViewClient = WebViewClientClass()
    
            val settings = webview.settings
            settings.javaScriptEnabled = true
    
  3. 캐시 및 쿠키 설정

      캐시 모드는 웹뷰 기본값으로 설정한다.(WebSetting.LOAD_CACHE_ELSE_NETWORK 설정 시 일부 카드사 세션 오류 발생)

      쿠키 허용 설정 (Android 5.0 이상 시 third-party 쿠키 허용 추가)

    //setup cache
    /*
     * WebView에서 캐시사용 관련 Default 설정은 WebSettings.LOAD_DEFAULT 입니다.
     * ex) settings.cacheMode = WebSettings.LOAD_DEFAULT
     * 가급적 캐시 사용 설정을 변경하지 않을것을 권고 드립니다.
     * @중요 : 'WebSettings.LOAD_CACHE_ELSE_NETWORK' 로 변경금지.
     * @중요 : Do not change the setting to 'WebSettings.LOAD_CACHE_ELSE_NETWORK'
    */
    settings.cacheMode = WebSettings.LOAD_DEFAULT
    
    if( android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) {    //Android 5.0 이상
        settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW)
        CookieManager.getInstance().setAcceptCookie(true)
        CookieManager.getInstance().setAcceptThirdPartyCookies(webview, true)
    } else {
        CookieManager.getInstance().setAcceptCookie(true)
    }
    
  4. 결제 페이지 호출

      웹뷰의 postUrl을 통해 결제 요청 URL을 호출한다. (가맹점 결제 요청 페이지)

    webview.postUrl(MERCHANT_URL, null)
    
  5. URI 처리 및 Intent 처리

      URI에 포함된 요청 데이터를 Intent를 통해 어플리케이션 호출(startActivity)

      Android 하위 버전의 경우 intent:// 방식이 아닌 scheme 호출 방식으로 들어올 수 있음

      해당 경우 scheme을 수동으로 추가해야 함 (ex cloudpay://~ 로 들어올 경우 if( url.startwith(“cloudpay”)

    private class WebViewClientClass : WebViewClient() {
        override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
            println("url : " + url)
    
            try {
                if( url != null && (url.contains("market://") || url.contains("intent")) ) {
    
                    var intent: Intent? = null
    
                    try {
                        intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME)
                    } catch (e: URISyntaxException) {
                        println("error : " + e.printStackTrace())
                    }
    
                    if( view?.context?.packageManager?.resolveActivity(intent, 0) == null ) {
                        val pkgName = intent?.`package`
                        if( pkgName != null ) {
                            val uri = Uri.parse("market://search?q=pname:" + pkgName)
                            intent = Intent(Intent.ACTION_VIEW, uri)
                            view?.context?.startActivity(intent)
                        }
                    } else {
                        val uri = Uri.parse(intent?.dataString)
                        intent = Intent(Intent.ACTION_VIEW, uri)
                        view?.context?.startActivity(intent)
                    }
                } else {
                    view?.loadUrl(url)
                }
            } catch (e: Exception) {
                println("error : " + e.printStackTrace())
                return false
            }
    
            return true
        }
    }
    

안드로이드 JAVA Web-view 연동

  1. 환경설정

      AndroidManifast.xml 파일에 권한 및 네트워크 보안 예외 설정을 합니다.

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="sample.nicepay.co.kr.nicepayappsample">
    
        <uses-permission android:name="android.permission.INTERNET" />  // 네트워크 사용 권한 허용
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme"
            android:usesCleartextTraffic="true"> // 네트워크 TLS 기본값 변경으로 인해 일반 텍스트 사용 시 설정 (Android 9.0 이상)
            <activity android:name=".MainActivity"
                android:configChanges="orientation"
                android:screenOrientation="portrait">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <activity
                android:name=".WebViewActivity"
                android:label="NicePay Smart"
                android:configChanges="orientation"
                android:screenOrientation="portrait">
                <intent-filter>
                    <action android:name="android.intent.action.VIEW" />
                </intent-filter>
            </activity>
    
        </application>
    
    </manifest>
    
  2. 웹뷰 연동

      웹뷰에서 자바스크립트 실행 가능하도록 설정 (WebViewActivity.java)

    public class WebViewActivity extends Activity {
        private static final String TAG = "NICE";
        private static final String MERCHANT_URL = "https://web.nicepay.co.kr/demo/v3/mobileReq.jsp";
    
        private WebView mWebView = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_webview);
    
            mWebView = (WebView)findViewById(R.id.webview);
    
            //setup default
            mWebView.setWebViewClient(new WebViewClientClass());
    
            //javascript allow
            mWebView.getSettings().setJavaScriptEnabled(true);
    
  3. 캐시 및 쿠키 설정

      캐시 모드는 웹뷰 기본값으로 설정한다.(WebSetting.LOAD_CACHE_ELSE_NETWORK 설정 시 일부 카드사 세션 오류 발생)

      쿠키 허용 설정 (Android 5.0 이상 시 third-party 쿠키 허용 추가)

    //setup cache
    /*
    * WebView에서 캐시사용 관련 Default 설정은 WebSettings.LOAD_DEFAULT 입니다.
    * ex) mWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
    * 가급적 캐시 사용 설정을 변경하지 않을것을 권고 드립니다.
    * @중요 : 'WebSettings.LOAD_CACHE_ELSE_NETWORK' 로 변경금지.
    * @중요 : Do not change the setting to 'WebSettings.LOAD_CACHE_ELSE_NETWORK'
    */
    mWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
    
    //setup cookie
    if( android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) {    //Android 5.0 이상
     mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
     CookieManager cookieManager = CookieManager.getInstance();
     cookieManager.setAcceptCookie(true);
     cookieManager.setAcceptThirdPartyCookies(mWebView, true);
    } else {
     CookieManager cookieManager = CookieManager.getInstance();
     cookieManager.setAcceptCookie(true);
    }
    
  4. 결제 페이지 호출

      웹뷰의 postUrl을 통해 결제 요청 URL을 호출한다. (가맹점 결제 요청 페이지)

    mWebView.postUrl(MERCHANT_URL, null);
    
  5. URI 처리 및 Intent 처리

      URI에 포함된 요청 데이터를 Intent를 통해 어플리케이션 호출(startActivity)

      Android 하위 버전의 경우 intent:// 방식이 아닌 scheme 호출 방식으로 들어올 수 있음

      해당 경우 scheme을 수동으로 추가해야 함 (ex cloudpay://~ 로 들어올 경우 if( url.startwith(“cloudpay”)

    private class WebViewClientClass extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            Log.i(TAG,"current url : " + url);
    
            try {
                if( url != null && (url.contains("market://") || url.startsWith("intent")) ) {
                    Intent intent = null;
    
                    try {
                        intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
                    } catch (URISyntaxException ex) {
                        Log.e(TAG,"[error] Bad request uri format : [" + url + "] =" + ex.getMessage());
                        return false;
                    }
    
                    if( getPackageManager().resolveActivity(intent,0) == null ) {
                        String pkgName = intent.getPackage();
                        if( pkgName != null ) {
                            Uri uri = Uri.parse("market://search?q=pname:" + pkgName);
                            intent = new Intent(Intent.ACTION_VIEW, uri);
                            startActivity(intent);
                        }
                    } else {
                        Uri uri = Uri.parse(intent.getDataString());
                        intent = new Intent(Intent.ACTION_VIEW, uri);
                        startActivity(intent);
                    }
                } else {
                    view.loadUrl(url);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
    
            return true;
        }
    }
    

iOS SWIFT Web-view 연동

  1. 가맹점 어플리케이션 URL Scheme 설정

      가맹점 어플리케이션 URL Scheme 등록 (결제 요청 전문 중 WapUrl 필드 값으로 사용)

      info.plist 파일에 URL Scheme을 등록한다. (3rd 어플리케이션 -> 가맹점 어플리케이션 호출)

      (미설정 시 특정 3rd 어플리케이션에서 인증 or 결제 완료 후 가맹점 어플리케이션으로 자동 전환 불가)

  2. 3rd 어플리케이션 URL Scheme 등록

      info.plist 파일에 3rd URL Scheme을 등록한다. (가맹점 어플리케이션 -> 3rd 어플리케이션 호출)

      (미설정 시 3rd 어플리케이션 연동 불가)

  3. 네트워크 보안 예외 설정

      HTTP 또는 유효하지 않은 인증서를 가진 HTTPS 연결 시 예외 처리

      (Apple에서는 하기와 같은 방법을 권장하지 않으며, 특정 도메인에 대해서만 예외 처리하도록 권장함)

  4. 결제 페이지 호출

      웹뷰의 load를 통해 결제 요청 URL을 호출한다. (가맹점 결제 요청 웹 페이지)

    override func viewDidLoad() {
        super.viewDidLoad()
    
        // Do any additional setup after loading the view.
        title = "구매하기"
    
        webView = WKWebView(frame: self.view.frame)
        webView?.navigationDelegate = self
        webView?.uiDelegate = self
        self.view.addSubview(webView!)
    
        let url = URL(string: PAY_URL)
        let request = URLRequest(url: url!)
        webView?.load(request)
    }
    
  5. URL 처리 및 3rd 어플리케이션 호출

      URL에 포함된 App Scheme을 통해 어플리케이션 호출(openURL)

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        let request = navigationAction.request
        let optUrl = request.url
        let optUrlScheme = optUrl?.scheme
    
        guard let url = optUrl, let scheme = optUrlScheme
            else {
                return decisionHandler(WKNavigationActionPolicy.cancel)
        }
    
        debugPrint("url : \(url)")
    
        if( scheme != "http" && scheme != "https" ) {
            if( scheme == "ispmobile" && !UIApplication.shared.canOpenURL(url) ) {  //ISP 미설치 시
                UIApplication.shared.openURL(URL(string: "http://itunes.apple.com/kr/app/id369125087?mt=8")!)
            } else if( scheme == "kftc-bankpay" && !UIApplication.shared.canOpenURL(url) ) {    //BANKPAY 미설치 시
                UIApplication.shared.openURL(URL(string: "http://itunes.apple.com/us/app/id398456030?mt=8")!)
            } else {
                if( UIApplication.shared.canOpenURL(url) ) {
                    UIApplication.shared.openURL(url)
                } else {
                    //1. App 미설치 확인
                    //2. info.plist 내 scheme 등록 확인
                }
            }
        }
    
        decisionHandler(WKNavigationActionPolicy.allow)
    }
    
  6. 자바스크립트 팝업 처리

      웹뷰의 오버라이딩 함수를 재정의 하여 팝업 처리

    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        let alert = UIAlertController(title: "", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "확인", style: .default, handler: { (UIAlertAction) in
            completionHandler()
        }))
    
        self.present(alert, animated: true, completion: nil)
    }
    

iOS Objective-C Web-view 연동

  1. 가맹점 어플리케이션 URL Scheme 설정

      가맹점 어플리케이션 URL Scheme 등록 (결제 요청 전문 중 WapUrl 필드 값으로 사용)

      info.plist 파일에 URL Scheme을 등록한다. (3rd 어플리케이션 -> 가맹점 어플리케이션 호출)

      (미설정 시 특정 3rd 어플리케이션에서 인증 or 결제 완료 후 가맹점 어플리케이션으로 자동 전환 불가)

  2. 3rd 어플리케이션 URL Scheme 등록

      info.plist 파일에 3rd URL Scheme을 등록한다. (가맹점 어플리케이션 -> 3rd 어플리케이션 호출)

      (미설정 시 3rd 어플리케이션 연동 불가)

  3. 네트워크 보안 예외 설정

      HTTP 또는 유효하지 않은 인증서를 가진 HTTPS 연결 시 예외 처리

      (Apple에서는 하기와 같은 방법을 권장하지 않으며, 특정 도메인에 대해서만 예외 처리하도록 권장함)

  4. 결제 페이지 호출

      웹뷰의 loadRequest를 통해 결제 요청 URL을 호출한다. (가맹점 결제 요청 웹 페이지)

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view from its nib.
        self.title = @"구매하기";
        
        self.webView = [[[WKWebView alloc] init] autorelease];
        self.webView.navigationDelegate = self;
        self.webView.UIDelegate = self;
        [self.view addSubview:self.webView];
        
        //nicepay 결제테스트 URL 입니다.
        //제공 된 샘플 상 payRequest 스크립트 페이지를 참고 하시여 개발 하시면 됩니다.
        [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:PAY_URL]]];
    }
    
  5. URL 처리 및 3rd 어플리케이션 호출

      URL에 포함된 App Scheme을 통해 어플리케이션 호출(openURL)

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        NSURLRequest *request = navigationAction.request;
        NSURL *url = [request URL];
        NSString *urlScheme = [url scheme];
        
        NSLog(@"url : %@", url);
        
        if( ![urlScheme isEqualToString:@"http"] && ![urlScheme isEqualToString:@"https"] ) {
            if( [urlScheme isEqualToString:@"ispmobile"] && ![[UIApplication sharedApplication] canOpenURL:url] ) {
                //ISP App가 설치되어 있지 않을 경우 앱스토어로 이동
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://itunes.apple.com/kr/app/id369125087?mt=8"]];
            } else if( [urlScheme isEqualToString:@"kftc-bankpay"] && ![[UIApplication sharedApplication] canOpenURL:url] ) {
                //BANKPAY App가 설치되어 있지 않을 경우 앱스토어로 이동
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://itunes.apple.com/us/app/id398456030?mt=8"]];
            } else {
                if( [[UIApplication sharedApplication] canOpenURL:url] ) {
                    [[UIApplication sharedApplication] openURL:url];    //App 실행
                } else {
                    //1. App 미설치 확인
                    //2. info.plist 내 scheme 등록 확인
                }
            }
        }
        
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    
  6. 자바스크립트 팝업 처리

      웹뷰의 오버라이딩 함수를 재정의 하여 팝업 처리

    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil
                                                                                 message:message
                                                                          preferredStyle:UIAlertControllerStyleAlert];
        [alertController addAction:[UIAlertAction actionWithTitle:@"확인"
                                                            style:UIAlertActionStyleCancel
                                                          handler:^(UIAlertAction *action) {
                                                              completionHandler();
                                                          }]];
        [self presentViewController:alertController animated:YES completion:^{}];
    }