How to ask for remote permission in iOS 10/Swift 3 - swift

I want to ask the user for permissions (remote and local notifications, camera and audio) from a separate viewController. The viewcontroller will be presented during the onboarding process, and never again.
How can I ask for permissions to display remote notifications outside the AppDelegate?
My question is not how to trigger them, but how to make sure that the AppDelegate is "responsible" for handling them once a permission have been granted.
Current code in AppDelegate
import UIKit
import UserNotifications
import PushKit
import CallKit
AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, UNUserNotificationCenterDelegate {
let pushRegistry = PKPushRegistry(queue: DispatchQueue.main)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
pushRegistry.delegate = self
pushRegistry.desiredPushTypes = [.voIP]
....
}
ViewController where I ask for permission
import UIKit
import UserNotifications
class AskForNotificationPermissionVC: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
requestPermissions { (videoGranted, audioGranted, notificationsGranted) in
if videoGranted && audioGranted && notificationsGranted {
DispatchQueue.main.async{
self.performSegue(withIdentifier: "toPaySegue", sender: self)
}
} else {
DispatchQueue.main.async{
self.presentSpecialPopoup()
}
}
}
}
func requestPermissions (completion: #escaping ((Bool, Bool, Bool)->())) {
let center = UNUserNotificationCenter.current()
center.delegate = UIApplication.shared.delegate as! UNUserNotificationCenterDelegate?
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { (videoGranted: Bool) -> Void in
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeAudio, completionHandler: { (audioGranted: Bool) -> Void in
center.requestAuthorization(options: [.alert, .badge, .sound]) { (notificationGranted:Bool, error) -> Void in
UIApplication.shared.registerForRemoteNotifications()
completion(videoGranted, audioGranted, notificationGranted)
}
})
})
}
}
Any help is very, very much appreciated !! Thank you.

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
//handle result
}

Related

Unable to navigate to other view controller after Google sign-in

How can I go to another view controller after successfully signing with google? I've tried "self.inputViewController?.performSegue(withIdentifier: "goToMain", sender: self)" in my App Delegate but not getting any respond. Am I supposed to add the method in App Delegate or the view controller with the sign-in button?
App Delegate
import UIKit
import Firebase
import GoogleSignIn
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance()?.clientID = "my_client_id"
GIDSignIn.sharedInstance()?.delegate = self
return true
}
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let error = error {
print(error)
return
}
guard
let authentication = user?.authentication,
let idToken = authentication.idToken
else {
return
}
let credential = GoogleAuthProvider.credential(withIDToken: idToken,
accessToken: authentication.accessToken)
Auth.auth().signIn(with: credential) { authResult, error in
if let error = error {
let authError = error as NSError
print(authError.localizedDescription)
return
}
self.inputViewController?.performSegue(withIdentifier: "goToMain", sender: self)
}
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return GIDSignIn.sharedInstance().handle(url)
}
// 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.
}
}
Are you sure about the inputViewController is not nil? This may a reason for not working.
You can add a function to test this, or you can use the print function to check, or, you can use debug point to check inputViewController is nil or not.
I'd like to add comment but I don't have enough reputation point :).
Good luck.

FCM Notifications are received in background but not foreground on iOS

I am getting FCM messages pushed to my iOS device fine when in the background but not in the foreground. I have found a number of articles where others had the same issue and solved it by adding the willPresentNotification function. However this isn't solving the issue for me. My FCM code is as follows:
class FCMManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate {
static let shared = FCMManager()
let database = Database.database().reference()
public func registerForPushNotifications() {
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .sound, .announcement, .badge, .carPlay, .providesAppNotificationSettings]
UNUserNotificationCenter.current()
.requestAuthorization( options: authOptions,
completionHandler: { granted, _ in
guard granted else {
print("Apple push notifications are not registered")
return
}
print("Apple push notifications are registered")
})
Messaging.messaging().delegate = self
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
updatePushTokenIfNeeded()
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
updatePushTokenIfNeeded()
}
}
My notification payloads are set up as:
["to" : "fcm_token",
"notification" : ["title" : "Message Title",
"body" : "Message Body",
"sound" : "default",
"badge" : 1]
]
Then my app delegate is as follows:
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
let notificationCenter = UNUserNotificationCenter.current()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
let fcmManager = FCMManager()
fcmManager.registerForPushNotifications()
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
if #available(iOS 14, *) {
completionHandler([.banner])
} else {
completionHandler([.alert])
}
}
}

Why the push notification don‘t work in iOS with Firebase from device to device?

I have created the Production Identifier and all this stuff and it has worked but sometime later suddenly it doesn't work anymore. And I have nothing changed in the Notification Area in my code.
From Firebase Cloud Messaging - Test Sending works fine. But from Device to Device not.
import UIKit
import Firebase
import FirebaseMessaging
import FirebaseInstanceID
import UserNotifications
import AVFoundation
import GoogleMobileAds
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
static let NOTIFICATION_KEY = "https://gcm-http.googleapis.com/gcm/send"
static var DEVICE_ID = String()
static let SERVER_KEY = "AAAACucgXz8:APA91bE_vEyKiqR34sruY2f5tetjj_DrwVi42v9tL015tLEOZmwBh-q7oWsNXUrpR0S9XBCrbxMJtgUu70xNAyDeouNvxn1kHKll2Dcwzxbf40lbappxs-o6IDvHVvEajzX5Dzsq8MW8"
static var EXITAPP = Bool()
static var LIKESCOUNTER = Int()
var dateForm = DateFormatter()
var timeFormatter = DateFormatter()
static var INSERTTIME = false
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible() //Damit wir die ganzen Views selber bearbeiten können.
window?.rootViewController = UINavigationController(rootViewController: ViewController())
if #available(iOS 10.0, *){
UNUserNotificationCenter.current().delegate = self
let option: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: option) { (bool, err) in
}
}
application.registerForRemoteNotifications()
UIApplication.shared.applicationIconBadgeNumber = 0
GADRewardBasedVideoAd.sharedInstance().load(GADRequest(), withAdUnitID: "ca-app-pub-3940256099942544/1712485313")
if #available(iOS 9.0, *){
application.isStatusBarHidden = true //HIDE STATUS BAR
}
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
insertOnlineActivity(online: false)
connectToFCM()
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
AppDelegate.EXITAPP = true
// if AppDelegate.INSERTTIME{
// insertLastLikedTime()
// }
insertOnlineActivity(online: false)
connectToFCM()
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
insertOnlineActivity(online: true)
connectToFCM()
}
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.
insertOnlineActivity(online: true)
connectToFCM()
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String){
guard let newToken = InstanceID.instanceID().token() else {return}
AppDelegate.DEVICE_ID = newToken
connectToFCM()
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
let notification = response.notification.request.content.body
print(notification)
completionHandler()
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
guard let newToken = InstanceID.instanceID().token() else {return}
//let newToken = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
AppDelegate.DEVICE_ID = newToken
connectToFCM()
Messaging.messaging().setAPNSToken(deviceToken, type: .unknown)
}
func connectToFCM(){
Messaging.messaging().shouldEstablishDirectChannel = true
}
This is how I call the Notification
fileprivate func setUpPushNotifications(fromDeviceID: String){
let message = self.userName + " has sent you a voice message."
let title = "New Message"
let toDeviceID = fromDeviceID
var headers:HTTPHeaders = HTTPHeaders()
headers = ["Content-Type":"application/json","Authorization":"key=\(AppDelegate.SERVER_KEY)"]
let notifications = ["to" : "\(toDeviceID)" , "notification":["body":message,"title":title,"badge":1,"sound":"default"]] as [String : Any]
request(AppDelegate.NOTIFICATION_KEY as URLConvertible, method: .post as HTTPMethod, parameters: notifications, encoding: JSONEncoding.default, headers: headers).response { (response) in
print(response)
}
}

FCM push notification not showing when app is open in swift 3

I want to show fcm message any time if my app is open or not open.I want to catch message and save core data.when my app is opened I will get my message but notification alert doesn't show. But when I close my app it shows my message but I did not get my message in background.. here is my appDelegate
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate , UNUserNotificationCenterDelegate,MessagingDelegate{
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
// For iOS 10 data message (sent via FCM
Messaging.messaging().remoteMessageDelegate = self
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
FirebaseApp.configure()
return true
}
//MARK: FCM Token Refreshed
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
// FCM token updated, update it on Backend Server
}
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("Messaging",messaging)
print("remoteMessage*******************",remoteMessage)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (_ options: UNNotificationPresentationOptions) -> Void) {
print("Handle push from foreground")
// custom code to handle push while app is in the foreground
print("\(notification.request.content.userInfo)")
if UIApplication.shared.applicationState == .active { // In iOS 10 if app is in foreground do nothing.
print("active****")
completionHandler([])
} else { // If app is not active you can show banner, sound and badge.
print("Not active****")
completionHandler([.alert, .badge, .sound])
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("Handle push from background or closed")
print("\(response.notification.request.content.userInfo)")
}
func tokenRefreshNotification(notification: NSNotification) {
let refreshedToken = InstanceID.instanceID().token()
// print("fcm**************************","Dhruw: Connected to FCM. Token : \(String(describing: refreshedToken))")
var fcm_token = String(describing: refreshedToken!)
print("fcm toker********",fcm_token);
connectToFCM()
}
func connectToFCM() {
Messaging.messaging().shouldEstablishDirectChannel = true
}
func applicationWillResignActive(_ application: UIApplication) {
}
func applicationDidEnterBackground(_ application: UIApplication) {
}
func applicationWillEnterForeground(_ application: UIApplication) {
}
func applicationDidBecomeActive(_ application: UIApplication) {
}
func applicationWillTerminate(_ application: UIApplication) {
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Finjo_Expense_Management")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
guard let messageId = userInfo["gcm.message_id"]
else {
return
}
print(messageId)
print("did*****",userInfo);
let aps = userInfo[AnyHashable("aps")] as? NSDictionary
var message = aps?["alert"] as! String;
print("message",message)
}
// Called when APNs has assigned the device a unique token
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Convert token to string
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
// Print it to console
print("APNs device token: \(deviceTokenString)")
//09256B251D3BBEAA50949067DF40AB75E5D2668170AB0C3B0D310205F2876C32
// Persist it in your backend in case it's new
}
// Called when APNs failed to register the device for push notifications
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
// Print the error to console (you should alert the user that registration failed)
print("APNs registration failed: \(error)")
}
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)")
}
}
}
}
With Advance thanks...Please help me
When app is open you need to set localnotification for showing notifications.. otherwise you need to show custom view.

FBSDKLoginManager logInWithReadPermissions:fromViewController:handler:]: unrecognized selector sent to instance 0x7fed38d61290

I can't seem to resolve this issue. I went in and deleted all parse and fb SDKs and then downloaded the newest parse and fb SDKs and put into project.
Still getting this error in logs. Don't even get to fb screen. Below is my code. I have researched all instances of this issue and yet no resolve. I am missing something.
AppDelegate.swift:
import UIKit
import Parse
import ParseFacebookUtilsV4
import Bolts
// If you want to use any of the UI components, uncomment this line
// import ParseUI
// If you want to use Crash Reporting - uncomment this line
// import ParseCrashReporting
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
//--------------------------------------
// MARK: - UIApplicationDelegate
//--------------------------------------
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Enable storing and querying data from Local Datastore.
// Remove this line if you don't want to use Local Datastore features or want to use cachePolicy.
Parse.enableLocalDatastore()
let parseConfiguration = ParseClientConfiguration(block: { (ParseMutableClientConfiguration) -> Void in
ParseMutableClientConfiguration.applicationId = "xxx"
ParseMutableClientConfiguration.clientKey = "xxx"
ParseMutableClientConfiguration.server = "https://yourapp.herokuapp.com/parse"
})
Parse.initializeWithConfiguration(parseConfiguration)
PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions)
PFUser.enableAutomaticUser()
let defaultACL = PFACL();
// If you would like all objects to be private by default, remove this line.
defaultACL.publicReadAccess = true
PFACL.setDefaultACL(defaultACL, withAccessForCurrentUser:true)
if application.applicationState != UIApplicationState.Background {
// Track an app open here if we launch with a push, unless
// "content_available" was used to trigger a background push (introduced in iOS 7).
// In that case, we skip tracking here to avoid double counting the app-open.
let preBackgroundPush = !application.respondsToSelector("backgroundRefreshStatus")
let oldPushHandlerOnly = !self.respondsToSelector("application:didReceiveRemoteNotification:fetchCompletionHandler:")
var noPushPayload = false;
if let options = launchOptions {
noPushPayload = options[UIApplicationLaunchOptionsRemoteNotificationKey] != nil;
}
if (preBackgroundPush || oldPushHandlerOnly || noPushPayload) {
PFAnalytics.trackAppOpenedWithLaunchOptions(launchOptions)
}
}
if application.respondsToSelector("registerUserNotificationSettings:") {
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
let types: UIRemoteNotificationType = [UIRemoteNotificationType.Badge, UIRemoteNotificationType.Alert, UIRemoteNotificationType.Sound]
application.registerForRemoteNotificationTypes(types)
}
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}
//--------------------------------------
// MARK: Push Notifications
//--------------------------------------
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let installation = PFInstallation.currentInstallation()
installation.setDeviceTokenFromData(deviceToken)
installation.saveInBackground()
PFPush.subscribeToChannelInBackground("") { (succeeded, error) in
if succeeded {
print("ParseStarterProject successfully subscribed to push notifications on the broadcast channel.");
} else {
print("ParseStarterProject failed to subscribe to push notifications on the broadcast channel with error = %#.", error)
}
}
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
if error.code == 3010 {
print("Push notifications are not supported in the iOS Simulator.")
} else {
print("application:didFailToRegisterForRemoteNotificationsWithError: %#", error)
}
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
PFPush.handlePush(userInfo)
if application.applicationState == UIApplicationState.Inactive {
PFAnalytics.trackAppOpenedWithRemoteNotificationPayload(userInfo)
}
}
func application(application: UIApplication,
openURL url: NSURL,
sourceApplication: String?,
annotation: AnyObject) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}
func applicationDidBecomeActive(application: UIApplication) {
FBSDKAppEvents.activateApp()
}
}
ViewController.swift:
import UIKit
import Parse
import FBSDKCoreKit
import FBSDKLoginKit
import ParseFacebookUtilsV4
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// array of what we want to get from the fb user account
let permissions = ["public_profile"]
PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) {
(user: PFUser?, error: NSError?) -> Void in
if let error = error { // if error exists
print(error)
} else {
if let user = user { // if user exists
print(user)
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}