ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • WkWebview post 방식시 httpbody 씹는 문제 (iOS 10 이하 대응) 해결방안
    iOS 2018. 7. 10. 16:48

    iOS 10 이하에서는 request에 포스트 방식으로 전송시, httpbody를 씹는 버그가 있습니다.

    iOS 11 이상에서는 해결된 이슈이지만,


    iOS  11에서도  [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];


    처럼 컨텐트 타입을 세팅 안하면 httpbody 씹으므로 주의할 필요가 있습니다.


    아무튼 iOS 10 이하에서도 대응할 방안이 필요한데,

    제일 간단한 건 포스트 방식 대신에 get  방식으로 보내는 거겠습니다.

    하지만 (다른 문제는 뒤로 하고) get 방식으로 보내는 경우, 웹뷰가 띄우는 페이지가 최적화가 개판으로 되어 로딩 속도가 크게 길면 뻗어버리는 문제가 있더군요.


    따라서 이런 방식으로 해결하는 방식을 썼습니다.


    1. 처음에 인앱의 html 파일을 로드

    2. 로드가 끝나면, html 파일 내의 post를 보내는 자바스크립트를 호출



    - (void)viewDidLoad {

        [super viewDidLoad];

        

        

       

        [self setUpWebView];

        self.wkWebview.navigationDelegate = self;

        


        if (@available(iOS 11, *)){

            NSString *body = [NSString stringWithFormat@"email=%@&password=%@"@"test1",@"t123"];

            NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:URL]];

            [request setHTTPMethod@"POST"];

            

            [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

            [request setHTTPBody: [body dataUsingEncodingNSUTF8StringEncoding]];

            [self.wkWebview loadRequest:request];

        }else {

            didMakePostRequest = FALSE;

            NSString *path = [[NSBundle mainBundlepathForResource:@"POSTRequestJS" ofType:@"html"];

            

            NSString *html = [[NSString allocinitWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

             [self.wkWebview loadHTMLString:html baseURL:[[NSBundle mainBundlebundleURL]];

            

     

        }

        


        

    }


    POSTRequestJS

    라는 파일을 일단 로드합니다. 서포팅 파일즈 밑에 PostRequestJS.html 이라는 파일을 넣어주면 되겠습니다.

    <html>

        <head>

            <script>

                

                

                //POST request example:

                //post('URL', {key: 'value'});

                function post(path, params) {

                    var method = "post";

                    var form = document.createElement("form");

                    form.setAttribute("method", method);

                    form.setAttribute("action", path);

                   

                    for(var key in params) {

                        if(params.hasOwnProperty(key)) {

                            var hiddenField = document.createElement("input");

                            hiddenField.setAttribute("type""hidden");

                            hiddenField.setAttribute("name", key);

                            hiddenField.setAttribute("value", params[key]);

                            

                            form.appendChild(hiddenField);

                        }

                    }

                    

                    document.body.appendChild(form);

                    

                    form.submit();

                }

            </script>

        </head>

        <body>

        </body>

    </html>


    그냥 html  파일입니다. 해당 파일을 약간 수정하여, 바디에 <h1>hello html</h1> 같은거 살짝 삽입하면 로드 됬나 안됬나 확인 가능.

    post('URL', {key: 'value'});


    라는 자바스크립트를 호출하면, 해당 주소에 키 박아넣어서 포스트 해버리는 방식입니다.


    - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {


        if (@available(iOS 11, *)){

        }else{

            if (!didMakePostRequest) {

                [self makePostRequest];

            }else {

              

            }

        }

        

        

    }


    해당 html  파일 로드 끝났으면 이 함수 자동으로 호출됩니다. makePostRequest 함수에서 하는 일은, 자바스크립트 호출 하나입니다.



    - (void)makePostRequest

    {

        didMakePostRequest = YES;

        NSString *body = [NSString stringWithFormat: @"email:'%@',password: '%@'",@"test1"@"1234"];

        

        NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:URL]];

        [request setHTTPMethod@"POST"];

        

        [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

        [request setHTTPBody: [body dataUsingEncodingNSUTF8StringEncoding]];

          NSString *jscript = [NSString stringWithFormat:@"post('%@', {%@});"URL, body];

        NSLog(@"Javascript: %@", jscript);

        

        [self.wkWebview evaluateJavaScript:jscript completionHandler:^(id object, NSError * _Nullable error) {

            if (error) {

                NSLog(@"----------->>>>>>>>>>>>> evaluateJavaScript error : %@", [error localizedDescription]);

            }

        }];

        

        

    }

    }


    바디의 형식이 다른걸 주의합니다. 자바스크립트를 호출하는 것이므로, 

    email=qwer&password=1234 방식이 아니라,

    자바스크립트 배열형식에 맞게  email : 'qwer', password : '1234'

    방식으로 넘겨 주고,


    post("http://naver.com", { email : 'qwer', password : '1234'}); 자바스크립트를 평가한다고 생각하시면 되겠습니다.


    마음대로 안 되면, 


     if (error) {

                NSLog(@"----------->>>>>>>>>>>>> evaluateJavaScript error : %@", [error localizedDescription]);

            }


    여기에 브레이크포인트 찍습니다. 보통 자바스크립트에 인자 잘못 줘서 깨진다는 느낌의 에러를 표시하니까, 고쳐서 쓰면 됩니다.


    자바스크립트 평가 끝났으면, 다음 로딩부턴 이 함수 다시 부르지 않도록

    didMakePostRequest = YES;

    로 막아주는 것까지 하면 끝.

Designed by Tistory.