I am having some problems with RealmSwift with the Notification Service Extension. I hope everyone can help me or give me some advice. I sincerely thank you all! And my English is not good, let me know if there is something unclear.
First, I used FCM to push the message to my ios device, I need to save my push notification to the ios device (using Realm).
There are only two cases that have a way to save successfully.
1.app running
2.app is killed/background, and click to push banner notifications I hope I can do the app off/background and save it without having to click on the banner notification.
So I used the following method
1.Add Notification Service Extension in the project
2.Enable Background fetch/Remote notifications
3.Project and Notification Service Extension added to app groups
I know that Extension can't share data, so I changed the default path of Realm.
I added the following code to AppDelegates.swift and added the same code in NotificationService.swift.
like this
let sharedDirectory: URL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myapp")! as URL
let sharedRealmURL = sharedDirectory.appendingPathComponent("db.realm")
Realm.Configuration.defaultConfiguration = Realm.Configuration(fileURL: sharedRealmURL)
After I added these codes, when the app is killed or the background, the push message can be successfully saved to Realm, but not every time, 10 push notifications will only store 5, and most Importantly, the functionality that could have been stored in the app runing or clicking on the banner notification failed.
(But it is stored, because if I cancel the code that changes the default path of Realm, the data that has not been saved will be displayed again)
My Realm class
import Foundation
import RealmSwift
class Order: Object {
#objc dynamic var id = UUID().uuidString
#objc dynamic var name = ""
#objc dynamic var amount = ""
#objc dynamic var createDate = Date()
override static func primaryKey() -> String? {
return "id"
}
}
import UIKit
import RealmSwift
class RealmDao: NSObject {
static let shared = RealmDao()
private var realm: Realm!
private override init() {
self.realm = try! Realm()
}
func getRealmObject() -> Realm {
return self.realm
}
}
Part of my AppDelegate.swift
let realm = try! Realm()
let order: Order = Order()
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
////share Realm
let sharedDirectory: URL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myapp")! as URL
let sharedRealmURL = sharedDirectory.appendingPathComponent("db.realm")
Realm.Configuration.defaultConfiguration = Realm.Configuration(fileURL: sharedRealmURL)
tainerURL(forSecurityApplicationGroupIdentifier: "group.myapp")
FirebaseApp.configure()
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
Messaging.messaging().delegate = self // For iOS 10 data message (sent via FCM)
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { granted, error in
if granted {
print("ok...")
} else {
print("no...")
}
})
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let sharedDirectory: URL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myapp")! as URL
let sharedRealmURL = sharedDirectory.appendingPathComponent("db.realm")
Realm.Configuration.defaultConfiguration = Realm.Configuration(fileURL: sharedRealmURL)
let userInfo = notification.request.content.userInfo
print("userInfo: \(userInfo)")
guard
let aps = userInfo[AnyHashable("aps")] as? NSDictionary,
let alert = aps["alert"] as? NSDictionary,
let body = alert["body"] as? String,
let title = alert["title"] as? String
else {
// handle any error here
return
}
print("Title: \(title) \nBody:\(body)")
order.name = title
order.amount = body
try! realm.write {
realm.add(order)
}
completionHandler([.badge, .sound, .alert])
}
All my NotificationService.swift
import UserNotifications
import Firebase
import UIKit
import RealmSwift
import Realm
class NotificationService: UNNotificationServiceExtension {
let realm = try! Realm()
let order: Order = Order()
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: #escaping (UNNotificationContent) -> Void) {
let sharedDirectory: URL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myapp")! as URL
let sharedRealmURL = sharedDirectory.appendingPathComponent("db.realm")
Realm.Configuration.defaultConfiguration = Realm.Configuration(fileURL: sharedRealmURL)
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
let message = request.content.userInfo
print("userInfo: \(message)")
guard
let aps = message[AnyHashable("aps")] as? NSDictionary,
let alert = aps["alert"] as? NSDictionary,
let title = alert["body"] as? String,
let body = alert["title"] as? String
else {
// handle any error here
return
}
print("Title: \(title) \nBody:\(body)")
order.name = title
order.amount = body
try! realm.write {
realm.add(order)
}
if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here...
bestAttemptContent.body = "\(bestAttemptContent.body) [fortest]"
contentHandler(bestAttemptContent)
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
I think my problem seems to be a problem with the default path change, because when I change the path, the push notification in the execution is saved, but the code that must delete the change path will be displayed! Is it what I missed that causes the original path to still exist (so the push notification in the app running will be stored in another data table?)
Related
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.
I am beginner in swift and Xcode 12, I am trying to implement core data correctly in my project after forgetting to check the option Core data when I have created the project , I manipulated my appDelegate.swift and also I had wrote few code lines about core data functions , but I still face problems with it like the error type 'NSManagedObject' has no member 'fetch' for example , I feel I have not implemented core data correctly
here my AppDelegate.swift after few manipulations :
//
// AppDelegate.swift
// Bicycall
//
// Created by Jamil Joo on 1/12/2020.
//
import UIKit
import CoreData
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "Bicycall")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
here my controller where I have used the core data:
//
// login.swift
// Bicycall
//
// Created by Jamil Joo on 2/12/2020.
//
import UIKit
import CoreData
class login: UIViewController {
var id: Int?
var name: String?
var lastname: String?
var email:String?
var password:String?
var phone:String?
override func viewDidLoad() {
super.viewDidLoad()
self.DeleteAllData()
// Do any additional setup after loading the view.
}
//widgets
#IBOutlet weak var txtEmail: UITextField!
#IBOutlet weak var txtPassword: UITextField!
//Actions
#IBAction func btnLogin(_ sender: Any){
//get
/*
guard let url = URL(string: "http://localhost:3000/bikes") else {
return
}
let session = URLSession.shared
session.dataTask(with: url) { ( data , response ,error) in
if let response = response {
print(response)
}
if let data = data {
print(data)
do
{
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
}catch{
print(error)
}
}
}.resume()
*/
//post
guard let url = URL(string: "http://localhost:3000/login") else {
return
}
let bodyparameters = ["email": txtEmail.text, "password": txtPassword.text]
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: bodyparameters, options: []) else{
return
}
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data,response,error) in
if let response = response {
print(response)
}
if let data = data {
do {
//let json = try JSONSerialization.jsonObject(with: data, options: [])
// print(json);
print(data)
let user = try JSONDecoder().decode(User.self, from: data)
DispatchQueue.main.async {
self.id = user.user_id
self.name = user.name
self.lastname = user.lastname
self.email = user.email
self.password = user.password
self.phone = user.phone
print(self.id!)
print(self.email!)
if(user.user_id != 0){
//self.saveUser(user)
self.performSegue(withIdentifier: "HomeSegue", sender: "nil")
self.saveUser()
}else{
let alert = UIAlertController(title: "Login Failed", message: "Wrong credentials", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true)
}
}
}catch{
print(error)
}
}
}.resume()
}
func DeleteAllData(){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.persistentContainer.viewContext
let DelAllReqVar = NSBatchDeleteRequest(fetchRequest: NSFetchRequest<NSFetchRequestResult>(entityName: "Users"))
do {
try managedContext.execute(DelAllReqVar)
}
catch {
print(error)
}
}
func saveUser() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//represente l'ORM
let persistentContainer = appDelegate.persistentContainer
let managedContext = persistentContainer.viewContext
let entityDescription = NSEntityDescription.entity(forEntityName: "Users" , in: managedContext)
let object = NSManagedObject(entity: entityDescription! , insertInto: managedContext )
object.setValue(id! , forKey: "user_id" )
object.setValue(email! , forKey: "email" )
object.setValue(password! , forKey: "password" )
object.setValue(name! , forKey: "name" )
object.setValue(lastname! , forKey: "lastname" )
object.setValue(phone! , forKey: "phone" )
do {
try managedContext.save()
print("INSERT SUCCESSFULLY")
print(id!)
}
catch {
print("INSERT ERROR")
}
}
func DisplayData() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//represente l'ORM
let persistentContainer = appDelegate.persistentContainer
let managedContext = persistentContainer.viewContext //retourne NSManagedObject toujours
//la requete retourne un NSManagedObject
let request = NSFetchRequest<NSManagedObject>(entityName : "Users")
//execution de la requete
do {
let result = try NSManagedObject.fetch(request)
for item in result {
favourites.append(item.value(forKey: "MovieName") as! String)
item.value()
}
}
catch {
print("NO DATA FOUND , Error")
}
}
#IBAction func btnSignup(_ sender: Any) {
performSegue(withIdentifier: "signupSegue", sender: "nil")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
What I am trying to do is to repair my project CoreData and fix what can be fixed to prevent the errors I obtain in my controller
ps: I have created a data model Users
The error is a typo and quite clear:
You cannot call fetch on the type NSManagedObject, you have to call it on the NSManagedObjectContext instance.
Replace
let result = try NSManagedObject.fetch(request)
with
let result = try managedContext.fetch(request)
I'm trying to allow a user to report a user (in a Tinder-like app). To report, this button takes the user to a new VC to elaborate the issue as an email.
What I'm missing:
How can I add the reporter's and reportee's Firebase unique ID to the email (or whatever form of communication)? (So then I can investigate and take action as needed)
Here's what I have:
The code to properly send an email...
func configureMailController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients(["RadiusAppHelp#gmail.com"])
mailComposerVC.setSubject("Reporting user")
mailComposerVC.setMessageBody("Please include as much detail as possible:", isHTML: false)
return mailComposerVC
}
func showMailError() {
let sendMailErrorAlert = showAlert(withTitle: "Could not send message", message: "Please try again")
let dismiss = UIAlertAction(title: "Okay", style: .default, handler: nil)
// sendMailErrorAlert.addAction(dismiss)
// self.present(sendMailErrorAlert, animated: true, completion: nil)
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
}
The code to pull the other user's ID in the swipe view VC...
var otherUsersId = ""
var currentlyViewedUserId: String?
firebaseServer.fetchUsers {[weak self] (usersDict) in
self?.usersDict = usersDict
let fetchedUsers = Array(usersDict.values)
self?.filterBlockedUsers(from: fetchedUsers)
self?.loadFirstUser()
self?.cardView.reloadData()
}
func loadFirstUser() {
if users.count > 0 {
let imageView = UIImageView()
let storage = Storage.storage()
let storageRef = storage.reference(withPath:
"\(users[0].userId!)/photos/\(0)")
currentlyViewedUserId = users[0].userId
PhotoUploader.downloadImageUrl(from:
storageRef) { (url) in
guard let url = url else { return }
imageView.downloaded(from: url,
contentMode: .scaleAspectFill)
}
nameLbl.text = users[0].firstName
setupDetailsFor(user: users[0])
infoCollectionView.reloadData()
}
}
As well as the code to block a user (but blocking / reporting functions work independently).
Any help is greatly appreciated!
Okay, I found at least a temporary fix...
(Not using Firestore however, which I'll eventually need to implement — https://www.youtube.com/watch?v=Ofux_4c94FI)
In FirebaseFunctions.swift...
// Report Someone
func reportSomeone(with userId: String, completion:
#escaping (Error?) -> Void) {
let usersRef = db.child("users")
if let uid = Auth.auth().currentUser?.uid {
usersRef.child("\(uid)/report/\ .
(userId)").setValue(true) { (error, dbref) in
completion(error)
}
}
}
// Set Preferences for Reporting
func reportPreferences(with userId: String,
completion: #escaping (Error?) -> Void) {
let usersRef = db.child("users")
if let uid = Auth.auth().currentUser?.uid {
usersRef.child("\(uid)/preferences/\ .
(userId)").setValue(true) { (error, dbref) in
completion(error)
}
}
}
In User.swift...
var report: [String: Bool]? = [:]
func makeDictionary() -> [String: Any] {
print("")
return [
"report": report ?? [:]
]
static func makeObjectFrom(_ dictionary: [String:
Any]) -> LocalUser {
let report = dictionary["report"] as?
[String:Bool] ?? [:]
}
let localUser = LocalUser(report: report)
In the View Controller...
import Firebase
var currentUserId = Auth.auth().currentUser?.uid
var otherUsersId = ""
// Report Button
var isCurrentUserReported = false
var isOtherUserReported = false
var currentlyViewedUserId: String?
// FILTER REPORTED USERS
func filterReportUsers(from users: [LocalUser]) {
var notReportUsers = users
var notReportUsersDict = self.usersDict
var reportUsers = newUser.report ?? [:]
if let currentUserId =
Auth.auth().currentUser?.uid {
reportUsers[currentUserId] = true
}
for (userId, report) in reportUsers ?? [:] {
print("UserId...", userId)
print("UserHere...", usersDict[userId])
if let user = usersDict[userId] {
notReportUsersDict.removeValue(forKey:
userId)
}
}
let notReport = Array(notReportUsersDict.values)
self.users = notReport
}
This isn't perfect, but it works!
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()
}
I created the application use existing database realm 2.3.0 and swift 3.1 xcode 8.3.
But when I try to access the realm database. there is an error.
Could not access database: Error Domain=io.realm Code=2 "Unable to open a realm at path '/Users/dodipurnomo/Library/Developer/CoreSimulator/Devices/858C796B-CBA8-424B-9A97-0893304B758B/data/Containers/Data/Application/A2D910EE-AAC5-4836-9FE7-97F744E802E5/Documents/Conversio.realm': Unsupported Realm file format version." UserInfo={NSFilePath=/Users/dodipurnomo/Library/Developer/CoreSimulator/Devices/858C796B-CBA8-424B-9A97-0893304B758B/data/Containers/Data/Application/A2D910EE-AAC5-4836-9FE7-97F744E802E5/Documents/Conversio.realm,
Above is an error message when I try to execute the database.
As for the class to hendleing the database realm is as follows:
import RealmSwift
import UIKit
class DBManager{
//MARK: - Singleton shared intance
static let sharedIntance = DBManager()
//MARK: - overide init function in realm
static var realm: Realm {
get {
do {
let realm = try Realm()
return realm
}
catch {
print("Could not access database: ", error)
}
return self.realm
}
}
public static func write(realm: Realm, writeClosure: () -> ()) {
do {
try realm.write {
writeClosure()
}
} catch {
print("Could not write to database: ", error)
}
}
public static func query(realm: Realm,queryClosure: () -> ()){
}
func save(entityList: [Object], shouldUpdate update: Bool = false) {
DBManager.realm.beginWrite()
for entity in entityList {
if let key = type(of: entity).primaryKey(), let value = entity[key] , update {
if let existingObject = DBManager.realm.object(ofType: type(of: entity), forPrimaryKey: value as AnyObject) {
let relationships = existingObject.objectSchema.properties.filter {
$0.type == .array
}
for relationship in relationships {
if let newObjectRelationship = entity[relationship.name] as? ListBase , newObjectRelationship.count == 0 {
entity[relationship.name] = existingObject[relationship.name]
}
}
}
}
DBManager.realm.add(entity, update: update)
}
do {
try DBManager.realm.commitWrite()
} catch let writeError {
debugPrint("Unable to commit write: \(writeError)")
}
DBManager.realm.refresh()
}
}
And I set the Realm in appdelegate as follows:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let desPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let fullDesPath = URL(fileURLWithPath: desPath).appendingPathComponent("Conversio.realm")
var config = Realm.Configuration()
config.deleteRealmIfMigrationNeeded = true
config.fileURL = fullDesPath
Realm.Configuration.defaultConfiguration = config
chekDB()
return true
}
//chek database
func chekDB() {
let bundleDB = Bundle.main.path(forResource: "Conversio", ofType: "realm")
let desPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let fileManager = FileManager.default
let fullDesPath = URL(fileURLWithPath: desPath).appendingPathComponent("Conversio.realm")
let fullDestPathString = String(describing: fullDesPath)
if fileManager.fileExists(atPath: fullDesPath.path){
print("Database file is exis !")
print(fileManager.fileExists(atPath: bundleDB!))
}else{
do{
try fileManager.copyItem(atPath: bundleDB!, toPath: fullDesPath.path)
}catch{
print("error encured while copying file to directori \(fullDestPathString)")
}
}
}
The error message you're getting means that realm file was created with newer version of Realm, so update Realm to the latest version.
Also keep in mind if you open realm with Realm Browser that uses a newer version of realm it asks you to convert the file format. If you do that you can open this realm with older version of realm-cocoa.