ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [iOS] 웹뷰로 하이브리드앱 구현 시작하기. Building a Hybrid App with UIWebView.
    앱등이에게 살충제를 뿌린다./iOS 2015. 11. 27. 10:09

    소스 다운로드 > https://github.com/cpromise/HybridAppIOS





    웹뷰띄워 하이브리드앱 만들어보기

    웹앱, 하이브리드앱.. 각 단어가 정확히 어떤 정의를 갖는지 모르겠지만!!

    웹뷰로 iOS앱을 만드는 법에 대해서 알아봅시다.

    샘플코드및 동영상은 맨 아래에




    웹뷰를 통해 HTTP URL요청하기

    NSURLRequest객체를 만든 뒤 UIWebView의 loadRequest메소드를 통해 호출할 수 있다. NSURL요청을할 때, HTTP요청인 경우에는 헤더에 원하듣 필드와 값을 지정하여 전달할 수 있다.

    UIWebView *webview = [[UIWebView alloc] init] ;

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLwithString:@""] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0f];

    [webview loadRequest:request];



    델리게이트를 통해서 Response를 확인할 수 있다.

    • webView: shouldStartLoadWithRequest: navigationType:
      • 웹뷰가 로딩을 시작하기 전에 호출된다.
      • 추후에 Javascript - Objective-C와의 통신에도 사용된다.
    • webViewDidStartLoad:
    • webViewDidFinishLoad:
    • webView: didFailLoadWithError:
      • 웹뷰가 데이터를 로딩하는데 실패하면 호출된다.
      • error를 통해 원인을 파악할 수 있다. (ex: NSLog(@"%@",error.description);)

    iOS9부터 SSL(TLS)을 지원하지 않는 서버는 요청을 권장하지 않고 있다.

    HTTPS가 아닌 HTTP요청을 시도하면 webView: didFailLoadWithError: 메소드가 호출되고 error파라미터는 The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.를 포함하는 메시지를 전달한다. HTTP호출의 제한을 명시적으로 해제하려면 info.plist파일을 수정하여 HTTP 호출을 시도할 수 있다.



    Javascript와 Objective-C가 통신할 수 있다.

    웹뷰 내에 있는 Javascript코드를 통해 Objective-C를 호출하거나 Objective-C코드를 통해 Javascript코드를 호출할 수 있다.


    1. Javascript코드에서 Objective-C코드 호출

    <input type="button" onClick="callNative()" value="샘플버튼"/> 

    이런 태그가 있다고 가정할 때, 버튼을 누르면 Javascript에 구현된 callNative()라는 메소드가 실행될 것이다.



    <script>

    var callNative = function(){

        window.location = "appscheme://callNative";

    }

    </script> 

    callNative는 이렇게 App의 URL scheme을 호출하는 역할만 해줄뿐!!


    **참고

    iOS에서 웹브라우저에서 앱을 열때는 보통 이렇게 URL을 통해 호출합니다. 예를들면 신한앱카드, 카카오페이로 결제하기가 있습니다. 

    앱이 없을 때 앱스토어로 이동하는 방식 역시 이 안에서 if문으로 분기처리하여 앱이 없다면 앱스토어로 연결되는 방식으로 구현됩니다.


    이렇게 하면 네이티브 코드에서는 아래 메소드가 호출됩니다.

     - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

    이 메소드는 리턴타입에서 볼 수 있듯 웹뷰에서 온 요청을 수행할 것인지 말 것인지를 결정하여 BOOL타입을 리턴합니다.


    //예시구현

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{

        if ([[[request URL] absoluteString] hasPrefix:@"appscheme:"]) {

            NSString *requestString = [[request URL] absoluteString];

            NSArray *components = [requestString componentsSeparatedByString:@"://"];

            NSString *functionName = [components objectAtIndex:1];

            

            [self performSelector:NSSelectorFromString(functionName)];

            return NO;

        } else{

            return YES;

        }


    -(void)callNative{

        NSLog(@"%s called.",__FUNCTION__);

    }

    "appscheme://callNative"라는 문자열이 들어왔고, appscheme이라는 문자열과 callNative라는 문자열로 분리했습니다. 그리고 appscheme이 앱과 일치한다면 callNative라는 selector를 실행하게 되는 구조입니다. Javascript에서 전달한 함수이름이 Objective-C와 같지 않아도 원하는 Objective-C의 메소드를 실행할 수 있다는 점이 눈에 띕니다.



    **참고 : request 파라미터에는 웹뷰에 로드된 컨텐츠에서 어떤 리퀘스트가 있을 때 들어오는 변수인데 아래와 같이 구성되어 있습니다.

    • absoluteString – An absolute string for the URL. Creating by resolving the receiver’s string against its base.
    • absoluteURL – An absolute URL that refers to the same resource as the receiver.
    • If the receiver is already absolute, returns self.
    • baseURL – The base URL of the receiver. If the receiver is an absolute URL, returns nil.
    • host – The host of the URL.
    • parameterString – The parameter string of the URL.
    • password – The password of the URL (i.e. http://user:pass@www.test.com would return pass)
    • path – Returns the path of a URL.
    • port – The port number of the URL.
    • query – The query string of the URL.
    • relativePath – The relative path of the URL without resolving against the base URL.
    •  If the receiver is an absolute URL, this method returns the same value as path.
    • relativeString – string representation of the relative portion of the URL.  If the receiver is an absolute URL this method returns the same value as absoluteString.
    • scheme – The resource specifier of the URL (i.e. http, https, file, ftp, etc).
    • user – The user portion of the URL.



    2. Objective-C에서 Javascript코드 호출

    - (NSString * _Nullable)stringByEvaluatingJavaScriptFromString:(NSString * _Nonnull)script

    이 메소드를 통해서 웹뷰에 로드된 페이지의 Javascript에 접근할 수 있습니다.

    사용법은 아래와 같습니다.



    //웹페이지의 타이틀 값 알아보기 <title>태그

    - (IBAction)btn1:(id)sender {

        NSString *title = [webview stringByEvaluatingJavaScriptFromString:@"document.title"]; 

        NSLog(@"Document Title : %@",title);

    }


    //웹페이지의 Javascript 메소드 실행하기

    - (IBAction)btn2:(id)sender {

        [webview stringByEvaluatingJavaScriptFromString:@"functionFromObjc()"]; 

        //Javascript에 구현되어 있는 functionFromObjc메소드가 실행됩니다.

    }









    샘플코드


    <!-- html파일 -->


    <html>

        <head>

            <meta charset="utf-8" />

            <title>테스트용 로컬 html문서</title>

            <script>

                var jsFuncFromObjc = function(){

                    alert("func1 is called.");

                }

            

                var objcFuncFromJS = function(){

                   window.location = "hybrid://objcFuncFromJS";

                }

            

                var sampleMethod = function(){

                    alert("method is called");

                }

            

                var changeDocument = function(){

                    var titleList = ["Hello world","Bye world"];


                    var title = document.getElementById("titleName");

                    var curTitle = title.innerText;

                    

                    if(curTitle == titleList[0]){

                        title.innerText = titleList[1];

                    } else{

                        title.innerText = titleList[0];

                    }

                }

            </script>

        </head>

        

        <body>

            <p>웹페이지</p>

            

            <p id="titleName">Hello world</p>

            <input type="button" value="버튼1" onClick="objcFuncFromJS()"/>

        </body>


    </html> 





    이 앱을 실행시킨 동영상

    찹쌀도우너츠전임스타일의 아날로그감성을 담아 직접촬영으로 올립니다.

    웹뷰는 빨간 테두리부분이고 아랫쪽 레이블은 네이티브입니다.





    댓글 5

    • 초보 2017.03.28 19:15

      안녕하세요! 글 설명을 넘 잘해놓으셔서 읽으면서 따라하다가 궁금한점이 생겨서 댓글 남겨봅니다..
      지금 제가 폰갭으로 하이브리드앱을 만들고있는데,
      javascript에서 objective-c의 메소드를 불러오려하는데, 아무리 클릭을 해도 shouldStartLoadWithRequest 이리로 넘어오질 못하더라구요..
      그러다가 찾아보니 코르도바 홈페이지의 도큐먼트에는 네이티브와 하이브리드 코드를 통신?하려면 인터페이스를 만들어야한다고 되어있더라구요,
      고무망치님께서는 하이브리드앱이 아니라 네이티브지만 웹뷰로 javascript를 사용하고있는경우가 맞는지요..?

      • 고무망치 2017.03.28 20:58 신고

        안녕하세요. 방문해주셔서 감사합니다~!
        네이티브에서 웹뷰로 javascript를 사용하고 있는 경우가 맞습니다.

        shouldStartLoadWithRequest가 호출되지 않는 이유는 webview의 delegate가 설정되어 있지 않기 때문으로 추정되는데요.

        혹시 샘플코드나 코드 전체를 제가 볼 수 있을까요?^^

    • 2017.03.29 09:15

      비밀댓글입니다

    • 2017.03.29 09:33

      비밀댓글입니다

Designed by Tistory.