Getting Thread: signal SIGABRT - swift

Building an app with a chat feature and getting a SIGBRT error. It doesn't seem to be talking to the Firebase database. I checked all my outlets and they seem to all be intact and I didn't see any broken outlets.
the error I'm getting in the debug area is
"2018-08-21 01:09:15.479487-0400 Split App[83668:9375919] *** Terminating app due to uncaught exception 'FIRAppNotConfigured', reason: 'Failed to get default Firebase Database instance. Must call [FIRApp configure] (FirebaseApp.configure() in Swift) before using Firebase Database.... libc++abi.dylib: terminating with uncaught exception of type NSException"
class DataService{
static let dataService = DataService()
private var _BASE_REF = Database.database().reference()
private var _ROOM_REF = Database.database().reference().child("rooms")
var BASE_REF: DatabaseReference {
return _BASE_REF
}
var ROOM_REF:DatabaseReference{
return _ROOM_REF
}
var storageRef: StorageReference{
return Storage.storage().reference()
}
var fileURL: String!
// store the thumbnail in database
func CreateNewRoom(user: User, caption: String, data: NSData){
let filePath = "\(user.uid)/\
(Int(NSDate.timeIntervalSinceReferenceDate))"
let metaData = StorageMetadata()
metaData.contentType = "image/jpg"
storageRef.child(filePath).putData(data as Data, metadata: metaData){
(metadata, error) in if error != nil {
print ("Error Uploading: \(String(describing:
error?.localizedDescription))")
return
}
//create a url for data (photo thumbnail image)
_ = metadata?.storageReference?.downloadURL(completion: error as!
(URL?, Error?) -> Void)
if Auth.auth().currentUser != nil {
let idRoom = self.BASE_REF.child("rooms").childByAutoId()
idRoom.setValue(["caption": caption,"thumbnailURLFromStorage":
self.storageRef.child(metadata!.path!).description, "fileURL" :
self.fileURL])
}
}
}
func fetchDataFromServer(callback: #escaping (Room) -> ()){
DataService.dataService.ROOM_REF.observe(.childAdded){ (snapshot) in
let room = Room(key: snapshot.key, snapshot: snapshot.value as!
Dictionary<String, Any>)
callback(room)
}
}
func SignUp(username:String, email: String, password: String, firstName:
String, lastName: String, data: NSData){
Auth.auth().createUser(withEmail: email, password: password, completion:
{ (user, error) in
if error != nil {
print(error!)
}
else {
print("Registration Successful")
}
let changeRequest =
Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = username
changeRequest?.commitChanges(completion: {(error) in
if let error = error {
print (error.localizedDescription)
return
}
})
let filePath = "profileimage/\(String(describing:
Auth.auth().currentUser!.uid))"
let metadata = FirebaseStorage.StorageMetadata()
metadata.contentType = "image/jpeg"
self.storageRef.child(filePath).putData(data as Data, metadata:
metadata, completion: {(metadata, error) in
if let error = error {
print ("\(error.localizedDescription)")
return
}
_ = metadata?.storageReference?.downloadURL(completion: error as!
(URL?, Error?) -> Void)
if let error = error {
print (error.localizedDescription)
return
}
else {
print ("Sweet!")
}
let appDelegate: AppDelegate = UIApplication.shared.delegate as!
AppDelegate
appDelegate.login()
})
}
}

You should follow these steps
Step 1 Import Firebase to your AppDelegate.swift
import Firebase
Step 2 call configure() in didFinishLaunchingWithOptions method in AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
return true
}
Hope it helps

You have not configured firebase yet .
So just inside you app delegate first import Firebase and inside the method didFinishLaunchingWithOptions configure firebase.
By writing a single line FirebaseApp.configure().

Related

Google Auth: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'presentingViewController must be set.'

I have incorporated Google sign in into my app. It was working well this whole time and then suddenly stopped working, now giving me this error in the debugger:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'presentingViewController must be set.'
Here is my code for the login view controller (edited to show only necessary code):
class WelcomeViewController: UIViewController, GIDSignInDelegate {
#IBOutlet weak var signInGoogleButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
setUpGoogleButton()
GIDSignIn.sharedInstance()?.presentingViewController = self
}
// MARK: - SIGN UP WITH GOOGLE
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let err = error {
print("Failed to log into Google: ", err)
return
}
print("Successfully logged into Google")
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken)
// sign user in with Firebase
Auth.auth().signIn(with: credential, completion: { (user, error) in
let firstName = user?.user.displayName
let email = user?.user.email
let lastName = ""
let uid = user?.user.uid
if let err = error {
print("Failed to create a Firebase User with Google account: ", err)
return
} else {
// Successfully logged in
print("Successfully logged into Firebase with Google email: ", email ?? "", "Now add user to Firestore if user is new.")
// check if user already exists
self.addUserToFirestore(firstName ?? "", lastName, email ?? "", uid ?? "", "Google")
}
})
}
fileprivate func setUpGoogleButton() {
Utilities.styleLightFilledButton(signInGoogleButton)
signInGoogleButton!.addTarget(self, action:
#selector(handleCustomGoogleSignIn), for: .touchUpInside)
GIDSignIn.sharedInstance()?.delegate = self
}
#objc func handleCustomGoogleSignIn() {
GIDSignIn.sharedInstance().signIn()
}
// MARK: - Other functions
func addUserToFirestore(_ firstName:String, _ lastName:String, _ email:String, _ uid:String, _ signInMethod:String) {
let db = Firestore.firestore()
let docRef = db.collection("users").document(uid)
// check if user exists in firestore
docRef.getDocument { (document, error) in
if let document = document {
if document.exists {
let message = "Good news! You already have a Coal account that uses " + email + ".\nPlease sign in to your existing account. Then you will be able to link your " + signInMethod + " profile from your Account Settings page."
// user exists. send to chats screen.
print("User already exists. Document data: \(String(describing: document.data()))")
self.showError("You're already a member!", message)
} else {
// user does not exist. create a new user
print("Document does not exist. Create new user.")
docRef.setData(["firstname":firstName, "lastname":lastName, "email":email]) { err in
if err != nil {
// Show error message
print("Error saving user data to Firestore")
} else {
print("New user created in Firestore")
self.transitionToConvo()
}
}
}
}
}
}
func showError(_ title:String, _ message:String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
func transitionToConvo() {
let tabBarC = self.storyboard?.instantiateViewController(withIdentifier: "mainTabBarController") as! TabBarController
tabBarC.modalPresentationStyle = .fullScreen
self.present(tabBarC, animated: true, completion: nil)
print("Switched to TabBarController")
}
} // end
Here is the app delegate:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let err = error {
print("Failed to log into Google: ", err)
return
}
print("Successfully logged into Google")
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken)
Auth.auth().signIn(with: credential, completion: { (user, error) in
if let err = error {
print("Failed to create a Firebase User with Google account: ", err)
return
}
guard let uid = user?.user.uid else { return }
print("Successfully logged into Firebase with Google", uid)
})
}
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance()?.clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance()?.delegate = self
ApplicationDelegate.shared.application(
application,
didFinishLaunchingWithOptions: launchOptions
)
return true
}
#available(iOS 9.0, *)
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
ApplicationDelegate.shared.application(
app,
open: url,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
annotation: options[UIApplication.OpenURLOptionsKey.annotation]
)
return GIDSignIn.sharedInstance().handle(url)
}
}
The error occurs every time I click the signInGoogleButton. Any help is appreciated, thank you!!

Firebase iOS clicking on shortened link returns ' Receive failed with error "Software caused connection abort" '

I'm just going to paste in a couple of my files so that you can test this really easily and see what's going on. I'm clicking the button and it's making the shortened dynamic link. Then, I'm typing out the DynamicLink in the notes app and then I press the link. I get redirected to the app and the following error is returned:
[connection] nw_read_request_report [C1] Receive failed with error "Software caused connection abort"
Side note: all of this is being tested on an iPhone 7 (a physical device, not the simulator).
FirebaseTestApp and AppDelegate:
import SwiftUI
import Firebase
#main
struct FirebaseTestApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
var functionMaster: functions = functions()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
return true
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url)
if dynamicLink != nil {
print("Dynamic link : \(String(describing: dynamicLink?.url))")
return true
}
return false
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
print("Successful penetration")
guard let inComingURL = userActivity.webpageURL else { return false }
print("Incoming Web Page URL: \(inComingURL)")
self.functionMaster.handleIncomingDynamicLink(inComingURL)
return true
}
}
functions class:
import Foundation
import Firebase
import UIKit
class functions: ObservableObject {
func makeDynamicLink() {
var components = URLComponents()
components.scheme = "https"
components.host = "www.firebase-test.com" //this can be some random domain right? It doesn't have to actually exist yet?
components.path = "/data"
let stringifiedNumber = String(123)
components.queryItems = [stringifiedNumber]
let dynamicLinksDomainURIPrefix = "https://something.page.link"
guard let linkParameter = components.url else { return }
print("I am sharing \(linkParameter)")
guard let linkBuilder = DynamicLinkComponents(link: linkParameter, domainURIPrefix: dynamicLinksDomainURIPrefix) else { return }
if let myBundleId = Bundle.main.bundleIdentifier {
linkBuilder.iOSParameters = DynamicLinkIOSParameters(bundleID: myBundleId)
}
linkBuilder.iOSParameters?.appStoreID = "962194608"
linkBuilder.socialMetaTagParameters = DynamicLinkSocialMetaTagParameters()
linkBuilder.socialMetaTagParameters?.title = testLocation.name
linkBuilder.socialMetaTagParameters?.descriptionText = testLocation.address
linkBuilder.shorten { [weak self] (url, warnings, error) in
if let error = error{
print("Firebase encountered an error: \(error)")
return
}
if let warnings = warnings {
for warning in warnings {
print("Firebase Warning: \(warning)")
}
}
guard let url = url else { return }
print("The short URL is: \(url.absoluteString)")
self?.showShareSheet(url: url)
}
guard let longDynamicLink = linkBuilder.url else { return }
print("The long URL is: \(longDynamicLink)")
}
func showShareSheet(url: URL) {
let promoText = "Check out this thing I've marked in FirebaseTest!"
let activityVC = UIActivityViewController(activityItems: [promoText, url], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(activityVC, animated: true)
}
func handleIncomingDynamicLink(_ dynamicLink: URL) {
_ = DynamicLinks.dynamicLinks().handleUniversalLink(dynamicLink) { (dynamiclink, error) in
guard error == nil else {
print("Found an error: \(error?.localizedDescription ?? "")")
return
}
print("Dynamic link : \(String(describing: dynamiclink?.url))")
let path = dynamiclink?.url?.path
var id = 0
if let query = dynamiclink?.url?.query {
let dataArray = query.components(separatedBy: "=")
id = Int(dataArray[1]) ?? 0
}
if path == "data" {
//Write code here
}
}
}
}
ContentView:
import SwiftUI
struct ContentView: View {
#ObservedObject var functionMaster: functions = functions()
var body: some View {
Button("Click me to run some firebase stuff") {
functionMaster.makeDynamicLink()
}
.padding()
}
}
In browser, when I navigate to https://something.page.link/apple-app-site-association, I get this:
https://i.stack.imgur.com/6Ndo0.png
Try installing the files for the the simulator you want to test on, update Xcode, delete all other versions.

Firebase Re-Authenticate Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value error

The user needs to be authenticated again to change the email address. When I write the following code, I get the error: user.reauthenticate (with: credential) {_ in the line of error Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value.
var credential: AuthCredential! I have also defined this
if let user = Auth.auth().currentUser {
// re authenticate the user
user.reauthenticate(with: credential) { _,error in
if let error = error {
print(error)
} else {
// User re-authenticated.
user.updateEmail(to: self.emailField.text!) { (error) in
}
}
}
}
You need to prompt the user for their credentials, otherwise that property will be nil which will show the error you are seeing
let user = Auth.auth().currentUser
var credential: AuthCredential
// *** Prompt the user to re-provide their sign-in credentials ***
// populate the credential var with that data so it's not nil
//
user?.reauthenticate(with: credential) { error in
if let error = error {
// An error happened.
} else {
// User re-authenticated.
}
}
You can follow this example step by step
Configuration:
-> Select your project
-> Go to TARGETS
-> Select your project icon
-> Click info tab
-> Add new URL Types(REVERSED_CLIENT_ID from GoogleService-Info.plist)
1. You need to setup your pre requisite configuration into your AppDelegate class
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Pass device token to auth
Auth.auth().setAPNSToken(deviceToken, type: AuthAPNSTokenType.unknown)
}
// For iOS 9+
func application(_ application: UIApplication, open url: URL,
options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
if Auth.auth().canHandle(url) {
return true
}
// URL not auth related, developer should handle it.
return ApplicationDelegate.shared.application(application, open: url, options: options)
}
// For iOS 8-
func application(_ application: UIApplication,
open url: URL,
sourceApplication: String?,
annotation: Any) -> Bool {
if Auth.auth().canHandle(url) {
return true
}
// URL not auth related, developer should handle it.
return ApplicationDelegate.shared.application(application, open: url)
}
func application(_ application: UIApplication, didReceiveRemoteNotification notification: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
if Auth.auth().canHandleNotification(notification) {
completionHandler(UIBackgroundFetchResult.noData)
return
}else{
completionHandler(UIBackgroundFetchResult.newData)
}
// This notification is not auth related, developer should handle it.
}
2. It's your ViewModel class
class FirebaseSignin: NSObject {
public func firebaseSigninWith(phoneNumber: String?, completion: #escaping (Bool, String?, Error?)->()) {
//SVProgressHUD.show()
if let phoneNumber = phoneNumber {
print("firebaseSigninWith phoneNumber: ", phoneNumber)
Auth.auth().languageCode = "fr";
PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil) { [weak self] (verificationID, error) in
//SVProgressHUD.dismiss()
if let error = error {
completion(false, verificationID, error)
return
}else{
UserDefaults.standard.set(verificationID, forKey: "authVerificationID")
completion(true, verificationID, error)
}
}
}else{
completion(false, nil, nil)
}
}
public func otpConfirmation(verificationCode: String?, completion: #escaping (Bool, Any?, Error?)->()) {
//SVProgressHUD.show()
if let verificationCode = verificationCode {
if let verificationID = UserDefaults.standard.string(forKey: "authVerificationID") {
let credential = PhoneAuthProvider.provider().credential(withVerificationID: verificationID, verificationCode: verificationCode)
Auth.auth().signIn(with: credential) { (authResult, error) in
//SVProgressHUD.dismiss()
if let error = error {
completion(false, verificationID, error)
return
}else{
completion(true, verificationID, error)
}
}
}else{
completion(false, nil, nil)
}
}else{
completion(false, nil, nil)
}
}
}
3. you call your submitBttonAction function from LoginClass
func submitBttonAction() {
let mobile_no = mobileNumberTextField.getFormattedPhoneNumber(format: .E164)
self.firebaseSignin.firebaseSigninWith(phoneNumber: mobile_no) { [weak self] (isSuccess, verificationID, error) in
if isSuccess {
//GlobalVariable.showToastWith(view: GlobalVariable.getRootViewController()?.view, message: "OTP send successfully.")
//RootViewController.selectViewController(_viewController: .OTPConfrimationViewController, ["delegate": self])
// you open your OTPConfrimationViewController
}else{
//GlobalVariable.showToastWith(view: GlobalVariable.getRootViewController()?.view, message: "OTP sending fail \(error?.localizedDescription ?? "")")
}
}
}
4. confirm your OTP from TOPViewController class
func otpConfirmation() {
if let otp = self.otpTextField.text {
self.firebaseSignin.otpConfirmation(verificationCode: otp) { [weak self] (isSuccess, authResult, error) in
if isSuccess {
//GlobalVariable.showToastWith(view: GlobalVariable.getRootViewController()?.view, message: "OTP varified successfully.")
//self?.handleHeaderBackAction(nil)
//self?.delegate?.otpConfrimationCallBack(isSuccess)
}else{
//GlobalVariable.showToastWith(view: GlobalVariable.getRootViewController()?.view, message: "OTP varification fail \(error?.localizedDescription ?? "")")
}
}
}
}

Why does the function return the result ahead of time?

In appDelegate I will check whether the user is authorized through the userAuthorizedCheck() function. Depending on the result, redirect it to one or another stroyBoard. userAuthorizedCheck() should return the result only after the server has answered. The problem is that if i leave the last completion(false) in userAuthorizedCheck(), then it returns false first, and then it is checked. Even if the check was successful, then all the same, completion(false) is sent first and, as a result, the redirect is sent to the Authorization storyboard.
But if I remove the last completion(false), then I get Thread 1: signal SIGABRT, opposite func application (). print (tempToken) is triggered after checking userAuthorizedCheck (). If i put a breakpoint, i can see that in the userAuthorizedCheck () function, the last completion (false) works first.
AppDelegate:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
var storyboardName: String = ""
userAuthorizedCheck(after: { (succesful) in
if (succesful == true){
storyboardName = "Main"
}else{
print(false)
storyboardName = "Authorization"
}
})
let storyboard = UIStoryboard(name: storyboardName, bundle: Bundle.main)
window = UIWindow(frame: UIScreen.main.bounds)
window!.makeKeyAndVisible()
window!.rootViewController = storyboard.instantiateInitialViewController()
return true
}
func userAuthorizedCheck(after completion: #escaping (Bool) -> Void) {
let username : String = UserDefaults.standard.string(forKey: "username") ?? ""
let password : String = UserDefaults.standard.string(forKey: "password") ?? ""
let tokenSaved : String = UserDefaults.standard.string(forKey: "token") ?? ""
var tempToken:String = ""
//
if(!username.isEmpty && !password.isEmpty)
{
let json: [String: String] = ["username": username, "password": password]
login(json: json, after: {(status, token, code) in
if(code == 200 && !token.isEmpty){
UserDefaults.standard.setValue(token, forKey: "token");
UserDefaults.standard.synchronize();
tempToken = token
print(tempToken)
completion(true)
}
else{
tempToken = ""
completion(false)
}
})
}
else
{
completion(false)
}
completion(false)//The problem in this line, as I repent
}
login(in another swift file):
func login(json:Any, after completion: #escaping (Bool, _ token: String, _ code:Int) -> Void){
guard let url = URL(string: ngrok+"/api/auth/token/create")else{return}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField:"Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: json, options: [])else {return}
request.httpBody = httpBody
let sessionConfig = URLSessionConfiguration.default
sessionConfig.timeoutIntervalForRequest = 5.0
sessionConfig.timeoutIntervalForResource = 60.0
URLSession(configuration: sessionConfig).dataTask(with: request){(data, response, error) in
if error != nil{
print("server error")
completion(true, "", 0)
}
else if let response = response{
// print(response)
if let httpResponse = response as? HTTPURLResponse{
guard let data = data else{return}
do{
// print(data)
if(httpResponse.statusCode == 200){
if let json_response = try JSONSerialization.jsonObject(with: data, options: [])as? [String:Any]{
if let token = json_response["auth_token"]{
print(token as! String)
completion(true, "token",httpResponse.statusCode)
}
}
}
else if(httpResponse.statusCode == 400)
{
completion(true, "",httpResponse.statusCode)
print("The username or password you entered is incorrect")
}
else{
print("Unknown error")
completion(true, "", 0)
}
}
catch{
print("errasd")
print(error)
completion(true, "", 0)
}
}
}
}.resume()
}
I want the user Authorized Check () function to send the result only after the server has responded.
You cannot wait in didFinishLaunchingWithOptions for something asynchronous before returning true or false.
One option is to return true and load the storyboard after the response of the server
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
userAuthorizedCheck(after: { (succesful) in
let storyboardName = succesful ? "Main" : "Authorization"
let storyboard = UIStoryboard(name: storyboardName, bundle: Bundle.main)
self.window = UIWindow(frame: UIScreen.main.bounds)
window!.makeKeyAndVisible()
window!.rootViewController = storyboard.instantiateInitialViewController()
})
return true
}
And delete this line in userAuthorizedCheck
completion(false)//The problem in this line, as I repent
because it completes immediately which is not intended.

swift 3 facebook integration

trying to get Facebook connect working from a swift project.
Have been trying to follow along the following youtube video: https://www.youtube.com/watch?v=I6rTmfLp9aY
which unfortunately for me is in German.
so this is what I have so far:
I have my Facebook app with IOS enabled enabled and I planted my bundleID there.
Downloaded latest iOS framework and added to project
to the AppDelegate file I added:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FBSDKApplicationDelegate.sharedInstance()
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
FBSDKAppEvents.activateApp()
}
and this is the ViewController file
import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
import FBSDKShareKit
class ViewController: UIViewController, FBSDKAppInviteDialogDelegate, FBSDKLoginButtonDelegate{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if (FBSDKAccessToken.current() != nil)
{
let content = FBSDKAppInviteContent()
content.appLinkURL = NSURL(string: "{Facebook link to app}") as URL!
FBSDKAppInviteDialog.show(from: self, with: content, delegate: self)
}
else
{
let loginView : FBSDKLoginButton = FBSDKLoginButton()
self.view.addSubview(loginView)
loginView.center = CGPoint(x: self.view.frame.midX, y: self.view.frame.midY + 100)
loginView.readPermissions = ["public_profile", "email"]
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func appInviteDialog (_ appInviteDialog: FBSDKAppInviteDialog!, didCompleteWithResults results: [AnyHashable : Any]!)
{
}
func appInviteDialog (_ appInviteDialog: FBSDKAppInviteDialog!, didFailWithError error: Error!) {
print("Error took place in appInviteDialog \(error)")
}
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if ((error) != nil)
{
//process error
}
else if result.isCancelled {
//handle cancelation
}
else {
let content = FBSDKAppInviteContent()
content.appLinkURL = NSURL(string: "{Facebook link to app}") as URL!
FBSDKAppInviteDialog.show(from: self, with: content, delegate: self)
if result.grantedPermissions.contains("email")
{
//do work
}
}
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
}
}
No errors and no alerts. When i run simulator I get an empty screen. Must be doing something right cause I get the following msg:
SystemGroup/systemgroup.com.apple.configurationprofiles
2017-06-04 00:42:02.351876+0300 facebook_login[4569:144075] [MC] Reading from private effective user settings.
also, if I just paste in viewDidLoad the following lines from the code:
let loginView : FBSDKLoginButton = FBSDKLoginButton()
self.view.addSubview(loginView)
loginView.center = CGPoint(x: self.view.frame.midX, y: self.view.frame.midY + 100)
loginView.readPermissions = ["public_profile", "email"]
I get a beautiful Facebook button in simulator that of course crashes when i press it.
any help to work will be greatly appreciated
Facebook has a Swift SDK you might find easier to use than the Objective-C one (which they just call iOS). Try looking around the documentation here:
https://developers.facebook.com/docs/swift
Also, follow the steps described in the (other) iOS SDK to get started:
https://developers.facebook.com/docs/ios/getting-started/
This is the minimal app delegate I could get to work (notice the Swift SDK is missing the FB prefixes that exist in the iOS SDK):
import UIKit
import FacebookCore
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
SDKApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return SDKApplicationDelegate.shared.application(app, open: url, options: options)
}
}
And be sure to add all the required keys in your Info.plist or else you won't get authentication to work at all.
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith
result:FBSDKLoginManagerLoginResult!, error: Error!) {
if ((error) != nil) {
// Process error
print("Error! : \(error.localizedDescription)")
return
} else if result.isCancelled {
// Handle cancellations
print("Success! : user cancel login request")
return
} else {
let graphRequest : FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields" : "id, email, name,picture.type(large)"])
graphRequest.start(completionHandler: { (connection, result, error) -> Void in
if ((error) != nil) {
print("Error: \(error)")
} else {
// Do work in app.
let dataDict:NSDictionary = result as! NSDictionary
if let token = FBSDKAccessToken.current().tokenString {
print("tocken: \(token)")
let userDefult = UserDefaults.standard
userDefult.setValue(token, forKey: "access_tocken")
userDefult.synchronize()
}
if let user : NSString = dataDict.object(forKey: "name") as! NSString? {
print("user: \(user)")
}
if let id : NSString = dataDict.object(forKey: "id") as? NSString {
print("id: \(id)")
}
if let email : NSString = (result! as AnyObject).value(forKey: "email") as? NSString {
print("email: \(email)")
}
if let pictureData:NSDictionary = dataDict.object(forKey: "picture") as? NSDictionary{
if let data:NSDictionary = pictureData.object(forKey: "data") as? NSDictionary{
if let strPictureURL: String = data.object(forKey: "url") as? String{
self.imageviewUser.image = UIImage(data: NSData(contentsOf: NSURL(string: strPictureURL)! as URL)! as Data)
}
}
}
}
})
}
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!)
{
FBSDKAccessToken.setCurrent(nil)
FBSDKProfile.setCurrent(nil)
let manager = FBSDKLoginManager()
manager.logOut()
}