Pertanyaan Metode Callback jika pengguna menolak Push Prompt Pemberitahuan?


Masalah saya adalah saya ingin menunjukkan layar pemuatan untuk Push Prompt Pemberitahuan awal "Aplikasi ini ingin mengirimi Anda pemberitahuan push."

Jadi jika pengguna hits yes Saya dapat melanjutkan dan memulai aplikasi dalam metode delegasi yang kemudian digunakan:

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
  [self hideLoadingScreen];
}

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
  [self hideLoadingScreen];
}

Namun jika pengguna memukul no, tidak satupun dari metode ini dipanggil, yang masuk akal. Pertanyaan saya adalah, apakah ada metode delegasi yang berbeda yang dipecat jika dia menolak?

Masalah saya adalah jika no dipilih, layar pemuatan tidak pernah hilang. Jadi saya entah bagaimana perlu tahu kapan pengguna selesai dengan seleksi.


32
2017-09-27 14:19


asal


Jawaban:


Di iOS 7, saat push notification notification sistem muncul, aplikasi menjadi tidak aktif dan kebakaran UIApplicationWillResignActiveNotification. Demikian pula ketika pengguna menanggapi prompt (menekan Ya atau Tidak), aplikasi menjadi aktif kembali dan UIApplicationDidBecomeActiveNotification kebakaran.

Jadi Anda dapat mendengarkan pemberitahuan ini, dan kemudian menyembunyikan layar pemuatan Anda.

Catatan: Saat permintaan ditampilkan, tombol Beranda, Pusat Pemberitahuan, dan Pusat Kontrol dinonaktifkan sehingga mereka tidak dapat memicu UIApplicationDidBecomeActiveNotification palsu-positif. Namun jika pengguna menekan tombol Lock maka akan memicu UIApplicationDidBecomeActiveNotification.


29
2018-04-24 22:17



Anda selalu bisa mendapatkan jenis notifikasi yang saat ini diizinkan dari:

UIRemoteNotificationType notificationTypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];

Perlu diingat pengguna juga dapat menonaktifkan notifikasi di pengaturan ponsel.

Jika Anda memeriksa bahwa pada didRegisterForRemoteNotificationsWithDeviceToken Anda harus melihat apakah jenis yang Anda minta diaktifkan.


6
2017-09-27 14:35



Tidak bisa Anda hanya melakukan hal berikut:

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    BOOL pushEnabled = notificationSettings.types & UIUserNotificationTypeAlert;
}

Metode ini harus berupa panggilan balik ke prompt push notification, dan dari sana, Anda dapat memeriksa bitmask untuk melihat apakah pemberitahuan push diaktifkan atau tidak.


1
2018-01-04 21:47



Inilah cara saya melakukannya di Swift 3. Mereka yang menjadi kunci di sini adalah melacak keadaan siklus hidup aplikasi secara internal. Ketika push prompt ditampilkan, aplikasi akan berhenti aktif, tetapi tidak memasuki latar belakang. Ini semua di AppDelegate.swift saya.

Ini adalah peretasan yang sangat besar dan tidak direkomendasikan dalam produksi. Apple dapat mengubah cara peringatan ini ditampilkan dan ini dapat dipecahkan kapan saja. Ini diuji menggunakan berbagai iPhone dan iPad yang menjalankan iOS 9 dan 10.

/// An internal value used to track application lifecycle state
enum ApplicationLifecycleState {
    case willResignActive
    case didEnterBackground
    case willEnterForeground
    case didBecomeActive
    case unknown
}

/// This is used purely for tracking the application lifecycle for handling the system push notification alert
var internalLifecycleState: ApplicationLifecycleState = .unknown {
    didSet {
        // If we're not in the middle of asking for push permissions, none of the below applies, just bail out here
        if !isAskingForPushPermissions { return }

        // WARNING: Application lifecycle trickery ahead
        // The normal application lifecycle calls for backgrounding are as follows:
        // applicationWillResignActive -> applicationDidEnterBackground -> applicationWillEnterForeground -> applicationDidBecomeActive
        // However, when the system push notification alert is presented, the application resigns active, but does not enter the background:
        // applicationWillResignActive -> [user taps on alert] -> applicationDidBecomeActive
        // We can use this discrepancy to our advantage to detect if the user did not allow push permissions

        // If applicationDidBecomeActive
        // AND the previous state was applicationWillResignActive
        // AND the notification types bitmask is 0, we know that the user did not allow push permissions
        // User denied permissions
        if internalLifecycleState == .didBecomeActive
            && oldValue == .willResignActive
            && UIApplication.shared.currentUserNotificationSettings?.types.rawValue == 0 {
            // We're done
            firePushCompletionBlockAndCleanup(registered: false)
        } else {
            // The state below can only be entered on iOS 10 devices.
            // If the user backgrounds the app while the system alert is being shown,
            // when the app is foregrounded the alert will dismiss itself without user interaction.
            // This is the equivalent of the user denying push permissions.
            // On iOS versions below 10, the user cannot background the app while a system alert is being shown.

            if #available(iOS 10, *), internalLifecycleState == .didBecomeActive {
                firePushCompletionBlockAndCleanup(registered: false)
            }
        }
    }
}

/// Used internally to track if the system push notification alert is currently being presented
var isAskingForPushPermissions = false

typealias PushNotificationRegistrationCompletionBlock = ((_ registered: Bool) -> Void)

// ...

func applicationWillResignActive(_ application: UIApplication) {    
    internalLifecycleState = .willResignActive
}

func applicationDidEnterBackground(_ application: UIApplication) {
    internalLifecycleState = .didEnterBackground
}

func applicationWillEnterForeground(_ application: UIApplication) {
    internalLifecycleState = .willEnterForeground
}

func applicationDidBecomeActive(_ application: UIApplication) {
    internalLifecycleState = .didBecomeActive
}

// ...

func setupPushNotifications(_ application: UIApplication = UIApplication.shared, completion: @escaping PushNotificationRegistrationCompletionBlock) {
    isAskingForPushPermissions = true
    pushCompletionBlock = completion
    let settings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil)
    application.registerUserNotificationSettings(settings)
    application.registerForRemoteNotifications()
}

fileprivate func firePushCompletionBlockAndCleanup(registered: Bool) {
    pushCompletionBlock?(registered)
    pushCompletionBlock = nil
    isAskingForPushPermissions = false
}

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

    // application:didRegisterForRemoteNotificationsWithDeviceToken may be called more than once (once for each notification type)
    // By checking that the notification types bitmask is greater than 0, we can find the final time this is called (after the user actually tapped "allow")
    // If the user denied push permissions, this function is never called with a positive notification type bitmask value
    if UIApplication.shared.currentUserNotificationSettings?.types.rawValue ?? 0 > 0 {
        firePushCompletionBlockAndCleanup(registered: true)
    }
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    print("Failed to register for notifications with error: " + error.localizedDescription)
    firePushCompletionBlockAndCleanup(registered: false)
}

Pemakaian:

appDelegate.setupPushNotifications(completion: { [weak self] (registered) in
    // If registered is false, the user denied permissions
})

1
2018-03-19 01:28



Saya kira Anda dapat memiliki variabel BOOL untuk memeriksanya di AppDelegate Anda karena sepertinya tidak ada cara lain selain menggunakan API eksternal. Lihat ini.

AppDelegate.m

// declare a BOOL 
BOOL allow = NO;

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
allow = YES;
  [self hideLoadingScreen];
}

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
  allow = YES;
  [self hiedLoadingScreen];
}

Sekarang saya kira Anda dapat mengakses variabel BOOL ini untuk membedakan ketika Don't allow ditekan atau tidak.


0
2017-09-27 14:33



Ini dia SWIFT 2 contoh kode untuk kalian ... Agak rumit, tapi saya harap komentar saya akan membantu Anda memahaminya.

Definisikan variabel

var appDidBecomeActiveCount = 0
var userDefaults:NSUserDefaults!

AppDelegate - didFinishLaunchingWithOptions

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        userDefaults = NSUserDefaults.standardUserDefaults()
        if userDefaults.valueForKey("FirstLaunche") == nil {
            userDefaults.setBool(true, forKey: "FirstLaunche")
            userDefaults.synchronize()
        }

        // Register for notification
        //iOS 8+
        let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert , UIUserNotificationType.Badge ,UIUserNotificationType.Sound], categories: nil)
        UIApplication.sharedApplication().registerUserNotificationSettings(settings)
        UIApplication.sharedApplication().registerForRemoteNotifications()
}

AppDelegate - applicationDidBecomeActive

func applicationDidBecomeActive(application: UIApplication) {
            //Delay until alert get dismissed and notification type setted in app
            delay(0.5, closure: { () -> () in
                self.checkTheDilemma()
            })
}
//I love this short method <3_<3
func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

Periksa tindakan

func checkTheDilemma (){
        //Checking if this user turned off push notifications or didn't allow it at all
        let notificationType = UIApplication.sharedApplication().currentUserNotificationSettings()?.types

        if userDefaults.valueForKey("FirstLaunche") as! Bool == true {
            //User now is asked for notification permission because it's app's first launche
            // if appDidBecomeActiveCount == 0 --> Pop up message will appeare
            // if appDidBecomeActiveCount == 1 --> Pop up message dismissed
            // if notificationType?.rawValue == 0 --> Notifications off
            // if notificationType?.rawValue > 0  --> Notifications on
            if notificationType?.rawValue == 0
                && appDidBecomeActiveCount == 1 { //If user disabled notifications from pop up alert
                    // ** User just tapped "Don't allow" btn :\
                    // Do what ever you are here for

                    //Now set FirstLaunche = false
                    userDefaults.setBool(false, forKey: "FirstLaunche")
                    userDefaults.synchronize()
            }
        } else {
            if notificationType?.rawValue == 0
                && appDidBecomeActiveCount == 0 { // This guy is not registered for push notification
                    // ** User disabled notifications in past (because this is not his first launch)
            }
        }
        appDidBecomeActiveCount++
    }

0
2018-01-26 20:08



Anda dapat mendeteksi jika pengguna telah membatalkan permintaan pemberitahuan di didRegisterUserNotificationSettings metode yang diaktifkan setelah menelepon registerForRemoteNotificationTypesdengan memeriksa notificationSettings.types.

Jika Anda telah meminta sejumlah pengaturan tetapi notificationSettings.types == UIUserNotificationTypeNone berarti, pengguna tersebut telah membatalkan prompt.

Tapi jangan lupakan itu registerForRemoteNotificationTypes metode sekarang tidak lagi digunakan!


0
2017-12-05 05:47



Untuk Swift 3 dan Swift 4.0  Menggunakan NotificationCenter dan metode AppDelegate didRegister notificationSettings. NotificationSettings menunjukkan apakah pengguna memilih badge, suara, dll. Dan akan menjadi array kosong jika mereka menolak pemberitahuan push. Itu diaktifkan secara khusus ketika pengguna menanggapi pemberitahuan push prompt dan tampaknya apa yang paling devs gunakan, karena itu lebih spesifik daripada memeriksa didBecomeActive. Namun Apple mungkin mengubah ini. Siapa tahu?

Sayangnya, NotificationCenter tidak memiliki nama pemberitahuan prasetel sehingga Anda harus menyiapkan dan ekstensi (lihat akhir) atau menggunakan nilai mentah (SO memiliki lebih banyak tentang ini).

Di AppDelegate:

    func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
      // if not registered users will have an empty set of settings
      let accepted: Bool = !notificationSettings.types.isEmpty
      NotificationCenter.default.post(name: Notification.Name(rawValue: "didRespondToPrompt"), object: self, userInfo: ["didAccept" : accepted])
}

Kemudian amati di mana pun Anda perlu, misalnya dalam pengontrol tampilan:

class MyViewController: UIViewController {

//MARK: - Lifecycle
   override func viewDidLoad() {
      super.viewDidLoad()
      NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.didRespondToPushPrompt(_:)), name: NSNotification.Name(rawValue: "didRespondToPrompt"), object: nil)

   }
    @objc func didRespondToPushPrompt(_ notification: Notification) {

       if let userInfo: [AnyHashable : Any] = notification.userInfo, let didAccept: Bool = userInfo[NSNotificationKeyNames.didAccept] as? Bool, !didAccept {
        //if user doesn't accept, do this...

       } else  {
       //all other situations code goes here
      }

   }
}

Beberapa hal: Pertama, untuk Swift 4.0, saya menggunakan "@objc" di depan satu metode, tetapi itu tidak diperlukan untuk Swift 3.
Juga, untuk menggunakan NotificationCenter, dalam prakteknya saya tidak menggunakan "rawValue". Sebaliknya saya membuat ekstensi seperti ini:

import Foundation

extension NSNotification.Name {
   static let DidRegisterForPushNotifications = NSNotification.Name("DidRegisterForPushNotifications")
}

Yang kemudian bisa saya gunakan seperti ini:

NotificationCenter.default.post(name: Notification.Name.DidRegisterForPushNotifications, object: self, userInfo: ["didAccept" : myBool]) dll, dll.


0
2017-12-22 23:02



Beberapa jawaban di sini tidak relevan lagi, atau lebih rumit dari seharusnya, karena kerangka kerja UserNotifications dan iOS 10 Anda dapat dengan mudah mendapatkan data ini seperti:

let center = UNUserNotificationCenter.current()

// Request permission to display alerts and play sounds.
center.requestAuthorization(options: [.alert, .sound]) 
{ (granted, error) in
  // Enable or disable features based on authorization.
}

0
2017-07-13 07:04