NSUbiquityIdentityDidChangeNotification does not fire with cloud kit - ios

This is my current code
func applicationDidBecameActive(notification:NSNotification) {
println("Application is active")
NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleIdentityChange:", name: NSUbiquityIdentityDidChangeNotification, object: nil)
}
func applicationBecameInactive(notification:NSNotification) {
println("Application is inactive")
NSNotificationCenter.defaultCenter().removeObserver(self, name: NSUbiquityIdentityDidChangeNotification, object: nil)
}
func handleIdentityChange(notification:NSNotification) {
println("this is working")
let fileManager = NSFileManager()
if let token = fileManager.ubiquityIdentityToken {
println("New token is \(token)")
}
else {
println("User has logged out of iCloud")
}
}
"Application is active" & "Application is inactive" works properly. There is no problem there.
I could not get it fire "This is working". By logging into different iCloud account or logging out of iCloud account.
I tried on simulator & on actual device.
Please help me fix this or suggest alternative method to achieve same goal(change in iCloud account).

In Swift I have sometimes needed to add #objc in front of a func for NSNotificationCenter to find it.
So instead of
func handleIdentityChange(notification:NSNotification) {
I'd try
#objc func handleIdentityChange(notification:NSNotification) {

Have a look at my comment in this question. I never received a NSUbiquityIdentityDidChangeNotification either. In iOS your app gets killed when you change accounts. In tvOS you can use NSUbiquitousKeyValueStoreAccountChange.

Related

How can I check my application's contacts store authorization status when my application becomes active using NotificationCenter?

My application has a menu with option "Contacts". When user selects Contacts for the first time, application asks user permission to use device Contacts. If user allows access, opens a view controller with contacts of his/her device, if he doesn't, nothing happens. After that every time they select "Contacts" option, it heads to Device Settings where they should allow access to contacts or dismiss it. When they allow access and go back to the app, I want it to open the view controller with contacts, but it doesn't.
I've tried to use NotificationCenter with didBecomeActiveNotification option, but it does not seem to help.
func checkPermissionToDeviceContacts() {
switch CNContactStore.authorizationStatus(for: .contacts) {
case .notDetermined:
self.requestContactsAccess()
case .authorized:
self.openContactsViewController()
case .denied:
self.headToSettingsOfPermissions()
default: return
}
}
func headToSettingsOfPermissions() {
if let bundleId = Bundle.main.bundleIdentifier,
let url = URL(string: "\(UIApplication.openSettingsURLString)&path=APPNAME/\(bundleId)")
{
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
self.setupNotifications()
}
func setupNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(self.applicationDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
}
#objc func applicationDidBecomeActive() {
if CNContactStore.authorizationStatus(for: .contacts) == .authorized {
self.openContactsViewController()
}
NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
}
I also cannot debug it, because when Device Settings are opened and I change the access status of Contacts, my console prints a message "Message from debugger: Terminated due to signal 9".
The problem is that the selector function works when I do not change the authorization status, but when I do, it does not work anyway.
P.S. This is my first time to use NotificationCenter, maybe I do not use it properly.
NotificationCenter sends always the affected notification as parameter, you have to declare
#objc func applicationDidBecomeActive(_ notification : Notification) {
and remove self in the selector parameter
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)

swift notification messages manually for app

How to notify the message when manually changes from device notifications from setting
. notifications changes, what method will be invoke inside app, to know that notification was changes
override func awakeFromNib() {
super.awakeFromNib()
let center = UNUserNotificationCenter.current()
center.getNotificationSettings { (settings) in
if(settings.authorizationStatus == .authorized)
{
print(" authorized")
DispatchQueue.main.async {
self.onOffSwitch.isOn = true
}
}
else
{
print(" not authorized")
DispatchQueue.main.async {
self.onOffSwitch.isOn = false
}
}
}
I got tableview inside SettingViewcontroller customize my cell where added the swift onOffSwift.
Based on the setting manually user changes the notifications from setting I wants my app sync accordingly.
SettingViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tbl_SettingView.reloadData()
}
I expected this will work for me? but not
How to handle when user changes there notifications from setting screen should reflect on mobile app screen.
Your app doesn't get an automatic notification when the settings are changed. But the user can make this change only in the Settings app, so you can check the settings when your app comes back to the foreground.
The reason your
override func viewWillAppear(_ animated: Bool) {
doesn't help is that viewWillAppear is not called when the app comes back to the foreground.
There might be better ways but the one I know is this:
Store Settings.authorizationStatus as value in a singleton class or as an entry in UserDefaults
Whenever the app becomes active compare the new value to the stored value. If the they are not the same than you know the settings were changed
I believe you want to get your updated settings when your app enters foreground and not when viewWillAppear called. Just add the observer to your viewDidLoad() (and don't forget to remove it once you're done with the controller):
NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: nil) { _ in
UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { settings in
DispatchQueue.main.async {
// update your view with current settings.authorizationStatus
}
})
}

iOS Face ID/Touch ID Lock Screen Conflict in willEnterForegroundNotification

I have code that puts a blurred UIVisualEffectView over the current window when the didEnterBackgroundNotification notification is fired. It then tries to reverse this when willEnterForegroundNotification is fired (simplified for easy reading):
class AutoBlur {
init() {
NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
}
#objc func appDidEnterBackground() {
blur()
}
#objc func appWillEnterForeground() {
guard UserState.isScreenLockEnabled else {
unblur()
return
}
let authContext = LAContext()
authContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "test") { success, error in
DispatchQueue.main.async {
guard success else {
return
}
unblur()
}
}
}
//...
}
While this approach generally works, when testing the Face ID functionality of app I found the following anomaly:
Open the app
Turn the screen off on the device
Wake the device
Swipe up on the device's lock-screen
Expected results: The device should unlock, and then my app should run its Face ID evaluate code to un-blur the view.
Actual results: The swipe-up action is undercut by my app's Face ID evaluation code. It prevents the user from being able to swipe up on their lock-screen, effectively locking them out of their device.
Is there some state I should be monitoring or some other event that's safer to respond to for triggering my Face ID evaluation?

Swift Firebase Delete An user when app will terminate

Im trying to Delete user when app will terminate but this does not work.
If I have an anonymous user signed in and the user close the app I don't want firebase to save the anonymous user. I want to delete it. This is my current code. Thank you in advance
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
if let users = Auth.auth().currentUser {
if !users.isAnonymous {
return
}else {
users.delete(completion: { (error) in
if error != nil {
print(error!)
return
}
try! Auth.auth().signOut()
print("Anonymous user deleted")
})
}
}
}
I added listerners in the ViewDidLoad to the screen where I want the user the be deleted from. Like this:
NotificationCenter.default.addObserver(self, selector: #selector(suspending), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(suspending), name: NSNotification.Name.UIApplicationWillTerminate, object: nil)
And then I have this function to delete the user:
#objc func suspending () {
if Auth.auth().currentUser != nil {
let user = Auth.auth().currentUser
user?.delete { error in
if let error = error {
print("An error happened delting the user.")
} else {
print("Account succesfully deleted.")
}
}
}
}
The only thing that could happen is, that you need to re-authenticate. If that's the case, than follow this answer to implement it as well
Hei #pprevalon, I've been trying to achieve the same thing as you, just by updating a value on appWillTerminate, but here's what I found out from other members
Your implementation of this method has approximately five seconds to perform any tasks and return. If the method does not return before time expires, the system may kill the process altogether.
Still trying to figure out a way, since it happens 1/10 times for the func appWillTerminate to be called, but I cannot count on that.
P.S. Besides that, think about this : If the user switches from active -> background at first, followed by background -> kill app, the method will never get called.

How to send and receive data in Today extensions

I want to develop an app for iOS that have a Widget for notification center, but I don't know how I should send and receive data (pass data) between View Controller and And Today Extension.
I tried to use structs, but it doesn't work, and also I used app groups but I don't want to use this method.
let shared = NSUserDefaults(suiteName: "group.Demo.Share-Extension-Demo.mahdi")
shared?.setObject("Hello", forKey: "kkk")
Apart from NSUserDefaults, you can use the NSNotificationCenter to send or receive data anywhere.
You need to set the observer where you can receive the data like below:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "dataReceived:", name: "SpecialKey", object: nil)
}
Funciton to catch data:
func dataReceived(notification: NSNotification) {
//deal with notification.userInfo
println(notification.userInfo)
println("Received Data")
}
And you need to define NSNotificationCenter from where you need to send the data:
NSNotificationCenter.defaultCenter().postNotificationName("SpecialKey", object: nil, userInfo: ["MyData": "Demo"])
References:
The complete guide to NSNotificationCenter
Hope it helps!
http://moreindirection.blogspot.in/2014/08/nsnotificationcenter-swift-and-blocks.html
For the people who haven't found a way to implement calling function or button click from App Extension (Widget):
Note: This is using Swift
Note 2: Replace the names of NSNotification and methods with your implementations
First, create NotificationCenter post method (In Swift 2.0 - NSNotification Center)
Create methods in App Delegate class -
var scheme: String!
var host: String!
Then, add the following function on the bottom of the class (after the last one):
func application(_ app: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
scheme = url.scheme
host = url.host
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "NOTIFICATION_NAME"), object: nil)
return true
}
In your ViewController class, where you want to execute the function or the statement from clicking Widget, add the following in super.viewDidLoad():
NotificationCenter.default.addObserver(self,selector: #selector(self.YOUR_METHOD_NAME),
name: NSNotification.Name(rawValue: "NOTIFICATION_NAME"),
object: nil)
And the method you want to call:
func YOUR_METHOD_NAME(notification: NSNotification) {
let appDelegate =
UIApplication.shared.delegate as! AppDelegate
if appDelegate.scheme != nil {
startRecording()
}
}
I'm assuming that you have already created your widget target, and the view for it. Add this to your button in TodayViewController from which you want to handle the click:
#IBAction func openApp(_ sender: UIButton) {
openApp()
}
And the function to handle opening app by URl Scheme:
func openApp(){
let myAppUrl = NSURL(string: "YOUR_URL_SCHEME://YOUR_HOST_NAME")!
extensionContext?.open(myAppUrl as URL, completionHandler: { (success) in
if (!success) {
self.textView.text = "There was a problem opening app!"
}
})
}
For YOUR_URL_SCHEME, add your scheme that you have specified in Info.plist, if your don't, go to this link and follow instructions:
Add URL Scheme to Xcode
For YOUR_HOST_NAME, you can remove this, and only open app by URL Scheme.
Happy coding!

Resources