Phát hiện nếu ứng dụng được khởi chạy / mở từ thông báo đẩy


171

Có thể biết ứng dụng đã được khởi chạy / mở từ thông báo đẩy không?

Tôi đoán sự kiện ra mắt có thể được bắt gặp ở đây:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    if (launchOptions != nil) {
         // Launched from push notification
         NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    }
}

Tuy nhiên, làm cách nào tôi có thể phát hiện ra nó đã được mở từ thông báo đẩy khi ứng dụng ở chế độ nền?


6
Đây là một bài viết cũ, nhưng rất hữu ích. Thật không may, các câu trả lời hàng đầu không thực sự giải quyết vấn đề (như các ý kiến ​​chỉ ra). Vui lòng xem xét việc đánh dấu một câu trả lời mới là 'được chấp nhận' vì câu trả lời hiện tại chưa hoàn thành.
MobileVet

1
Câu hỏi này có 100 nghìn lượt xem nhưng câu trả lời được chọn không chính xác hoặc đầy đủ. Đối với khách truy cập, hãy xem xét sắp xếp theo Hoạt động thay vì theo Phiếu bầu để tìm giải pháp hiện đại.
Albert Renshaw

Câu trả lời:


187

Xem mã này:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground  )
    {
         //opened from a push notification when the app was on background
    }
}

giống như

-(void)application:(UIApplication *)application didReceiveLocalNotification (UILocalNotification *)notification

19
@Quản lý. Đây là một câu trả lời hay ở chỗ nó chỉ ra cách phát hiện khi một ứng dụng chạy nền được đưa lên nền trước từ thông báo đẩy. Vì khi ứng dụng không chạy, bạn cần câu trả lời của M.Othman bên dưới.
OpenUserX03

6
Tôi nhận được cuộc gọi đến ứng dụng: didReceiveRemoteNotification: sau khi nhấn vào thông báo bất kể ứng dụng chỉ ở chế độ nền hay không chạy, vì vậy câu trả lời này hoàn toàn phù hợp với nhu cầu của tôi. Đã thử nghiệm trên iOS 7 & 8
Newtz

16
Giống như một số người khác chỉ ra, điều này không phát hiện "khởi chạy / mở từ thông báo đẩy". Điều này được gọi khi nhận được thông báo, không phải khi nó được mở. Vì vậy, nếu bạn nhận được thông báo trong bg nhưng gõ biểu tượng ứng dụng để mở ứng dụng, mã bạn có ở đây vẫn sẽ chạy và bạn có thể mở một trang mà người dùng không có ý định mở.
Bảo Lôi

4
@Quản lý. phương pháp này không cho biết ứng dụng đã được mở thông qua trung tâm thông báo và biểu tượng ứng dụng nếu chế độ nền - thông báo từ xa được chọn. Nó làm khi nó không được kiểm tra. Tôi đã ghi lại sự khác biệt trong bài đăng này: stackoverflow.com/questions/32061897/ trên
Bao Lei

2
Xác nhận rằng điều này hoạt động với Google Cloud Messaging.
CularBytes

127

muộn nhưng có thể hữu ích

Khi ứng dụng không chạy

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

được gọi là ..

bạn cần kiểm tra thông báo đẩy ở đâu

NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
    NSLog(@"app recieved notification from remote%@",notification);
    [self application:application didReceiveRemoteNotification:notification];
} else {
    NSLog(@"app did not recieve notification");
}

2
Lưu ý rằng trong đoạn trích trên, thông báo không nên được khai báo là (UILocalNotification *) mà là (
NSDipedia

1
Bằng cách này, bạn có thể thấy nếu có bất kỳ thông báo nào cho ứng dụng, trong khi không chạy! Câu hỏi là, làm thế nào để phát hiện nếu ứng dụng được mở từ một thông báo. Trong trường hợp này, didReceiveRemoteNotification được gọi, ngay cả khi ứng dụng hoàn toàn không chạy. - Tôi thích câu trả lời của bạn, vì nó khá quan trọng đối với nhiều trường hợp, nhưng không phải là câu trả lời chính xác cho câu hỏi.
Axel Zehden

Là câu trả lời của bạn và câu trả lời này cả hai làm cùng một điều?
Mật ong

38

Vấn đề chúng tôi gặp phải là cập nhật chính xác chế độ xem sau khi ứng dụng được khởi chạy. Có những chuỗi phức tạp của các phương pháp vòng đời ở đây gây nhầm lẫn.

Phương pháp vòng đời

Thử nghiệm cho iOS 10 của chúng tôi đã tiết lộ các trình tự phương pháp vòng đời sau đây cho các trường hợp khác nhau:

DELEGATE METHODS CALLED WHEN OPENING APP  

Opening app when system killed or user killed  
    didFinishLaunchingWithOptions  
    applicationDidBecomeActive    

Opening app when backgrounded  
    applicationWillEnterForeground  
    applicationDidBecomeActive  

DELEGATE METHODS WHEN OPENING PUSH

Opening push when system killed
    [receiving push causes didFinishLaunchingWithOptions (with options) and didReceiveRemoteNotification:background]
    applicationWillEnterForeground
    didReceiveRemoteNotification:inactive
    applicationDidBecomeActive

Opening push when user killed
    didFinishLaunchingWithOptions (with options)
    didReceiveRemoteNotification:inactive [only completionHandler version]
    applicationDidBecomeActive

Opening push when backgrounded
    [receiving push causes didReceiveRemoteNotification:background]
    applicationWillEnterForeground
    didReceiveRemoteNotification:inactive
    applicationDidBecomeActive

Vấn đề

Ok, vậy bây giờ chúng ta cần phải:

  1. Xác định xem người dùng đang mở ứng dụng từ một lần đẩy
  2. Cập nhật chế độ xem dựa trên trạng thái đẩy
  3. Xóa trạng thái để các lần mở tiếp theo không đưa người dùng trở lại vị trí tương tự.

Một mẹo nhỏ là việc cập nhật khung nhìn phải xảy ra khi ứng dụng thực sự hoạt động, đây là phương thức vòng đời tương tự trong mọi trường hợp.

Phác thảo giải pháp của chúng tôi

Dưới đây là các thành phần chính của giải pháp của chúng tôi:

  1. Lưu trữ một notificationUserInfobiến đối tượng trên AppDelegate.
  2. Đặt notificationUserInfo = niltrong cả hai applicationWillEnterForegrounddidFinishLaunchingWithOptions.
  3. Đặt notificationUserInfo = userInfotrongdidReceiveRemoteNotification:inactive
  4. Từ applicationDidBecomeActiveluôn luôn gọi một phương thức tùy chỉnh openViewFromNotificationvà vượt qua self.notificationUserInfo. Nếu self.notificationUserInfokhông thì quay lại sớm, nếu không thì mở chế độ xem dựa trên trạng thái thông báo được tìm thấy trong self.notificationUserInfo.

Giải trình

Khi mở từ một lần đẩy didFinishLaunchingWithOptionshoặc applicationWillEnterForegroundluôn được gọi ngay lập tức trước đó didReceiveRemoteNotification:inactive, vì vậy trước tiên chúng tôi đặt lại thông báoUserInfo trong các phương thức này để không có trạng thái cũ. Sau đó, nếu didReceiveRemoteNotification:inactiveđược gọi, chúng tôi biết rằng chúng tôi đang mở từ một lần đẩy, vì vậy chúng tôi đã thiết lập tính self.notificationUserInfonăng được chọn applicationDidBecomeActiveđể chuyển tiếp người dùng đến đúng chế độ xem.

Có một trường hợp cuối cùng là nếu người dùng mở ứng dụng trong trình chuyển đổi ứng dụng (tức là nhấn đúp vào nút home trong khi ứng dụng ở phía trước) và sau đó nhận được thông báo đẩy. Trong trường hợp này chỉ didReceiveRemoteNotification:inactiveđược gọi, và Will EntryForeground cũng như didFinishLaunching không được gọi nên bạn cần một số trạng thái đặc biệt để xử lý trường hợp đó.

Hi vọng điêu nay co ich.


Cuối cùng một cái gì đó hoạt động, cảm ơn! Tôi muốn tạo một cờ "appResuming" và mở màn hình theo các receivephương thức khi trạng thái ứng dụng được kích hoạt hoặc ứng dụng đang hoạt động trở lại. Điều đó có thể dẫn đến các vấn đề với việc thay đổi VC khi ứng dụng vẫn không hoạt động. Giải pháp của bạn trông rất tuyệt, cho đến khi Apple thay đổi vòng đời một lần nữa.
shelll

Còn iOS 9 thì sao, các phương thức vòng đời được gọi theo cùng một cách và thứ tự? Tôi đã không có thiết bị iOS 9 vì vậy tôi không thể kiểm tra điều này đúng cách.
shelll

2
Có hai trường hợp cạnh khác ngoại trừ trình chuyển đổi ứng dụng. 1) Khi trung tâm thông báo được kéo từ trên xuống và phủ lên ứng dụng 2) Khi bảng điều khiển của iOS có wifi / BT / etc được kéo từ dưới lên và phủ lên ứng dụng. Trong cả ba trường hợp chỉ applicationWillResignActiveđược gọi và sau đó là applicationDidBecomeActive. Vì vậy, sau khi applicationWillResignActiveđược gọi, không lưu thông báo nhận được cho đến khi một applicationDidEnterBackgroundhoặc applicationDidBecomeActiveđược gọi.
shelll

Cảm ơn đã thêm những trường hợp này @shelll. Nó luôn luôn phức tạp hơn! Tôi không chắc chắn về iOS9. Tôi có thể nói rằng có thể an toàn khi cho rằng chúng giống nhau, nhưng ai biết được.
Eric Conner

Chỉ cần một cái đầu lên. Tôi đã thử nghiệm iOS 11 Beta 9 hôm nay và thấy rằng trong trường hợp bạn có ứng dụng của mình ở phía trước, hãy khóa điện thoại và sau đó chọn một thông báo đẩy từ màn hình khóa, nó đang gọi didReceiveRemoteNotification: nền trước khi gọi ứng dụngWill EntryForeground chứ không phải những gì chúng ta đang thấy trên iOS 10 nơi nó gọi là applicationWill EntryForeground và sau đó didReceiveRemoteNotification: không hoạt động - vì vậy đây là trường hợp cạnh chưa được bảo hiểm. Theo tôi đây là một lỗi trong mã iOS, nhưng được đưa ra mức độ phát hành của iOS 11 gần như thế nào, đó là điều cần lưu ý.
Roy

24

Đây là một bài viết mòn ... nhưng nó vẫn còn thiếu một giải pháp thực tế cho vấn đề (như được chỉ ra trong các ý kiến ​​khác nhau).

Câu hỏi ban đầu là về việc phát hiện khi nào ứng dụng được khởi chạy / mở từ thông báo đẩy, ví dụ như người dùng nhấn vào thông báo. Không có câu trả lời thực sự bao gồm trường hợp này.

Lý do có thể được nhìn thấy trong luồng cuộc gọi khi có thông báo đến, application:didReceiveRemoteNotification...

được gọi khi nhận được thông báo lần nữa khi thông báo được gõ bởi người dùng. Bởi vì điều này, bạn không thể biết bằng cách chỉ nhìn vào UIApplicationStatethời tiết người dùng gõ nó.

Ngoài ra, bạn không còn cần phải xử lý tình huống 'khởi động nguội' của ứng dụng application:didFinishLaunchingWithOptions...như application:didReceiveRemoteNotification...được gọi lại sau khi khởi chạy trong iOS 9+ (có thể là 8).

Vì vậy, làm thế nào bạn có thể biết nếu người dùng nhấn bắt đầu chuỗi sự kiện? Giải pháp của tôi là đánh dấu thời gian ứng dụng bắt đầu ra khỏi nền hoặc bắt đầu lạnh và sau đó kiểm tra thời gian đó application:didReceiveRemoteNotification.... Nếu nó nhỏ hơn 0,1, thì bạn có thể chắc chắn rằng vòi đã kích hoạt khởi động.

Swift 2.x

class AppDelegate: UIResponder, UIApplicationDelegate {

  var wakeTime : NSDate = NSDate()        // when did our application wake up most recently?

  func applicationWillEnterForeground(application: UIApplication) {    
    // time stamp the entering of foreground so we can tell how we got here
    wakeTime = NSDate()
  }

  func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
    // ensure the userInfo dictionary has the data you expect
    if let type = userInfo["type"] as? String where type == "status" {
      // IF the wakeTime is less than 1/10 of a second, then we got here by tapping a notification
      if application.applicationState != UIApplicationState.Background && NSDate().timeIntervalSinceDate(wakeTime) < 0.1 {
        // User Tap on notification Started the App
      }
      else {
        // DO stuff here if you ONLY want it to happen when the push arrives
      }
      completionHandler(.NewData)
    }
    else {
      completionHandler(.NoData)
    }
  }
}

Swift 3

class AppDelegate: UIResponder, UIApplicationDelegate {

    var wakeTime : Date = Date()        // when did our application wake up most recently?

    func applicationWillEnterForeground(_ application: UIApplication) {
      // time stamp the entering of foreground so we can tell how we got here
      wakeTime = Date()
    }

  func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

      // ensure the userInfo dictionary has the data you expect
      if let type = userInfo["type"] as? String, type == "status" {
        // IF the wakeTime is less than 1/10 of a second, then we got here by tapping a notification
        if application.applicationState != UIApplicationState.background && Date().timeIntervalSince(wakeTime) < 0.1 {
          // User Tap on notification Started the App
        }
        else {
          // DO stuff here if you ONLY want it to happen when the push arrives
        }
        completionHandler(.newData)
      }
      else {
        completionHandler(.noData)
      }
    }
}

Tôi đã thử nghiệm điều này cho cả hai trường hợp (ứng dụng ở chế độ nền, ứng dụng không chạy) trên iOS 9+ và nó hoạt động như một bùa mê. 0,1s cũng khá bảo thủ, giá trị thực tế là ~ 0,002s nên 0,01 cũng tốt.


1
Đây dường như là giải pháp hoạt động duy nhất phân biệt giữa thực sự nhấn vào thông báo và mở thanh trạng thái trên ứng dụng.
liviucmg

4
Đây là giải pháp làm việc duy nhất từ ​​tất cả các StackOverflow. Điều duy nhất tôi muốn thêm vào, là khi bạn hỗ trợ iOS 10 trở lên, bạn chỉ cần sử dụng UNNotificationCenterAPI, cụ thể là các phương thức UNNotificationCenterDelegate. Các userNotificationCenter(UNUserNotificationCenter, didReceive: UNNotificationResponse, withCompletionHandler: @escaping () -> Void) phương thức gọi func API đó chỉ khi người dùng thực sự gõ vào thông báo.
Từ chối

Làm thế nào để tìm kiếm swift 3?
Jochen Österre Rich

Giải pháp không hoạt động khi ứng dụng ở trạng thái không hoạt động (người dùng vuốt xuống trung tâm thông báo hoặc vuốt lên trung tâm điều khiển) và nhận thông báo. Khi người dùng nhấn vào thông báo, ứng dụng sẽ không nhận được applicationWillEnterForeground cuộc gọi, do đó, giải pháp không thể phát hiện ra vòi.
DevGansta

@DevGansta Khi bạn thêm lớp của mình như UNUserNotificationCenter.current().delegatetrong application:didFinishLaunchingWithOptions, ứng dụng sẽ gọi userNotificationCenter(didReceive response)sau khi nhấn vào trường hợp bạn mô tả
Dorian Roy

22

Khi ứng dụng bị chấm dứt và người dùng nhấn vào thông báo đẩy

public func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
   if launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] != nil {
      print("from push")
    }
}

Khi ứng dụng ở chế độ nền và người dùng chạm vào thông báo đẩy

Nếu người dùng mở ứng dụng của bạn từ cảnh báo hiển thị hệ thống, hệ thống có thể gọi lại phương thức này khi ứng dụng của bạn sắp vào nền trước để bạn có thể cập nhật giao diện người dùng và hiển thị thông tin liên quan đến thông báo.

public func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
  if application.applicationState == .inactive {
    print("from push")
  }
}

Tùy thuộc vào ứng dụng của bạn, nó cũng có thể gửi cho bạn sự thúc đẩy thầm lặng với content-availablebên trong aps, vì vậy hãy lưu ý điều này nữa :) Xem https://stackoverflow.com/a/33778990/1418457


2
Chỉ trả lời mà không cảm thấy như một hack bẩn và chính xác. Những gì tôi đang thiếu là nếu ứng dụng ở chế độ nền và người dùng mở nó bằng tay, làm thế nào để kiểm tra điều đó? Trong khi vẫn có thể kiểm tra khởi động lạnh và đẩy từ nền.
Jochen Österre Rich

1
@ JochenÖsterre Rich Xin chào, tôi tóm tắt tại đây, vui lòng kiểm tra Medium.com/@onmyway133/iêu
onmyway133 6/2/2017

19

Swift 2.0 cho trạng thái 'Không chạy' (Thông báo cục bộ & từ xa)

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


// Handle notification
if (launchOptions != nil) {

    // For local Notification
    if let localNotificationInfo = launchOptions?[UIApplicationLaunchOptionsLocalNotificationKey] as? UILocalNotification {

        if let something = localNotificationInfo.userInfo!["yourKey"] as? String {
            self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
        }


    } else

    // For remote Notification
    if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as! [NSObject : AnyObject]? {

        if let something = remoteNotification["yourKey"] as? String {
            self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
        }
    }

}


return true
}

15

Trong application:didReceiveRemoteNotification:kiểm tra xem bạn đã nhận được thông báo khi ứng dụng của bạn trong foreground hoặc background.

Nếu nó được nhận trong nền, hãy khởi chạy ứng dụng từ thông báo.

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        NSLog(@"Notification received by running app");
    } else {
        NSLog(@"App opened from Notification");
    }
}

3
Lưu ý rằng "Ứng dụng được mở từ Thông báo" sẽ là dương tính giả nếu thông báo được gửi trong khi người dùng ở một màn hình khác (ví dụ: nếu họ kéo thanh trạng thái xuống và sau đó nhận được thông báo từ ứng dụng của bạn).
Kevin Cooper

4
@Kevin Chính xác. Nó khiến bạn tự hỏi tại sao apple dường như đặt một thực tập viên để thiết kế quy trình xử lý thông báo ...
Andreas

làm cách nào chúng tôi có thể phát hiện nếu chúng tôi nhấn vào thông báo nhận được ở trạng thái hoạt động
Mayank Jain

13

Đối với nhanh chóng:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
    PFPush.handlePush(userInfo)

    if application.applicationState == UIApplicationState.Inactive || application.applicationState == UIApplicationState.Background {
        //opened from a push notification when the app was in the background

    }

}

4

Có, bạn có thể phát hiện theo phương thức này trong appDelegate :

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
      /* your Code*/
}

Đối với thông báo địa phương:

- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
{
         /* your Code*/
}

1
Phương pháp này không được gọi nếu ứng dụng không chạy. Đó là những gì được hỏi ở đây
Pfitz

Vấn đề của tôi không phải là xử lý thông báo, mà là biết nó có được mở khi bạn nhấp vào biểu ngữ không (khi ứng dụng ở chế độ nền).
joao

3

nếu ai đó muốn câu trả lời trong swift 3

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    switch application.applicationState {
    case .active:
        //app is currently active, can update badges count here
        break
    case .inactive:
        //app is transitioning from background to foreground (user taps notification), do what you need when user taps here
        break
    case .background:
        //app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
        break
    default:
        break
    }
}

nhưng làm thế nào để biết ứng dụng có được mở hay không bằng cách nhấn vào thông báo đẩy khi ứng dụng bị chấm dứt
3804063

1
khi ai đó chạm vào đẩy, ứng dụng sẽ được mở, bất kể nó có bị chấm dứt hay không. và trường hợp .inactive đang gọi
Hamid Shahsavari

1
Tôi cần phát hiện xem ứng dụng có được mở hay không bằng cách nhấn nút đẩy và muốn điều hướng đến nội dung tương ứng tôi thấy instagram đang làm điều đó
3804063

Làm thế nào về thông báo địa phương?
Amir Shabani

3

Đăng bài này cho người dùng Xamarin.

Chìa khóa để phát hiện nếu ứng dụng được khởi chạy thông qua thông báo đẩy là AppDelegate.FinishedLaunching(UIApplication app, NSDictionary options)phương thức và từ điển tùy chọn được truyền vào.

Từ điển tùy chọn sẽ có khóa này trong đó nếu đó là thông báo cục bộ : UIApplication.LaunchOptionsLocalNotificationKey.

Nếu đó là một thông báo từ xa, nó sẽ được UIApplication.LaunchOptionsRemoteNotificationKey.

Khi khóa là LaunchOptionsLocalNotificationKey, đối tượng là loại UILocalNotification. Sau đó, bạn có thể xem thông báo và xác định đó là thông báo cụ thể.

Pro-tip: UILocalNotificationkhông có định danh trong đó, giống như vậy UNNotificationRequest. Đặt khóa từ điển trong UserInfo có chứa requestId để khi kiểm tra UILocalNotification, bạn sẽ có một requestId cụ thể có sẵn để dựa trên một số logic.

Tôi phát hiện ra rằng ngay cả trên iOS 10+ các thiết bị khi tạo thông báo vị trí bằng cách sử dụng UNUserNotificationCenter's AddNotificationRequest& UNMutableNotificationContent, rằng khi ứng dụng không chạy (tôi giết nó), và được khởi động bằng cách khai thác các thông báo trong trung tâm thông báo, mà điển vẫn chứa các UILocalNotificaitonđối tượng.

Điều này có nghĩa là mã của tôi kiểm tra khởi chạy dựa trên thông báo sẽ hoạt động trên các thiết bị iOS8 và iOS 10+

public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
    _logger.InfoFormat("FinishedLaunching");

    if(options != null)
    {
        if (options.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey))
        {
            //was started by tapping a local notification when app wasn't previously running.
            //works if using UNUserNotificationCenter.Current.AddNotificationRequest OR UIApplication.SharedApplication.PresentLocalNotificationNow);

            var localNotification = options[UIApplication.LaunchOptionsLocalNotificationKey] as UILocalNotification;

            //I would recommended a key such as this :
            var requestId = localNotification.UserInfo["RequestId"].ToString();
        }               
    }
    return true;
}

2

Trực tiếp từ tài liệu cho

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo:nil

Nếu ứng dụng đang chạy và nhận được thông báo từ xa, ứng dụng sẽ gọi phương thức này để xử lý thông báo.

Việc thực hiện phương pháp này của bạn nên sử dụng thông báo để thực hiện một hành động thích hợp.

Và một lát sau

Nếu ứng dụng không chạy khi có thông báo đẩy, phương thức sẽ khởi chạy ứng dụng và cung cấp thông tin phù hợp trong từ điển tùy chọn khởi chạy.

Ứng dụng không gọi phương thức này để xử lý thông báo đẩy đó.

Thay vào đó, việc bạn thực hiện

application:willFinishLaunchingWithOptions:

hoặc là

application:didFinishLaunchingWithOptions:

phương pháp cần lấy dữ liệu tải thông báo đẩy và trả lời thích hợp.


2

Tôi sẽ bắt đầu với một biểu đồ trạng thái mà tôi đã tạo để sử dụng cho riêng mình để trực quan hóa nó một cách chính xác hơn và xem xét tất cả các trạng thái khác: https://docs.google.com.vn ? gid = 0 & đơn = đúng

Sử dụng biểu đồ này, chúng ta có thể thấy những gì thực sự cần thiết để phát triển một hệ thống xử lý thông báo mạnh mẽ, hoạt động trong hầu hết các trường hợp sử dụng có thể.

Giải pháp hoàn chỉnh

  • Lưu trữ tải thông báo trong didReceiveRemoteNotification
  • Xóa thông báo được lưu trữ trong applicationWill EntryForegrounddidFinishLaunchingWithOptions
  • Để giải quyết các trường hợp kéo Trung tâm điều khiển / Trung tâm thông báo, bạn có thể sử dụng cờ willResignActiveCalled và đặt thành sai ban đầu, Đặt điều này thành đúng trong phương thức applicationWillResignActive ,
  • Trong phương thức didReceiveRemoteNotification , chỉ lưu thông báo (userInfo) khi willResignActiveCalled là sai.
  • Đặt lại willResignActiveCalled thành false trong applicationDid EntryBackgroundapplicationDidBecomeActive .

Lưu ý: Câu trả lời tương tự được đề xuất trong các nhận xét về câu trả lời của Eric, tuy nhiên, bảng trạng thái giúp tìm kiếm tất cả các tình huống có thể xảy ra như tôi đã làm trong ứng dụng của mình.

Vui lòng tìm mã hoàn chỉnh bên dưới và nhận xét bên dưới nếu bất kỳ trường hợp cụ thể nào không được xử lý:

Ứng viên

class AppDelegate: UIResponder, UIApplicationDelegate {
  private var willResignActiveCalled = false

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    NotificationUtils.shared.notification = nil
    return true
  }
  func applicationWillResignActive(_ application: UIApplication) {
    willResignActiveCalled = true
  }
  func applicationDidEnterBackground(_ application: UIApplication) {
    willResignActiveCalled = false
  }
  func applicationWillEnterForeground(_ application: UIApplication) {
    NotificationUtils.shared.notification = nil
  }
  func applicationDidBecomeActive(_ application: UIApplication) {
    willResignActiveCalled = false
    NotificationUtils.shared.performActionOnNotification()
  }
  func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    if !willResignActiveCalled { // Check if app is in inactive by app switcher, control center, or notification center
      NotificationUtils.shared.handleNotification(userInfo: userInfo)
    }
  }
}

Thông báoUtils : Đây là nơi bạn có thể viết tất cả mã của mình để điều hướng đến các phần khác nhau của ứng dụng, xử lý Cơ sở dữ liệu (CoreData / Realm) và thực hiện tất cả các công việc khác cần được thực hiện khi nhận được thông báo.

   class NotificationUtils {
  static let shared = NotificationUtils()
  private init() {}

  var notification : [AnyHashable: Any]?

  func handleNotification(userInfo : [AnyHashable: Any]){
    if UIApplication.shared.applicationState == UIApplicationState.active {
      self.notification = userInfo //Save Payload
      //Show inApp Alert/Banner/Action etc
      // perform immediate action on notification
    }
    else if UIApplication.shared.applicationState == UIApplicationState.inactive{
      self.notification = userInfo
    }
    else if UIApplication.shared.applicationState == UIApplicationState.background{
      //Process notification in background,
      // Update badges, save some data received from notification payload in Databases (CoreData/Realm)
    }
  }

  func performActionOnNotification(){
    // Do all the stuffs like navigating to ViewControllers, updating Badges etc
    defer {
      notification = nil
    }
  }
}

tốt hơn nên đặt điều này như một bình luận vì đây không phải là câu trả lời.
Maddy

@Maddy Cảm ơn bạn đã gợi ý, Cập nhật câu trả lời với tất cả các chi tiết
chetan anand

1
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
    print("Push notification received: \(data)")

    if let info = data["aps"] as? Dictionary<String, AnyObject> {
        let alertMsg = info["alert"] as! String
        print(alertMsg)
        switch application.applicationState {
        case .active:
            print("do stuff in case App is active")
        case .background:
            print("do stuff in case App is in background")
           // navigateToChatDetailViewControler(pushdata: data)
        case .inactive:
            print("do stuff in case App is inactive")
            // navigateToChatDetailViewControler(pushdata: data)
        }
    }
}

1

Chỉ có một cách đáng tin cậy và nó chỉ hoạt động cho iOS 10+ :

Sử dụng phương thức UNUserNotificationCenterhiện thực UNUserNotificationCenterDelegate:

- (void) userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {

    //Here you can get your original push if you need to
    NSDictionary* pusDict = response.notification.request.content.userInfo;

    if ([response.actionIdentifier isEqualToString: UNNotificationDefaultActionIdentifier]) {
        //User tapped the notification
    } else if ([response.actionIdentifier isEqualToString: UNNotificationDismissActionIdentifier]) {
        //User dismissed the notification 
    } else if ([response.actionIdentifier isEqualToString: MYCustomActionId]) {
        //User chose my custom defined action
    }
    ...
}

0

Bạn có thể dùng:

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

để xử lý các thông báo đẩy từ xa.

Kiểm tra tài liệu ở đây



0
     // shanegao's code in Swift 2.0
     func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
    {
            if ( application.applicationState == UIApplicationState.Inactive || application.applicationState == UIApplicationState.Background ){
                    print("opened from a push notification when the app was on background")
            }else{
                    print("opened from a push notification when the app was on foreground")
            }
    }

Nhưng nếu ứng dụng bị đóng (chấm dứt). Giống như Twitter hoặc Instagram, bằng cách nào đó, nó phát hiện ra nó và nếu ứng dụng thậm chí bị đóng, nó sẽ chuyển hướng bạn đến bài đăng hoặc hình ảnh mới hoặc hồ sơ của bạn, v.v.
Tarvo Mäesepp

0

Vấn đề với câu hỏi này là "mở" ứng dụng không được xác định rõ. Một ứng dụng được khởi chạy lạnh từ trạng thái không chạy hoặc ứng dụng được kích hoạt lại từ trạng thái không hoạt động (ví dụ: từ việc chuyển trở lại từ ứng dụng khác). Đây là giải pháp của tôi để phân biệt tất cả các trạng thái có thể có:

typedef NS_ENUM(NSInteger, MXAppState) {
    MXAppStateActive = 0,
    MXAppStateReactivated = 1,
    MXAppStateLaunched = 2
};

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // ... your custom launch stuff
    [[MXDefaults instance] setDateOfLastLaunch:[NSDate date]];
    // ... more custom launch stuff
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // Through a lot of trial and error (by showing alerts), I can confirm that on iOS 10
    // this method is only called when the app has been launched from a push notification
    // or when the app is already in the Active state.  When you receive a push
    // and then launch the app from the icon or apps view, this method is _not_ called.
    // So with 99% confidence, it means this method is called in one of the 3 mutually exclusive cases
    //    1) we are active in the foreground, no action was taken by the user
    //    2) we were 'launched' from an inactive state (so we may already be in the main section) by a tap
    //       on a push notification
    //    3) we were truly launched from a not running state by a tap on a push notification
    // Beware that cases (2) and (3) may both show UIApplicationStateInactive and cant be easily distinguished.
    // We check the last launch date to distinguish (2) and (3).

    MXAppState appState = [self mxAppStateFromApplicationState:[application applicationState]];
    //... your app's logic
}

- (MXAppState)mxAppStateFromApplicationState:(UIApplicationState)state {
    if (state == UIApplicationStateActive) {
        return MXAppStateActive;
    } else {
        NSDate* lastLaunchDate = [[MXDefaults instance] dateOfLastLaunch];
        if (lastLaunchDate && [[NSDate date] timeIntervalSinceDate:lastLaunchDate] < 0.5f) {
            return MXAppStateLaunched;
        } else {
            return MXAppStateReactivated;
        }
    }
    return MXAppStateActive;
}

MXDefaultschỉ là một gói nhỏ cho NSUserDefaults.


0

Dành cho swift

 func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]){

    ++notificationNumber
    application.applicationIconBadgeNumber =  notificationNumber;

    if let aps = userInfo["aps"] as? NSDictionary {

        var message = aps["alert"]
        println("my messages : \(message)")

    }
}

0

Xcode 10 Swift 4.2

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {

    let state : UIApplicationState = application.applicationState
    if (state == .Inactive || state == .Background) {
        // coming from background
    } else {
        // App is running in foreground
    }
}

0

Đối với iOS 10+, bạn có thể sử dụng phương pháp này để biết khi nào thông báo của bạn được nhấp bất kể trạng thái của ứng dụng.

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

    //Notification clicked
    completionHandler()
}

0

Câu trả lời của M.Othman là chính xác cho các ứng dụng không chứa đại biểu cảnh cho Ứng dụng phân quyền cảnh Điều này hoạt động với tôi trên iOS 13

Đây là đoạn mã nên được viết trong sẽ kết nối cảnh

if connectionOptions.notificationResponse == nil { 
//Not opened from push notification
} else {
  //Opened from push notification
}

Mã cho đại biểu ứng dụng để hỗ trợ các phiên bản trước didFinishLaunchingWithOptions

let notification = launchOptions?[UIApplication.LaunchOptionsKey.remoteNotification]
        if (notification != nil) {

            //Launched from push notification
        } else {

            //Launch from other source
        }

-1

Dành cho người dùng Swift:

Nếu bạn muốn khởi chạy một trang khác khi mở từ đẩy hoặc một cái gì đó tương tự, bạn cần kiểm tra nó didFinishLaunchingWithOptionsnhư sau:

let directVc: directVC! = directVC(nibName:"directVC", bundle: nil)
let pushVc: pushVC! = pushVC(nibName:"pushVC", bundle: nil)

if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
     self.navigationController = UINavigationController(rootViewController: pushVc!)
} else {
     self.navigationController = UINavigationController(rootViewController: directVc!)
}
self.window!.rootViewController = self.navigationController

Đại biểu không có thành viên điều hướng thành viên
Pablo Cegarra

1
Tạo bộ điều khiển điều hướng trong tệp AppDelegate.h. Đang sử dụng nó và nó hoạt động!
AAA

-1

Ở SWift:

Tôi đang chạy Thông báo đẩy (với tìm nạp nền). Khi ứng dụng của tôi ở chế độ nền và tôi nhận được thông báo đẩy, tôi thấy rằng didReceiveRemoteNotification trong appDelegate sẽ được gọi hai lần; một lần khi nhận được thông báo và lần khác khi người dùng nhấp vào thông báo thông báo.

Để phát hiện nếu cảnh báo thông báo đã được nhấp, chỉ cần kiểm tra xem applicationState raw value == 1 bên trong didReceiveRemoteNotification trong appDelegate.

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject: AnyObject]) {
    // If not from alert click applicationState(1)
    if (application.applicationState.rawValue != 1) {
        // Run your code here
    }
}

Tôi hi vọng cái này giúp được.


-1

Khi ứng dụng ở chế độ nền như shanegao, bạn có thể sử dụng

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground  )
    {
         //opened from a push notification when the app was on background
    }
}

Nhưng nếu bạn muốn khởi chạy ứng dụng và khi đóng ứng dụng và bạn muốn gỡ lỗi ứng dụng của mình, bạn có thể vào Chỉnh sửa lược đồ và trong menu bên trái, chọn Chạy và sau đó khởi chạy, chọn Chờ để thực thi được khởi chạy và sau đó bạn khởi chạy ứng dụng khi bạn khởi chạy bấm vào thông báo đẩy

Chỉnh sửa lược đồ> Chạy> Đợi thực thi được khởi chạy

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.