iOS类微信返回导航WebViewController

yeliz 8年前
   <p>AXWebViewController 是一款易用的基于 UIWebView (20160716更新:iOS8.0以上使用 WKWebView 实现)封装的网页浏览控制器. 在系统功能的基础上添加了工具条导航,可以刷新、返回、前进、等操作,同时, AXWebViewController 还实现了 微信样式 的导航返回支持,集成简单,使用方便。如图所示:</p>    <p><img src="https://simg.open-open.com/show/1cb5414a020e467d410768fc20e5177e.gif"> <img src="https://simg.open-open.com/show/3dc6e0c7110ea68c6c199f877352250d.gif"></p>    <h2>特性</h2>    <ul>     <li>手势滑动返回上个网页</li>     <li>微信样式导航返回</li>     <li>网页加载失败提示(iOS8.0以下)</li>     <li>网页加载进度提示</li>     <li>网页来源提示</li>     <li>支持 <strong>Peek</strong> 和 <strong>Pop</strong> 浏览网页,并且commit之后在本网页进行加载,不用跳转到Safari进行浏览,这里使用到了很多运行时的方法,因此,在使用的过程中可能会抛异常。</li>    </ul>    <h2>要求</h2>    <p>AXWebViewController 对系统版本支持到iOS7.0,需要使用到:</p>    <ul>     <li>Foundation.framework</li>     <li>UIKit.framework</li>    </ul>    <p>使用的时候最好使用最新版Xcode。</p>    <h2>使用</h2>    <p>AXWebViewController 使用和使用普通 UIViewController 一样简单,只需要在需要使用的地方使用 URL 初始化即可:</p>    <pre>  <code class="language-objectivec">AXWebViewController *webVC = [[AXWebViewController alloc] initWithAddress:@"http://www.baidu.com"];  webVC.showsToolBar = NO;  webVC.navigationController.navigationBar.translucent = NO;  self.navigationController.navigationBar.tintColor = [UIColor colorWithRed:0.100f green:0.100f blue:0.100f alpha:0.800f];  self.navigationController.navigationBar.barTintColor = [UIColor colorWithRed:0.996f green:0.867f blue:0.522f alpha:1.00f];  [self.navigationController pushViewController:webVC animated:YES];</code></pre>    <h3>使用工具条导航</h3>    <p>使用工具条只需在 AXWebViewController 初始化之后加入一句代码:</p>    <pre>  <code class="language-objectivec">webVC.navigationType = AXWebViewControllerNavigationToolItem;  webVC.showsToolBar = YES;</code></pre>    <p>注意,在设置 navigationType 为 AXWebViewControllerNavigationToolItem 之后,须确认 showsToolBar 为 YES 才能生效.</p>    <h3>使用微信样式导航</h3>    <p>在 AXWebViewController 初始化之后加入一句代码:</p>    <pre>  <code class="language-objectivec">webVC.navigationType = AXWebViewControllerNavigationBarItem;</code></pre>    <p>即可生效.</p>    <h3>Peek&Pop</h3>    <p>Peek和Pop使用的是原生的系统功能,在使用的时候只需要将 webView.allowsLinkPreview 设置为 YES 即可使用,这里需要注意下,在实现Peek和Pop的时候,使用了Runtime的相关知识,而且使用AOP的一个框架 <strong> <a href="/misc/goto?guid=4959630207627933220" rel="nofollow,noindex">Aspects</a> </strong> 进行了编程,在使用的过程中可能会出错,当然,出错的几率也是很小的(苹果不可能隔三差五的去修改自家的Private API吧= =),实现原理就不多讲了,基本上就是运行时的一些知识,代码如下:</p>    <pre>  <code class="language-objectivec">- (void)hookWebContentCommitPreviewHandler {      // Find the `WKContentView` in the webview.      __weak typeof(self) wself = self;      for (UIView *_view in _webView.scrollView.subviews) {      if ([_view isKindOfClass:NSClassFromString(@"WKContentView")]) {      id _previewItemController = object_getIvar(_view, class_getInstanceVariable([_view class], "_previewItemController"));      Class _class = [_previewItemController class];      SEL _performCustomCommitSelector = NSSelectorFromString(@"previewInteractionController:interactionProgress:forRevealAtLocation:inSourceView:containerView:");      [_previewItemController aspect_hookSelector:_performCustomCommitSelector withOptions:AspectPositionAfter usingBlock:^() {          UIViewController *pred = [_previewItemController valueForKeyPath:@"presentedViewController"];          [pred aspect_hookSelector:NSSelectorFromString(@"_addRemoteView") withOptions:AspectPositionAfter usingBlock:^() {              UIViewController *_remoteViewController = object_getIvar(pred, class_getInstanceVariable([pred class], "_remoteViewController"));                [_remoteViewController aspect_hookSelector:@selector(viewDidLoad) withOptions:AspectPositionAfter usingBlock:^() {                  _remoteViewController.view.tintColor = wself.navigationController.navigationBar.tintColor;              } error:NULL];          } error:NULL];            NSArray *ddActions = [pred valueForKeyPath:@"ddActions"];          id openURLAction = [ddActions firstObject];            [openURLAction aspect_hookSelector:NSSelectorFromString(@"perform") withOptions:AspectPositionInstead usingBlock:^ () {              NSURL *_url = object_getIvar(openURLAction, class_getInstanceVariable([openURLAction class], "_url"));              [wself loadURL:_url];          } error:NULL];            id _lookupItem = object_getIvar(_previewItemController, class_getInstanceVariable([_class class], "_lookupItem"));          [_lookupItem aspect_hookSelector:NSSelectorFromString(@"commit") withOptions:AspectPositionInstead usingBlock:^() {              NSURL *_url = object_getIvar(_lookupItem, class_getInstanceVariable([_lookupItem class], "_url"));              [wself loadURL:_url];          } error:NULL];          [_lookupItem aspect_hookSelector:NSSelectorFromString(@"commitWithTransitionForPreviewViewController:inViewController:completion:") withOptions:AspectPositionInstead usingBlock:^() {              NSURL *_url = object_getIvar(_lookupItem, class_getInstanceVariable([_lookupItem class], "_url"));              [wself loadURL:_url];          } error:NULL];          /*           UIWindow           -UITransitionView           --UIVisualEffectView           ---_UIVisualEffectContentView           ----UIView           -----_UIPreviewActionSheetView           */          /*           for (UIView * transitionView in [UIApplication sharedApplication].keyWindow.subviews) {           if ([transitionView isMemberOfClass:NSClassFromString(@"UITransitionView")]) {           transitionView.tintColor = wself.navigationController.navigationBar.tintColor;           for (UIView *__view in transitionView.subviews) {           if ([__view isMemberOfClass:NSClassFromString(@"UIVisualEffectView")]) {           for (UIView *___view in __view.subviews) {           if ([___view isMemberOfClass:NSClassFromString(@"_UIVisualEffectContentView")]) {           for (UIView *____view in ___view.subviews) {           if ([____view isMemberOfClass:NSClassFromString(@"UIView")]) {           __weak typeof(____view) w____view = ____view;           [____view aspect_hookSelector:@selector(addSubview:) withOptions:AspectPositionAfter usingBlock:^() {           for (UIView *actionSheet in w____view.subviews) {           if ([actionSheet isMemberOfClass:NSClassFromString(@"_UIPreviewActionSheetView")]) {           break;           }           }           } error:NULL];           }           }break;           }           }break;           }           }break;           }           }           */      } error:NULL];      break;      }      }  }</code></pre>    <p> </p>