Swiftyinsta: WebLogin not working

Created on 22 Jul 2019  ·  16Comments  ·  Source: TheM4hd1/SwiftyInsta

After update the pod weblogin not compiled in ios 10 version.
When I change to 11.0 version of ios it says:

  • 'loginDelegate' is deprecated: use InstagramLoginWebView properties instead.
  • 'InstagramLoginWebViewDelegate' is deprecated: use InstagramLoginWebViewProtocol closure properties instead.

When I changed InstagramLoginWebViewDelegate to InstagramLoginWebViewProtocol:

  • 'InstagramLoginWebViewProtocol' requires that 'LoginViewController' inherit from 'UIView'

My Codes:

class LoginViewController: 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**
}

}

extension LoginViewController : InstagramLoginWebViewProtocol { --'InstagramLoginWebViewProtocol' requires that 'LoginViewController' inherit from 'UIView'

func userLoggedSuccessfully() {
    print("User Logged Successfully")

    DispatchQueue.main.async {
        self.loginWebView.removeFromSuperview()
    }

}
help wanted

All 16 comments

Hey @effecttwins 😊

InstagramLoginWebView has changed a lot in the last update, and support for iOS 10.* had to be dropped because of incompatibility.
Using loginDelegate is no longer suggested, although still functional.
All you have to do to get the behavior you're used to is setting the following properties on your loginWebView:

  • didReachEndOfLoginFlow is a _closure_ called like redirected used to.
  • didSuccessfullyLogIn is a _closure_ replacing the _delegate_'s userLoggedSuccessfully().
  • completionHandler is a _closure_ replacing the _delegate_'s webViewFinishedToLoadUser(sessionChache:handler:)

This is the updated code for 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()
    }
}

so when I change the extension InstagramLoginWebViewDelegate to InstagramLoginWebViewProtocol and it says: 'InstagramLoginWebViewProtocol' requires that 'LoginViewController' inherit from 'UIView'

Code:

extension LoginViewController : 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)")
    }


}

You should never conform to InstagramLoginWebViewProtocol.
My fault for not marking it internal. I apologize.

This is all the code you need. No InstagramLoginWebViewProtocol. No 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 thanks for your all help.
But instagram login page not loaded there is only white page in screen

This is all the code you need. No InstagramLoginWebViewProtocol. No InstagramLoginWebViewDelegate.

@effecttwins copy and paste the code I wrote above. Don't forget to call the loadInstagramLogin().
It's literally already implemented for you 😊
It works

yeap I did copy and paste all code and called loadInstagramLogin :)
Also deleted InstagramLoginWebViewProtocol and InstagramLoginWebViewDelegate

in console I am getting this error, I am not sure it is related with this project or not
Could not signal service com.apple.WebKit.Networking: 113: Could not find specified service

Sorry, I've never added the loginWebView to the view in my code hahaha
I've edited it. Check it again. It should work now @effecttwins

You are awesome @sbertix
It is working now
Thanks for you all help

Hey @sbertix

What happens I'm following MVVM pattern and my view and my viewController is in different files? The view should not send data to View Controller. Is there way to have access to didSuccessfullyLogIn function after the initialization of the InstagramLoginWebView?

You don't need to init InstagramLoginWebView with a didSuccessfullyLogIn (it's optional).
And even with the other _closures_: you can simply assign a different value once you have it.
@anonrig

Can you provide an example of this, if I may ask? @sbertix :)

Sure. Can you send more info about your code? The way your model and view are setup, for instance.

Yeah of course!

Before 1.7.x I was handling the login success event on ViewController level using the delegates

Example view:

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")
    }
}

Example ViewController:

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")
    }
}

I don't exactly know what LoginWebViewModel is... but if the objective is to get everything into completeObservable you can simply do:

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")
    }
}

I've changed InstagramLoginWebView init(frame:) to init(frame:completionHandler:) and then updated the completionHandler to push values to your subject.

Thanks @sbertix

Was this page helpful?
0 / 5 - 0 ratings

Related issues

reefer picture reefer  ·  18Comments

sbertix picture sbertix  ·  8Comments

sbertix picture sbertix  ·  27Comments

anonrig picture anonrig  ·  3Comments

biox86 picture biox86  ·  12Comments