How to implement Login module as part of my iOS framework - ios

I am building an iOS framework and it should provide some common module like Register, Forgot Password, Login and Profile etc. So, any application that imports my framework should able to use these screens as it is. The challenge that I am facing is navigating from one screen to another screen in my iOS framework code. When navigating from once screen Login(screen1) to another screen Forgot Password(screen2), the handler(callback) methods are being invoked in screen1 view controller instead of screen2 view controller. We tried using xib and storyboard, however I did not find a solution for this.
Can somebody please point out any example code which does the similar stuff ?
Am I missing some thing over here in understanding iOS concepts, I am building an iOS framework which includes some UI flows, Is it possible?

I would suggest a delegate pattern, because callbacks are more one-shot, while delegates serve better the purpose to continually assist the lifetime of an object. Anyway I've created an example to cope with your requirements, git it here (Framework + test app included)
It involves a LoginController, which is the main entry point and orchestra for the framework.
When you initialise it, you pass a callback which will be used to send events, including "forgot password" and "user wants to exit", those are defined in an enum.
public enum LoginFrameworkStatus {
case Login
case ForgotPassword
case Help
case Disaster
case Exited
case UserWantsExit
}
Class offer an entry point to start the process:
public func enterLoginWorkflow(on controller: UIViewController, callback: LoginFrameworkCallback) {
let myBundle = Bundle(for: LoginController.self)
if let navi = UIStoryboard(name: "LoginWorkflow", bundle: myBundle).instantiateInitialViewController() as? MySpecialNavigationController {
presentingController = controller
navi.loginController = self
self.callback = callback
controller.present(navi, animated: true, completion: {
//presented!
callback?( .Login, navi, self) //If reference to LoginController is lost, tell the callback there's a problem.. shouldn't happend because we have a strong reference on the navigation controller.
})
}
}
.. and an exit point:
public func leaveLoginWorkflow() {
presentingController?.dismiss(animated: true, completion: {
self.callback?(.Exited, nil,self)
})
}
So the main interface for your framework would be:
LoginController().enterLoginWorkflow(on: self) { (status, controller, loginController) in
print("\(status) in \(controller?.description ?? "No Controller")")
switch status {
case .UserWantsExit:
loginController?.leaveLoginWorkflow()
case .ForgotPassword:
loginController?.leaveLoginWorkflow()
default:
()
}
}
In the test app I included a minimum workflow for you to test.
Let me know if this is what you needed, or if you want to investigate the delegation pattern, which I think would be way more suitable for this.

Try 1) IcaliaLabs/LoginKit (https://github.com/IcaliaLabs/LoginKit). LoginKit is a quick and easy way to add a Login/Signup UX to your iOS app.
2) TigerWolf/LoginKit https://github.com/TigerWolf/LoginKit

We can create a framework just like Parse.com does. It's well known and great app that used by thousands of developers.
Refer https://github.com/parse-community/ParseUI-iOS

Related

Create page after login xcode

I'm an XCode noob and I've looked all over for the answer. This is my first time building anything in XCode and I've created a login window using Firebase in ViewController.swift. Once the user is logged in, I want them to go to another screen that is using MapKit etc. How do I automatically link the login window success to the second page?
I've created a new cocoa touch class file as MapViewController.swift - do I just call the map function at the end of the login function or is there a more simple way to do it with the storyboard?
Sorry for the stupid question
after you check that the user enters the right credentials set function to call the new view controller
func transition() {
let mapViewController:MapViewController = MapViewController()
self.presentViewController(mapViewController, animated: true, completion: nil)
}
then call it
transition()

Best practice for presenting App internal error to user?

I use guard statement and fatalError() a lot in my app to make sure data are in consistent state. They help to catch bugs in development phase. Now I'm in the late phase of the project and start to consider how to deal with those fatalError() calls in release build.
I don't want to remove them because they help to expose unknown bugs. I don't want to just leave them as is in the product release either because they would just abort the App, which doesn't provide user any helpful information about what went wrong. What I'd like to achieve is to show an error message on the screen and then abort when user press "OK". I think there may be two approaches to do it:
1) Don't call fatalError(). Throw error instead. Let the top level code handles the error (e.g., showing an alert). The issue with the approach is that it requires to change many functions to become throwable, which I think is inconvenient.
2) The second approach is that from what I read on the net, it's possible for code to create alert without access to the current view controller on screen. The trick is to create a new window. I haven't investigated the details yet.
My concern is that I think both approaches have same inherent limitation and are not applicable in all situations. For example, suppose there is something goes wrong in a UITableViewControler's data source delegate method, does it work to present an alert from within the delegate method? I doubt it.
So I wonder what's the common practice to present the fatal error message to user? Thanks for any suggestions.
similar to create a window, there is a way to get 'currentViewController', you can use it to show an alert anywhere.
{
let view = UIViewController.current.view
Alert.show(on: view, message: errorMsg)
//or just: Alert.show(error), handle it in Alert class
}
extension UIViewController {
class func current(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return current(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
return current(base: tab.selectedViewController)
}
if let presented = base?.presentedViewController {
return current(base: presented)
}
return base
}
}
for UITableView/UIScrollView/UICollectionView, you can use runtime swizzle method to add a placeholder image when there is no data or an error occored for all views. such as EmptyDataSet
recored the errors and save the log into a local file, upload it to your server if necessary, analyse them and help users to solve there problem.

App not showing in external display extension for any iPhone

I created a new app in Xcode and added the following code in the AppDelegate file
func updateCarWindow()
{
guard let screen = UIScreen.screens.first(where: { $0.traitCollection.userInterfaceIdiom == .carPlay })
else
{
// CarPlay is not connected
self.carWindow = nil;
return
}
// CarPlay is connected
let carWindow = UIWindow(frame: screen.bounds)
carWindow.screen = screen
carWindow.makeKeyAndVisible()
carWindow.rootViewController = CarViewController(nibName: nil, bundle: nil)
self.carWindow = carWindow
}
and called the function in function application. The app is not showing in the CarPlay external display.
You don’t have direct access to the carplay screen, carplay manages everything using the CPInterfaceController class that is able to display so called templates (such as CPListTemplate and a handful of others). Your ability to draw on the screen is pretty much limited to drawing maps in a CPMapContentWindow.
I recommend you read the Apple docs first starting here:
https://developer.apple.com/carplay/documentation/CarPlay-Navigation-App-Programming-Guide.pdf
Don’t forget to set the correct app permissions and carplay entitlements othereise it simply won’t work and it might not tell you why.
And a final word that the Carplay framework is only supposed to work with navigation apps. Everything else would require a lot of workarounds, not to mention it would never pass app review.
Hope this helps

How to acknowledge system alerts on a device with KIF testing framework?

I found out how to acknowledge system alerts while on a simulator from this post using this line of code:
self.viewTester.acknowledgeSystemAlert()
Unfortunately, the KIF code has #if TARGET_IPHONE_SIMULATOR wrapped around it, so it won't work on a device. How can I get around permission alerts on a device during automated testing?
I had same issue and here the solution I found:
its right than this KIF function doesn't work on device, its only for simulators! so, You can have a UITest in the UITarget and just a single Test case in it that will add a UIMonitors like this:
// ask for all the permission from users then :
_ = addUIInterruptionMonitor(withDescription: "") { alert -> Bool in
let confirmLabels = ["Allow", "OK"]
for (_, label) in confirmLabels.enumerated() {
let allow = alert.buttons[label]
if allow.exists {
allow.tap()
break
}
}
return true
}
// do some UI interaction here like tapping on some view in app
So you can call this UITest each time before running your UnitTests and that will prepare your app to have all the permissions.
btw, if anyone has better solution please provide cause I wanna know, too ;)

Twitterkit present a new viewcontroller instead present on a target viewController

Im using TwiterKit 3.0 framwork. And im using Deeplink to share a tweet for my application. But the problem is its presenting a new viewController and shows the twitter dialogue box. But my requirement is need to share like in Photos app sharing screen.
if let deepLinkurl = branchObject.getShortUrl(with: shareLinkProperties) {
let composer = TWTRComposer()
composer.setURL(URL(string: deepLinkURL))
composer.show(from: self) { result in
if (result == TWTRComposerResult.cancelled) {
print("Tweet composition cancelled")
}
}
If i run above code I get like this
But I need something like this.
You can use Branch's showShareSheet() method for sharing Branch links to other apps.
Here is how the link is shared when using the shareSheet and selecting Twitter from the list of the Apps.
You can check out the documentation here

Resources