I have sample app with a button. On click button should be taking the user to push notification service for my app to be able to disable them or enable.
I know how to get to the general setting with this sample code but I think for notification probably you need some additional parameters like bundleId.
My question is more about URL for push notification for my app not only get to general setup as this is shown on code sample below
Sample code:
#IBAction func pushNotificationSettings(button: UIButton) {
guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
print("Settings opened: \(success)") // Prints true
})
} else {
// Fallback on earlier versions
}
}
}
For IOS 10 or above
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
if settings.authorizationStatus == .authorized {
// Notifications are allowed
}
else {
// Either denied or notDetermined
let alertController = UIAlertController(title: nil, message: "Do you want to change notifications settings?", preferredStyle: .alert)
let action1 = UIAlertAction(title: "Settings", style: .default) { (action:UIAlertAction) in
if let appSettings = NSURL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(appSettings as URL, options: [:], completionHandler: nil)
}
}
let action2 = UIAlertAction(title: "Cancel", style: .cancel) { (action:UIAlertAction) in
}
alertController.addAction(action1)
alertController.addAction(action2)
self.present(alertController, animated: true, completion: nil)
}
}
Related
Why won't RPScreenRecorder record the mic, even though it is enabled, if the permissions popup doesn't appear? It works when the popup appears but attempts after restarting the app don't record the mic.
here's the very simple app i made just to test this feature for a larger app.
I have tested this exact application on iOS 11 and it works every time. However on iOS 12+ it only works when the permission popup appears and that's every 8 minutes. It should work every time after giving permissions.
import ReplayKit
class ViewController: UIViewController, RPPreviewViewControllerDelegate {
private let recorder = RPScreenRecorder.shared()
private var isRecording = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func react() {
if !isRecording {
let alert = UIAlertController(title: "Record", message: "Would you like to record a video?", preferredStyle: .alert)
let okay = UIAlertAction(title: "Okay", style: .destructive, handler: { (action: UIAlertAction) in
self.startRecording()
})
alert.addAction(okay)
self.present(alert, animated: true, completion: nil)
} else {
stopRecording()
}
}
private func startRecording() {
guard self.recorder.isAvailable else {
print("Recording is not available at this time.")
return
}
self.recorder.isMicrophoneEnabled = true
self.recorder.startRecording{ [unowned self] (error) in
guard error == nil else {
print("There was an error starting the recording.")
return
}
print("Started Recording Successfully")
self.isRecording = true
}
}
private func stopRecording() {
recorder.stopRecording { [unowned self] (preview, error) in
print("Stopped recording")
guard preview != nil else {
print("Preview controller is not available.")
return
}
let alert = UIAlertController(title: "Recording Finished", message: "Would you like to edit or delete your recording?", preferredStyle: .alert)
let deleteAction = UIAlertAction(title: "Delete", style: .destructive, handler: { (action: UIAlertAction) in
self.recorder.discardRecording(handler: { () -> Void in
print("Recording suffessfully deleted.")
})
})
let editAction = UIAlertAction(title: "Edit", style: .default, handler: { (action: UIAlertAction) -> Void in
preview?.previewControllerDelegate = self
self.present(preview!, animated: true, completion: nil)
})
alert.addAction(editAction)
alert.addAction(deleteAction)
self.present(alert, animated: true, completion: nil)
self.isRecording = false
}
}
func previewControllerDidFinish(_ previewController: RPPreviewViewController) {
dismiss(animated: true)
}
}
I expect that the mic should record every single time after allowing the permissions however it appears to only be recording the mic during the sessions in which it asks for those permissions.
This appears to have been fixed in iOS 13. The OS now asks for permission every time you request to record the screen. I still don't have a fix for iOS 12 however.
In my scenario, User will get an alert for receiving Notification in application. If the user clicks on "Don't Allow" UILabel is updated with "Not enabled". If the user wants to change the notification,User will be navigated to application setting page to change the notification permission status.
func checkNotificationPermission(){
UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound]){
(granted, error) in
if granted == true {
DispatchQueue.main.async {
print("notificaation access true")
self.notificationAccessLbl?.text = "Enabled"
}
}
else {
DispatchQueue.main.async {
self.notificationAccessLbl?.text = "Not enabled"
}
}
}
UIApplication.shared.registerForRemoteNotifications() }
But when the user comes back to application, The UILabel is not getting updated when the user comes to application from Setting page.
for Updating the UILabel in application after the user comes from setting page to application. I Have Called
func checkNotificationPermission()
to update UILabel Value in ViewDidAppear() Method and I register the a function in applicationwillbecomeactive method() Kindly help me in this.
I have switch in setting page in application which allows user to enable disable push and that will be send on server but before that user must have allowed push from settings page of Device. here is my solution
I have created global object
var isPushEnabledFromSettings = false {
didSet {
// you can set label value here in main queue
}
}
and one method to check it
func isPushPermissionGiven (permission:#escaping (Bool) -> ()) {
if #available(iOS 10.0, *) {
let current = UNUserNotificationCenter.current()
current.getNotificationSettings(completionHandler: {settings in
switch settings.authorizationStatus {
case .notDetermined:
permission(false)
case .denied:
permission(false)
case .authorized:
permission(true)
}
})
} else {
// Fallback on earlier versions
if UIApplication.shared.isRegisteredForRemoteNotifications {
permission(true)
} else {
permission(false)
}
}
}
and in view did load added these lines
self.isPushPermissionGiven { (permission) in
self.isPushEnabledFromSettings = permission
}
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationDidBecomeActive, object: nil, queue: .main) {[weak self] (notificaiont) in
guard let strongSelf = self else {return }
strongSelf.isPushPermissionGiven { (permission) in
DispatchQueue.main.async {
strongSelf.isPushEnabledFromSettings = permission
}
}
}
Now I have switch in setting page which allows user to enable disable push
#objc func switchChanged (sender:UISwitch) {
guard self.isPushEnabledFromSettings else {
AppDelegate.sharedDelegate.navigateUesrToSettings(withMessage: "Please grant push permission from settings")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
sender.setOn(false, animated: false)
})
return
}
}
func navigateUesrToSettings (withTitle title:String = "YourApp", withMessage message:String) {
let alertController = UIAlertController (title: title, message: message, preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in
guard let _ = URL(string: UIApplicationOpenSettingsURLString) else {
return
}
self.navigate(To: UIApplicationOpenSettingsURLString)
}
alertController.addAction(settingsAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alertController.addAction(cancelAction)
AppDelegate.sharedDelegate.window?.rootViewController?.present(alertController, animated: true, completion: nil)
}
Hope it is helpful to you :)
I am working on an app and try to figure out whether my app is registered for Push Notifications or not. I mean user allow Push notifications or not. But when i want to check in code it always return true. i don't know why is it behaving like this.
My code for checking push notifications registration.
let isRegistered = UIApplication.shared.isRegisteredForRemoteNotifications
if isRegistered == false {
let alertController = UIAlertController(title: "Notification Alert", message: "Kindly enable push notifications", preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in
guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
})
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alertController.addAction(cancelAction)
alertController.addAction(settingsAction)
DispatchQueue.main.async {
self.present(alertController, animated: true, completion: nil)
}
}
What I understood is that if "isRegistered" is false you will ask the user to allow notifications in that case you should be asking for authorization like this :
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
if granted {
DispatchQueue.main.async(execute: {
UIApplication.shared.registerForRemoteNotifications()
})
}
}
I am using local notifications in my app, before presenting user with new notification screen I want to check the authorisation status first. I am using shouldPerformSegue(identifier:, sender:) -> Bool method, so that if the notifications are not authorised by user, the scene where the user configures and saves a new notification is not presented:
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "AddReminder" {
// Check to see if notifications are authorised for this app by the user
let isAuthorised = NotificationsManager.checkAuthorization()
if isAuthorised {
print(isAuthorised)
return true
}
else {
let alert = UIAlertController(title: "Title", message: "Message", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) {
(action: UIAlertAction) in
}
let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in
guard let settingsURL = URL(string: UIApplicationOpenSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsURL) {
UIApplication.shared.open(settingsURL, options: [:], completionHandler: { (success) in
print("Settings opened: \(success)")
})
}
}
alert.addAction(cancelAction)
alert.addAction(settingsAction)
present(alert, animated: true, completion: nil)
print(isAuthorised)
return false
}
}
// By default, transition
return true
}
Here is the method I use for authorisation check:
static func checkAuthorization() -> Bool {
// var isAuthorised: Bool
var isAuthorised = true
UNUserNotificationCenter.current().getNotificationSettings { (notificationSettings) in
switch notificationSettings.authorizationStatus {
case .notDetermined:
self.requestAuthorization(completionHandler: { (success) in
guard success else { return }
})
print("Reached .notDetermined stage")
case .authorized:
isAuthorised = true
case .denied:
isAuthorised = false
}
}
//print("Last statement reached before the check itself")
return isAuthorised
}
I figured that the last statement in the above function (return isAuthorized) returned before the body of UNUserNotificationCenter.current().getNotificationSettings{} is executed, therefore it always returns whatever isAuthorized is configured to, at the very beginning of the method.
Question:
Could you please suggest how I could check for authorisation using I better way, since my way does not even work.
This is only my first IOS app, so I am relatively new to IOS development; any help would be greatly appreciated.
If anyone having similar problem, then instead of using getNotificationsSettings(){} method, which will be computed after the enclosing method is returned; we could use different approach, i.e. getting currentUserNotificationSettings, which is notification settings of our app. Then check if current settings contain .aler, .sound and etc. If the answer is YES, then we could be sure that the applications has its notifications enabled.
Writing an app that requires the network. Run a method to check the WiFi is on and working, initially in the ViewController. So I got ...
wifiWorks = Reachability.isConnectedToNetwork()
This is defined like this ...
var wifiWorks: Bool = false {
didSet {
if wifiWorks {
print("Wifi On")
NotificationCenter.default.post(name: Notification.Name("WifiBon"), object: nil, userInfo: nil)
} else {
print("WiFi Off")
NotificationCenter.default.post(name: Notification.Name("noWiFi"), object: nil, userInfo: nil)
}
}
}
Now if noWifi gets called it shows an alert that basically goes to the settings like this...
func noWifi(notification:NSNotification) {
DispatchQueue.main.async {
//self.navigation.isHidden = true
let alert = UIAlertController(title: "Stop", message: "Your iPad isn't connected to the WiFi ...", preferredStyle: UIAlertControllerStyle.alert)
let settingsAction = UIAlertAction(title: "Settings", style: .default) { (_) -> Void in
guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
print("Settings opened: \(success)") // Prints true
})
}
}
alert.addAction(settingsAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: nil)
}
}
At which point, my app isn't running any longer, the user is sitting in settings, and has to switch back to my app having (hopefully) turned the WiFi on. Back in my app I got this in the app delegate.
func applicationWillEnterForeground(_ application: UIApplication) {
print("applicationWillEnterForeground")
wifiWorks = Reachability.isConnectedToNetwork()
}
Which brings me back full circle, so you cannot continue with the app, cause it needs the WiFi.
My question, does this dance make sense; or was/is there a cleaner way to do this?
You can use Reachability's own Notifications, as it's GitHub page suggests:
NotificationCenter.default.addObserver(self, selector: #selector(self.reachabilityChanged),name: ReachabilityChangedNotification,object: reachability)
do{
try reachability.startNotifier()
}catch{
print("could not start reachability notifier")
}
Callback:
func reachabilityChanged(note: NSNotification) {
let reachability = note.object as! Reachability
if !reachability.isReachable {
//you can show alert here
}
}
Also be aware that user can turn on/off wifi without leaving your app, just by switching wifi toggle from Control Center. That's why you should not rely only on applicationWillEnterForeground method.