рдкреЙрдб рд╡реЗрдмрд▓реЙрдЧрд┐рди рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдЖрдИрдУрдПрд╕ 10 рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рд╕рдВрдХрд▓рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ред
рдЬрдм рдореИрдВ рдЖрдИрдУрдПрд╕ рдХреЗ 11.0 рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдмрджрд▓рддрд╛ рд╣реВрдВ рддреЛ рдпрд╣ рдХрд╣рддрд╛ рд╣реИ:
InstagramLoginWebView
рдЧреБрдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВредInstagramLoginWebViewProtocol
рдХреНрд▓реЛрдЬрд░ рдкреНрд░реЙрдкрд░реНрдЯреАрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВредрдЬрдм рдореИрдВрдиреЗ InstagramLoginWebViewDelegate рдХреЛ InstagramLoginWebViewProtocol рдореЗрдВ рдмрджрд▓ рджрд┐рдпрд╛:
рдореЗрд░реЗ рдХреЛрдб:
рдХреНрд▓рд╛рд╕ рд▓реЙрдЧ рдЗрди рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░: UIViewController {
var loginWebView: InstagramLoginWebView! = nil
override func viewDidLoad() {
super.viewDidLoad()
loginWebView = InstagramLoginWebView(frame: self.view.frame)
self.view.addSubview(loginWebView!)
loginWebView?.loginDelegate = self **-- Cannot assign value of type 'LoginViewController' to type 'InstagramLoginWebViewDelegate?'**
self.loginWebView?.loadInstagramLogin(isNeedPreloadForCookieSync: true) **--Argument passed to call that takes no arguments**
}
}
рдПрдХреНрд╕рдЯреЗрдВрд╢рди LoginViewController: InstagramLoginWebViewProtocol { --'InstagramLoginWebViewProtocol' рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ 'LoginViewController' рдХреЛ 'UIView' рд╕реЗ рдЗрдирд╣реЗрд░рд┐рдЯ рдХрд┐рдпрд╛ рдЬрд╛рдП
func userLoggedSuccessfully() {
print("User Logged Successfully")
DispatchQueue.main.async {
self.loginWebView.removeFromSuperview()
}
}
рдЕрд░реЗ @effecttwins
InstagramLoginWebView
рдкрд┐рдЫрд▓реЗ рдЕрдкрдбреЗрдЯ рдореЗрдВ рдмрд╣реБрдд рдмрджрд▓ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдЕрд╕рдВрдЧрддрд┐ рдХреЗ рдХрд╛рд░рдг iOS 10.*
рд▓рд┐рдП рд╕рдорд░реНрдерди
loginDelegate
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдЕрдм рд╕реБрдЭрд╛рд╡ рдирд╣реАрдВ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рдЕрднреА рднреА рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд╣реИред
рдЖрдк рдЬрд┐рд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рдЖрджреА рд╣реИрдВ, рдЙрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдЕрдкрдиреЗ loginWebView
рдкрд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЧреБрдг рд╕реЗрдЯ рдХрд░рдирд╛ рд╣реИ:
didReachEndOfLoginFlow
рдПрдХ _рдХреНрд▓реЛрдЬрд░_ рд╣реИ рдЬрд┐рд╕реЗ redirected
рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИредdidSuccessfullyLogIn
_delegate_ рдХреЗ userLoggedSuccessfully()
рдХреА рдЬрдЧрд╣ рдПрдХ _рдХреНрд▓реЛрдЬрд░_ рд╣реИредcompletionHandler
, _delegate_ рдХреЗ webViewFinishedToLoadUser(sessionChache:handler:)
рдХреА рдЬрдЧрд╣ рдПрдХ _рдХреНрд▓реЛрдЬрд░_ рд╣реИрдпрд╣ 1.7.*
рдХреЗ рд▓рд┐рдП рдЕрджреНрдпрддрди рдХреЛрдб рд╣реИред
class LoginViewController: UIViewController {
var loginWebView: InstagramLoginWebView!
override func viewDidLoad() {
super.viewDidLoad()
loginWebView = InstagramLoginWebView(frame: self.view.frame,
didSuccessfullyLogIn: { [weak self] in DispatchQueue.main.async { self?.loginWebView.removeFromSuperview() }},
completionHandler: { sessionCache, handler in /* do whaterver you need to */ })
view.addSubview(loginWebView)
loginWebView.loadInstagramLogin()
}
}
рдЗрд╕рд▓рд┐рдП рдЬрдм рдореИрдВ рдПрдХреНрд╕рдЯреЗрдВрд╢рди InstagramLoginWebViewDelegate рдХреЛ InstagramLoginWebViewProtocol рдореЗрдВ рдмрджрд▓рддрд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рдХрд╣рддрд╛ рд╣реИ: 'InstagramLoginWebViewProtocol' рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ 'LoginViewController' 'UIView' рд╕реЗ рдкреНрд░рд╛рдкреНрдд рд╣реЛред
рдХреЛрдб:
рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд▓реЙрдЧрд┐рди рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░: InstagramLoginWebViewDelegate {
func userLoggedSuccessfully() {
print("User Logged Successfully")
}
func webViewFinishedToLoadUser(sessionCache: SessionCache, handler: APIHandlerProtocol) {
print("Loading user with sessioncache is successful")
do{
let encoder = JSONEncoder()
let data = try encoder.encode(sessionCache)
let sessionCacheString = String(data: data, encoding: .utf8)
}catch {
print("Whoops, an error occured: \(error)")
}
}
рдЖрдкрдХреЛ рдХрднреА рднреА InstagramLoginWebViewProtocol
рдЕрдиреБрд░реВрдк рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЗрд╕реЗ internal
рдЪрд┐рд╣реНрдирд┐рдд рдирд╣реАрдВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЗрд░реА рдЧрд▓рддреА рд╣реИред рдореИрдВ рдХреНрд╖рдорд╛рдкреНрд░рд╛рд░реНрдереА рд╣реВрдВред
рдпрд╣ рд╡рд╣ рд╕рдм рдХреЛрдб рд╣реИ рдЬрд┐рд╕рдХреА рдЖрдкрдХреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдирд╣реАрдВ InstagramLoginWebViewProtocol
ред рдирд╣реАрдВ InstagramLoginWebViewDelegate
ред
import UIKit
import SwiftyInsta
class LoginViewController: UIViewController {
var loginWebView: InstagramLoginWebView!
override func viewDidLoad() {
super.viewDidLoad()
loginWebView = InstagramLoginWebView(frame: view.frame,
didReachEndOfLoginFlow: nil,
didSuccessfullyLogIn: { [weak self] in
// I would actually put this in `didReachEndOfLoginFlow`,
// so the user never sees their timeline blinking.
DispatchQueue.main.async {
self?.loginWebView.removeFromSuperview()
}
},
completionHandler: { sessionCache, _ in
print("Loading user with sessioncache is successful")
do {
let encoder = JSONEncoder()
let data = try encoder.encode(sessionCache)
let sessionCacheString = String(data: data, encoding: .utf8)
} catch {
print("Whoops, an error occured: \(error)")
}
})
view.addSubview(loginWebView)
loginWebView.loadInstagramLogin()
}
}
@sbertix рдЖрдкрдХреА рд╕рднреА рдорджрдж рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред
рд▓реЗрдХрд┐рди рдЗрдВрд╕реНрдЯрд╛рдЧреНрд░рд╛рдо рд▓реЙрдЧрд┐рди рдкреЗрдЬ рд▓реЛрдб рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ, рд╕реНрдХреНрд░реАрди рдореЗрдВ рдХреЗрд╡рд▓ рд╕рдлреЗрдж рдкреЗрдЬ рд╣реИ
рдпрд╣ рд╡рд╣ рд╕рдм рдХреЛрдб рд╣реИ рдЬрд┐рд╕рдХреА рдЖрдкрдХреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдирд╣реАрдВ
InstagramLoginWebViewProtocol
ред рдирд╣реАрдВInstagramLoginWebViewDelegate
ред
@effecttwins рдореЗрд░реЗ рджреНрд╡рд╛рд░рд╛ рдКрдкрд░ рд▓рд┐рдЦреЗ рдЧрдП рдХреЛрдб рдХреЛ рдХреЙрдкреА рдФрд░ рдкреЗрд╕реНрдЯ рдХрд░реЗрдВред loadInstagramLogin()
рдкрд░ рдХреЙрд▓ рдХрд░рдирд╛ рди рднреВрд▓реЗрдВред
рдпрд╣ рд╕рдЪрдореБрдЪ рдЖрдкрдХреЗ рд▓рд┐рдП рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд▓рд╛рдЧреВ рд╣реИ
рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИрдВ
рд╣рд╛рдБ рдореИрдВрдиреЗ рд╕рднреА рдХреЛрдб рдХреЙрдкреА рдФрд░ рдкреЗрд╕реНрдЯ рдХрд┐рдпрд╛ рдФрд░ рд▓реЛрдбрдЗрдВрд╕реНрдЯрд╛рдЧреНрд░рд╛рдорд▓реЙрдЧрд┐рди рдХрд╣рд╛ :)
InstagramLoginWebViewProtocol рдФрд░ InstagramLoginWebViewDelegate рдХреЛ рднреА рд╣рдЯрд╛ рджрд┐рдпрд╛ рд╣реИ
рдХрдВрд╕реЛрд▓ рдореЗрдВ рдореБрдЭреЗ рдпрд╣ рддреНрд░реБрдЯрд┐ рдорд┐рд▓ рд░рд╣реА рд╣реИ, рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрд╣ рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИ рдпрд╛ рдирд╣реАрдВ
рд╕реЗрд╡рд╛ рд╕рдВрдХреЗрдд рдирд╣реАрдВ рдХрд░ рд╕рдХрд╛ com.apple.WebKit.Networking: 113: рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕реЗрд╡рд╛ рдирд╣реАрдВ рдорд┐рд▓ рд╕рдХрд╛
рдХреНрд╖рдорд╛ рдХрд░реЗрдВ, рдореИрдВрдиреЗ рдЕрдкрдиреЗ рдХреЛрдб рд╣рд╛рд╣рд╛рд╣рд╛ рдореЗрдВ loginWebView
рдХреЛ view
рдореЗрдВ рдХрднреА рдирд╣реАрдВ рдЬреЛрдбрд╝рд╛ рд╣реИ
рдореИрдВрдиреЗ рдЗрд╕реЗ рд╕рдВрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рд╣реИред рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рдЬрд╛рдВрдЪреЗрдВред рдЗрд╕реЗ рдЕрдм рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП @effecttwins
рдЖрдк рдХрдорд╛рд▓ рд╣реИрдВ @sbertix
рдпрд╣ рдЕрдм рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ
рдЖрдк рд╕рднреА рдХреА рдорджрдж рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж
рдЕрд░реЗ @sbertix
рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ рдореИрдВ рдПрдорд╡реАрд╡реАрдПрдо рдкреИрдЯрд░реНрди рдХрд╛ рдкрд╛рд▓рди рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдореЗрд░рд╛ рд╡рд┐рдЪрд╛рд░ рдФрд░ рдореЗрд░рд╛ рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдлрд╛рдЗрд▓реЛрдВ рдореЗрдВ рд╣реИ? рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреЛ рдбреЗрдЯрд╛ рдирд╣реАрдВ рднреЗрдЬрдирд╛ рдЪрд╛рд╣рд┐рдПред рдХреНрдпрд╛ InstagramLoginWebView рдХреЗ рдкреНрд░рд╛рд░рдВрдн рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж didSuccessfullyLogIn
рдлрд╝рдВрдХреНрд╢рди рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рд╣реИ?
рдЖрдкрдХреЛ init
InstagramLoginWebView
рд╕рд╛рде didSuccessfullyLogIn
(рдпрд╣ рд╡реИрдХрд▓реНрдкрд┐рдХ рд╣реИ) рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред
рдФрд░ рдЕрдиреНрдп _рдХреНрд▓реЛрдЬрд░_ рдХреЗ рд╕рд╛рде рднреА: рдПрдХ рдмрд╛рд░ рдЖрдкрдХреЗ рдкрд╛рд╕ рдПрдХ рдЕрд▓рдЧ рдорд╛рди рдЕрд╕рд╛рдЗрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
@anonrig
рдХреНрдпрд╛ рдЖрдк рдЗрд╕рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЕрдЧрд░ рдореИрдВ рдкреВрдЫ рд╕рдХрддрд╛ рд╣реВрдБ? @sbertix :)
рдЬрд╝рд░реВрд░ред рдХреНрдпрд╛ рдЖрдк рдЕрдкрдиреЗ рдХреЛрдб рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рднреЗрдЬ рд╕рдХрддреЗ рд╣реИрдВ? рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрд┐рд╕ рддрд░рд╣ рд╕реЗ рдЖрдкрдХрд╛ рдореЙрдбрд▓ рдФрд░ рджреГрд╢реНрдп рд╕реЗрдЯрдЕрдк рд╣реИред
рд╣рд╛рдБ рдмреЗрд╢рдХ!
1.7.x рд╕реЗ рдкрд╣рд▓реЗ рдореИрдВ delegates
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ ViewController рд╕реНрддрд░ рдкрд░ рд▓реЙрдЧрд┐рди рд╕рдлрд▓рддрд╛ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рд╕рдВрднрд╛рд▓ рд░рд╣рд╛ рдерд╛
рдЙрджрд╛рд╣рд░рдг рджреГрд╢реНрдп:
final class LoginWebView: UIView {
// MARK: - Properties
var bag = DisposeBag()
private(set) lazy var webView: InstagramLoginWebView = InstagramLoginWebView(frame: UIScreen.main.bounds)
private(set) lazy var closeButtonLabel: UILabel = {
let label: UILabel = .create(text: "Close".localized(), numberOfLines: 1, textAlignment: .center, textColor: .white, font: .light(size: 16))
label.isUserInteractionEnabled = true
return label
}()
private(set) lazy var closeButtonBarItem: UIBarButtonItem = UIBarButtonItem(customView: closeButtonLabel)
// MARK: - Initialization
init() {
super.init(frame: .zero)
[webView].forEach(addSubview(_:))
webView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
рдЙрджрд╛рд╣рд░рдг рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░:
final class LoginWebViewController: UIViewController, View, ErrorDisplayer {
// MARK: - Properties
private lazy var viewSource = LoginWebView()
private(set) var bag: DisposeBag
private(set) var viewModel: LoginWebViewModel
private(set) var completionObservable = PublishSubject<(SessionCache?, APIHandlerProtocol?)?>()
// MARK: - Initialization
init() {
bag = DisposeBag()
viewModel = LoginWebViewModel()
super.init(nibName: nil, bundle: nil)
bindErrorHandling()
observeDatasource()
}
// MARK: - Life cycle
override func loadView() {
view = viewSource
view.backgroundColor = .white
}
override func viewDidLoad() {
super.viewDidLoad()
viewSource.webView.loginDelegate = self
viewSource.webView.loadInstagramLogin(isNeedPreloadForCookieSync: true)
// viewSource.webView.didSuccessfullyLogIn
configureNavBar(with: "Login".localized(), prefersLargeTitle: false)
navigationItem.rightBarButtonItem = viewSource.closeButtonBarItem
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
рдореИрдВ рдареАрдХ рд╕реЗ рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рдХрд┐ LoginWebViewModel
рд╣реИ... рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЙрджреНрджреЗрд╢реНрдп рд╕рдм рдХреБрдЫ completeObservable
рддреЛ рдЖрдк рдмрд╕ рдпрд╣ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
final class LoginWebView: UIView {
// MARK: - Properties
var bag = DisposeBag()
private(set) lazy var webView: InstagramLoginWebView = InstagramLoginWebView(frame: UIScreen.main.bounds, completionHandler: nil)
private(set) lazy var closeButtonLabel: UILabel = {
let label: UILabel = .create(text: "Close".localized(), numberOfLines: 1, textAlignment: .center, textColor: .white, font: .light(size: 16))
label.isUserInteractionEnabled = true
return label
}()
private(set) lazy var closeButtonBarItem: UIBarButtonItem = UIBarButtonItem(customView: closeButtonLabel)
// MARK: - Initialization
init() {
super.init(frame: .zero)
[webView].forEach(addSubview(_:))
webView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
final class LoginWebViewController: UIViewController, View, ErrorDisplayer {
// MARK: - Properties
private lazy var viewSource = LoginWebView()
private(set) var bag: DisposeBag
private(set) var viewModel: LoginWebViewModel
private(set) var completionObservable = PublishSubject<(SessionCache?, APIHandlerProtocol?)?>()
// MARK: - Initialization
init() {
bag = DisposeBag()
viewModel = LoginWebViewModel()
super.init(nibName: nil, bundle: nil)
bindErrorHandling()
observeDatasource()
}
// MARK: - Life cycle
override func loadView() {
view = viewSource
view.backgroundColor = .white
}
override func viewDidLoad() {
super.viewDidLoad()
viewSource.webView.completionHandler = { [weak self] cache, handler in
self?.completionObservable.accept((cache, handler))
}
viewSource.webView.loadInstagramLogin()
// viewSource.webView.didSuccessfullyLogIn
configureNavBar(with: "Login".localized(), prefersLargeTitle: false)
navigationItem.rightBarButtonItem = viewSource.closeButtonBarItem
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
рдореИрдВрдиреЗ InstagramLoginWebView
init(frame:)
рдХреЛ init(frame:completionHandler:)
рдФрд░ рдлрд┐рд░ рдЖрдкрдХреЗ рд╡рд┐рд╖рдп рдореЗрдВ рдореВрд▓реНрдпреЛрдВ рдХреЛ рдЖрдЧреЗ рдмрдврд╝рд╛рдиреЗ рдХреЗ рд▓рд┐рдП completionHandler
рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рд╣реИред
рдзрдиреНрдпрд╡рд╛рдж @sbertix