IT_Programming/Objective-C · Swift · iOS

[iOS] 팝업 윈도우를 UIWebView에서 사용하기

JJun ™ 2010. 8. 30. 19:28



 출처: http://egloos.zum.com/saveworld/v/2828855




이 글은 아래에 링크 걸려있는 블로그의 내용을 번역한 내용입니다.


この文書は下のリンク先のブログの内容を翻訳したものです。

http://niw.at/articles/2009/02/06/how-to-enable-the-popup-window-on-uiwebview/ja

번역이 매끄럽지 못한 점, 죄송합니다..;; 


UIWebView는 iPhone SDK에서 꽤 중요한 UIKit 클래스입니다.
알고 계신대로 사파리가 통째로 들어있지만, 윈도우를 열거나 팝업 등의 이벤트는 처리되지 않도록 되어 있습니다.

<a href="somehere" target="_blank" />Open this link in new window</a>


예를 들면, 이러한 링크가 UIWebView 안에 표시되어 유저가 클릭했다고 해도 아무런 동작을 하지 않습니다.
물론, UIWebView는 상당히 고도로 추상화되어 있고, 몇가지 메소드를 호출하는 것은 가능합니다.

그래서 완벽하지는 않지만 어느정도 이 문제를 해결 할 방법을 제공합니다. 열쇠가 되는 메소드는 다음과 같습니다.

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
- (void)webViewDidFinishLoad:(UIWebView *)webView
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script

 


모든 팝업 윈도우를 가로채기


먼저 표시하고 있는 웹페이지의 모든 윈도우를 여는 이벤트를 가로챕니다. 방법은 JavaS-ript로 해결합니다.
먼저 모든 새 윈도우 열기 이벤트를 가로채서 열어야하는 URL을 특정화 하고, 그곳에 Objective-C 쪽에서 그 특정화 한 URL을 재처리하여
자신이 윈도우를 엽니다.

- (void)webViewDidFinishLoad:(UIWebView *)webView {
  [webView stringByEvaluatingJavaScriptFromString:/* JavaScriptの入った文字列 */];
}


다음의 JavaScript를 stringByEvaluatingJavaScriptFromString에 넘깁니다.

var tags = document.getElementsByTagName("a");
for(var i=0; i < tags.length; i++) {
  var tag = tags[i];
  var t = tag.getAttribute("target");
  var h = tag.getAttribute("href");
  if(/* targetとhrefを確認 */) {
    tag.setAttribute("target", "");
    tag.setAttribute("href", /* href属性から特別なURLを作成 */);
  }
}


webViewDidFinishLoad가 호출되었을 때에 JavaScript를 샐행하여 모든 anchor 태그를 가로채어 타겟 속성을 삭제하고
href에 특정화 시킨 URL으로 치환합니다. 다시 폼과 JavaScript로부터 이벤트를 가로챕니다.

var tags = document.getElementsByTagName("form");
for(var i=0; i < tags.length; i++) {
  var tag = tags[i];
  var submit = tag.submit;
  tag.submit = function() {
    var t = tag.target;
    var a = tag.action;
    if(/* targetとactionを確認 */) {
      tag.target = "";
      tag.action = /* action属性から特別なURLを作成  */
    }
    return submit.apply(this, arguments);
  };
}


このコードは多くの状況で動くのですが、すべての状況での動作は難しいです。特にsumitイベントのリスナーが存在する場合などです。


window.open = function(url) {
  if(/* urlを確認 */) {
    var t = document.createElement("a");
    t.setAttribute("href", /* 特別なurlを作成 */);
    var e = document.createEvent("MouseEvent");
    e.initMouseEvent("click");
    t.dispatchEvent(e);
  }
};


이 코드는 상당히 이상한 코드입니다.
window.open이 호출 될 때에 화면 뒤 쪽에서 보이지 않는 anchor 태그를 만들어 그것에 특별한 URL을 설정하여 HTTP Request를 발생시킵니다.
이 Request를 Objective-C 쪽에서 받습니다.


팝업 이벤트를 Objective-C에서 받기


이것으로 Objective-C 쪽에서 이벤트를 받을 수 있게 되었습니다. UIWebView의 delegate에서 팝업 이벤트를 받아 처리합니다.

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
  if(navigationType == UIWebViewNavigationTypeLinkClicked || navigationType == UIWebViewNavigationTypeFormSubmitted) {
    NSURL *url = [request URL];
    if(/* URLが特別なものか確認 */) {
      NSString *urlstr = /* 特別なURLから普通のURLに戻す */;
      NSMutableURLRequest *req = [request mutableCopyWithZone:nil];
      [req setURL:[NSURL URLWithString:urlstr]];
      if(/* ポップアップは閉じているか? */) {
        /* ポップアップを開く */
      }
      [popupWebView loadRequest:req];
      return NO;
    }
  }
  return YES;
}

이 아주 긴 이름의 delegate로 모든 HTTP Request를 취득할 수 있습니다. 먼저 Request의 URL가 JavaScript로 만든 특정화 시킨 것인가를 체크하여 
만약 그렇다면 보통의 URL을 반환하여 NSURLRequest를 작성하고, 팝업으로 띄울 UIWebView로 넘깁니다. 이 들 코드에 의해서 UIWebView로 팝업을
구현할 수 있습니다.

 


특별한 URL을 작성

이 문제는 조금 어렵습니다. 왜냐하면, HTTP Request의 베이스 URL을 보유하고 있을 필요가 있기 때문입니다.
URL을 바꿔 쓰더라도 안전한 부분, 예를 들면 스키마나 호스트명 등입니다만, 이것들을 바꿔쓰면 베이스 URL을 잃어버려
webView:shouldStartLoadWithRequest:navigationType에서 팝업을 위한 URL을 작성할 수 없게 되버립니다.

그렇기 때문에 한가지 대안으로 URL의 마지막에 특별한 Hash를 부여하는 것으로 일단 해결해보겠습니다.
그다지 안전하지는 않지만 대부분의 상황에서는 안전합니다.

function makeSpecialURL(url) {
  return url + (url.match(/#/) ? "_open" : "#open");
}


그리고 webView:shouldStartLoadWithRequest:navigationType에서 추가한 Hash를 삭제합니다.

if([[url fragment] hasSuffix:@"open"]) {
  NSString *urlstr = [[url absoluteString] substringToIndex:[[url absoluteString] length] - 5];
  ...
}

 



그 밖의 방법에 대해서


이 문제는 아마도 문서에 포함되지 않은 API나 delegate(webView:createWebViewWithRequest:)로 해결 할 수 있을겁니다.
하지만 iPhone SDK에서는 이 JavaScript를 사용하는 방법 이외에는 해결 방법이 없겠지요. 별로 좋은 구현방법은 아니지만,
iPhone 어플리케이션 제작에 도움이 되면 좋겠다고 생각합니다.


출처 : http://passion818.tistory.com/entry/팝업-윈도우를-UIWebView에서-사용하기