Created
September 3, 2017 15:20
-
-
Save oozoofrog/003b7ec6633b64167dd959abe03012e3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// WKWebView+Rx.swift | |
// RxGround | |
// | |
// Created by eyemac on 2017. 9. 2.. | |
// Copyright © 2017년 rollmind. All rights reserved. | |
// | |
import WebKit | |
import RxSwift | |
import RxCocoa | |
public class RxWKNavigationDelegateProxy | |
: DelegateProxy | |
, DelegateProxyType | |
, WKNavigationDelegate { | |
/// For more information take a look at `DelegateProxyType`. | |
public override class func createProxyForObject(_ object: AnyObject) -> AnyObject { | |
guard let webView: WKWebView = object as? WKWebView else { fatalError() } | |
return webView.createRxNavigationDelegateProxy() | |
} | |
/// For more information take a look at `DelegateProxyType`. | |
public class func setCurrentDelegate(_ delegate: AnyObject?, toObject object: AnyObject) { | |
guard let webView: WKWebView = object as? WKWebView else { fatalError() } | |
webView.navigationDelegate = delegate as? WKNavigationDelegate | |
} | |
/// For more information take a look at `DelegateProxyType`. | |
public class func currentDelegateFor(_ object: AnyObject) -> AnyObject? { | |
guard let webView: WKWebView = object as? WKWebView else { fatalError() } | |
return webView.navigationDelegate | |
} | |
} | |
public class RxWKUIDelegateProxy | |
: DelegateProxy | |
, DelegateProxyType | |
, WKUIDelegate { | |
/// For more information take a look at `DelegateProxyType`. | |
public override class func createProxyForObject(_ object: AnyObject) -> AnyObject { | |
guard let webView: WKWebView = object as? WKWebView else { fatalError() } | |
return webView.createRxUIDelegateProxy() | |
} | |
/// For more information take a look at `DelegateProxyType`. | |
public class func setCurrentDelegate(_ delegate: AnyObject?, toObject object: AnyObject) { | |
guard let webView: WKWebView = object as? WKWebView else { fatalError() } | |
webView.uiDelegate = delegate as? WKUIDelegate | |
} | |
/// For more information take a look at `DelegateProxyType`. | |
public class func currentDelegateFor(_ object: AnyObject) -> AnyObject? { | |
guard let webView: WKWebView = object as? WKWebView else { fatalError() } | |
return webView.uiDelegate | |
} | |
} | |
extension WKWebView { | |
public func createRxNavigationDelegateProxy() -> RxWKNavigationDelegateProxy { | |
return RxWKNavigationDelegateProxy(parentObject: self) | |
} | |
public func createRxUIDelegateProxy() -> RxWKUIDelegateProxy { | |
return RxWKUIDelegateProxy(parentObject: self) | |
} | |
} | |
extension Reactive where Base: WKWebView { | |
public var navigationDelegate: RxWKNavigationDelegateProxy { | |
return RxWKNavigationDelegateProxy.proxyForObject(base) | |
} | |
public var uiDelegate: RxWKUIDelegateProxy { | |
return RxWKUIDelegateProxy.proxyForObject(base) | |
} | |
//MARK: - WKNavigationDelegate | |
public var didStartProvisionalNavigation: Observable<Void> { | |
return self.navigationDelegate | |
.methodInvoked(#selector(WKNavigationDelegate.webView(_:didStartProvisionalNavigation:))) | |
.map { _ in } | |
} | |
public var didFinish: Observable<Void> { | |
return self.navigationDelegate | |
.methodInvoked(#selector(WKNavigationDelegate.webView(_:didFinish:))) | |
.map { _ in } | |
} | |
public var didFail: Observable<Void> { | |
return self.navigationDelegate | |
.methodInvoked(#selector(WKNavigationDelegate.webView(_:didFail:withError:))) | |
.map { args in throw args[2] as! Error } | |
} | |
public var didFailProvisionalNavigation: Observable<Void> { | |
return self.navigationDelegate | |
.methodInvoked(#selector(WKNavigationDelegate.webView(_:didFailProvisionalNavigation:withError:))) | |
.map { args in throw args[2] as! Error } | |
} | |
public var didTerminateWebContentProcess: Observable<Void> { | |
return self.navigationDelegate | |
.methodInvoked(#selector(WKNavigationDelegate.webViewWebContentProcessDidTerminate(_:))) | |
.map { _ in } | |
} | |
public typealias ActionPolicyHandle = @convention(block) (WKNavigationActionPolicy) -> Void | |
public var decideActionPolicy: Observable<(WKNavigationAction, ActionPolicyHandle)> { | |
return self.navigationDelegate | |
.methodInvoked(NSSelectorFromString("webView:decidePolicyForNavigationAction:decisionHandler:")) | |
.map { args in | |
return (self.cast(args[1]), self.castPointer(args[2])) } | |
} | |
public typealias ResponsePolicyHandle = @convention(block) (WKNavigationResponsePolicy) -> Void | |
public var decideResponsePolicy: Observable<(WKNavigationResponse, ResponsePolicyHandle)> { | |
return self.navigationDelegate | |
.methodInvoked(NSSelectorFromString("webView:decidePolicyForNavigationResponse:decisionHandler:")) | |
.map { args in | |
return (self.cast(args[1]), self.castPointer(args[2])) | |
} | |
} | |
public var didCommit: Observable<Void> { | |
return self.navigationDelegate | |
.methodInvoked(#selector(WKNavigationDelegate.webView(_:didCommit:))) | |
.map { _ in } | |
} | |
public var didReceiveServerRedirectForProvisionalNavigation: Observable<Void> { | |
return self.navigationDelegate | |
.methodInvoked(#selector(WKNavigationDelegate.webView(_:didReceiveServerRedirectForProvisionalNavigation:))) | |
.map { _ in } | |
} | |
public typealias AuthChallengeCompletionHandler = @convention(block) (URLSession.AuthChallengeDisposition, URLCredential?) -> Void | |
public var didReceive: Observable<(URLAuthenticationChallenge, AuthChallengeCompletionHandler)> { | |
return self.navigationDelegate | |
.methodInvoked(#selector(WKNavigationDelegate.webView(_:didReceive:completionHandler:))) | |
.map { args in | |
return (self.cast(args[1]), self.castPointer(args[2])) | |
} | |
} | |
//MARK: - WKUIDelegate | |
// public var createWebView: Observable<WKWebView> { | |
// return self.uiDelegate | |
// .methodInvoked(#selector(WKUIDelegate.webView(_:createWebViewWith:for:windowFeatures:))) | |
// .map { args in | |
// guard let configuration: WKWebViewConfiguration = args[1] as? WKWebViewConfiguration else { fatalError() } | |
// guard let action: WKNavigationAction = args[2] as? WKNavigationAction else { fatalError() } | |
// let webView = WKWebView(frame: .zero, configuration: configuration) | |
// webView.load(action.request) | |
// return webView | |
// } | |
// } | |
// public var closeWebView: Observable<WKWebView> { | |
// return self.uiDelegate | |
// .methodInvoked(#selector(WKUIDelegate.webViewDidClose(_:))) | |
// .map { args in self.cast(args[1]) } | |
// } | |
// public typealias CompletionHandlerWithNoArguments = () -> Void | |
// public typealias JavaScriptAlertPanelValues = (message: String, frame: WKFrameInfo, completionHandler: CompletionHandlerWithNoArguments) | |
// public var runJavaScriptAlertPanel: Observable<JavaScriptAlertPanelValues> { | |
// return self.uiDelegate | |
// .methodInvoked(#selector(WKUIDelegate.webView(_:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:))) | |
// .map { args in JavaScriptAlertPanelValues(self.cast(args[1]), self.cast(args[2]), self.castPointer(args[3])) } | |
// } | |
// | |
// public var addWebView: UIBindingObserver<Base, WKWebView> { | |
// return UIBindingObserver(UIElement: base, binding: { (base, newWebView) in | |
// newWebView.frame = base.bounds | |
// newWebView.autoresizingMask = [.flexibleWidth, .flexibleHeight] | |
// base.addSubview(newWebView) | |
// }) | |
// } | |
// | |
// public var removeWebView: UIBindingObserver<Base, WKWebView> { | |
// return UIBindingObserver(UIElement: base, binding: { (_, newWebView) in | |
// if newWebView.superview != nil { | |
// newWebView.removeFromSuperview() | |
// } | |
// }) | |
// } | |
} | |
extension WKNavigationType: CustomStringConvertible { | |
public var description: String { | |
switch self { | |
case .backForward: return "backForward" | |
case .formResubmitted: return "formResubmitted" | |
case .formSubmitted: return "formSubmitted" | |
case .linkActivated: return "linkActivated" | |
case .other: return "other" | |
case .reload: return "reload" | |
} | |
} | |
} | |
extension Reactive { | |
public func castPointer<T>(_ any: Any) -> T { | |
let block = any as AnyObject | |
let ptr = UnsafeRawPointer(Unmanaged<AnyObject>.passUnretained(block).toOpaque()) | |
let casted = unsafeBitCast(ptr, to: T.self) | |
return casted | |
} | |
public func cast<T>(_ any: Any) -> T { | |
guard let casted: T = any as? T else { fatalError() } | |
return casted | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment