Thông báo đẩy iOS: làm thế nào để phát hiện xem người dùng đã nhấn vào thông báo khi ứng dụng đang ở chế độ nền?


116

Có rất nhiều chủ đề stackoverflow liên quan đến chủ đề này, nhưng tôi vẫn không tìm thấy giải pháp tốt.

Nếu ứng dụng không có trong nền, tôi có thể kiểm tra launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]trong application:didFinishLaunchingWithOptions:cuộc gọi để xem nếu nó mở từ một thông báo.

Nếu ứng dụng đang ở chế độ nền, tất cả các bài đăng đề xuất sử dụng application:didReceiveRemoteNotification:và kiểm tra trạng thái ứng dụng. Nhưng như tôi đã thử nghiệm (và cũng như tên của API này gợi ý), phương thức này được gọi khi nhận được thông báo, thay vì được nhấn.

Vì vậy, vấn đề là, nếu ứng dụng được khởi chạy và sau đó ở chế độ nền và bạn biết thông báo được nhận từ application:didReceiveNotification( application:didFinishLaunchWithOptions:sẽ không kích hoạt tại thời điểm này), làm cách nào để bạn biết liệu người dùng đã tiếp tục ứng dụng từ biểu tượng ứng dụng? Bởi vì nếu người dùng nhấn vào thông báo, kỳ vọng là sẽ mở trang được đề cập trong thông báo đó. Nếu không thì không nên.

Tôi có thể sử dụng handleActionWithIdentifiercho thông báo hành động tùy chỉnh, nhưng điều này chỉ được kích hoạt khi nhấn vào nút tác vụ tùy chỉnh, không phải khi người dùng nhấn vào nội dung chính của thông báo.

Cảm ơn.

BIÊN TẬP:

sau khi đọc một câu trả lời dưới đây, tôi nghĩ theo cách này tôi có thể làm rõ câu hỏi của mình:

Làm thế nào chúng ta có thể phân biệt 2 tình huống này:

(A) 1. ứng dụng chuyển sang nền; 2. thông báo nhận được; 3. người dùng chạm vào thông báo; 4. ứng dụng đi vào nền trước

(B) 1. ứng dụng chuyển sang nền; 2. thông báo nhận được; 3. người dùng bỏ qua thông báo và chạm vào biểu tượng ứng dụng sau đó; 4. ứng dụng đi vào nền trước

Kể từ application:didReceiveRemoteNotification:được kích hoạt trong cả hai trường hợp ở bước 2.

Hoặc, chỉ nên application:didReceiveRemoteNotification:được kích hoạt ở bước 3 cho (A), nhưng bằng cách nào đó tôi đã định cấu hình ứng dụng của mình sai nên tôi thấy nó ở bước 2?


Sử dụng giá trị từ điển tùy chỉnh cho tải trọng của bạn và hành động tương ứng. Khá đơn giản.
soulhined

@soulshined một từ điển trong payload có thể cho biết liệu người dùng có nhấn vào thông báo hay không, phải không? ví dụ: người bạn A của bạn đã đăng một bài báo B, bạn có thể nói {user: A, article: B} trong tải trọng, trong khi ứng dụng đang ở chế độ nền và bạn nhận được didReceiveRemoteNotification. Làm thế nào để bạn biết khi ứng dụng hoạt động trở lại, liệu bạn có nên hiển thị bài viết hay không?
Bao Lei

2
@soulshined Tôi đã đọc tài liệu và tôi đã tự học về những gì đã làmReceiveRemoteNotification làm. Bạn đã thực sự đọc câu hỏi của tôi? Theo tài liệu chính thức của Apple didReceiveRemoteNotification "cho đại biểu biết rằng ứng dụng đang chạy đã nhận được thông báo từ xa". Tôi đang hỏi đâu là cách tốt để biết liệu người dùng có nhấn vào thông báo hay không. Liên kết SO mà bạn đề cập đến là khi ứng dụng đang chạy từ một khởi đầu mới, tôi đang hỏi kịch bản khi ứng dụng ở chế độ nền.
Bao Lei


1
@soulshined OK có lẽ tôi đã không trình bày đủ rõ ràng. Ý tôi là nếu ứng dụng bị thoát hoàn toàn, không chạy trong nền, thì didFinishLaunching sẽ được gọi. Nhưng nếu bạn khởi chạy ứng dụng của mình, sau đó chạy nền ứng dụng và bây giờ một thông báo xuất hiện và người dùng nhấn vào thông báo và bây giờ didFinishLaunching sẽ không được gọi lại. Thay vào đó applicationWillEnterForeground và applicationDidBecomeActive sẽ được gọi. Làm cách nào bạn có thể biết ứng dụng đang vào nền trước vì người dùng đã nhấn vào thông báo hoặc biểu tượng ứng dụng?
Bao Lei

Câu trả lời:


102

OK, cuối cùng tôi đã tìm ra.

Trong cài đặt mục tiêu ➝ tab Khả năng ➝ Chế độ nền, nếu bạn chọn "Thông báo từ xa", application:didReceiveRemoteNotification:sẽ được kích hoạt ngay khi có thông báo (miễn là ứng dụng ở chế độ nền) và trong trường hợp đó, không có cách nào để biết liệu người dùng sẽ nhấn vào thông báo.

Nếu bạn bỏ chọn hộp đó, application:didReceiveRemoteNotification:sẽ chỉ được kích hoạt khi bạn nhấn vào thông báo.

Hơi lạ khi chọn hộp này sẽ thay đổi cách một trong các phương thức ủy nhiệm ứng dụng hoạt động. Sẽ đẹp hơn nếu hộp đó được chọn, Apple sử dụng hai phương pháp ủy quyền khác nhau để nhận thông báo và nhấn thông báo. Tôi nghĩ rằng hầu hết các nhà phát triển luôn muốn biết liệu thông báo có được khai thác hay không.

Hy vọng rằng điều này sẽ hữu ích cho bất kỳ ai khác gặp phải vấn đề này. Apple cũng không ghi lại rõ ràng nó ở đây nên tôi phải mất một lúc để tìm hiểu.

nhập mô tả hình ảnh ở đây


6
Tôi đã đặt Chế độ nền thành "TẮT" hoàn toàn, nhưng vẫn nhận được thông báo khi có thông báo đến với ứng dụng ở chế độ nền.
Gottfried

5
Tuyệt quá! Điều này đã giúp tôi. Tuy nhiên, thật tiếc khi tôi cần tắt thông báo từ xa. Tôi muốn tìm nạp trước dữ liệu khi có thông báo đẩy VÀ phát hiện người dùng nhấn. Tôi không thể tìm ra cách để đạt được điều này.
Peter Fennema

1
Tôi đặt chế độ Nền thành chế độ "BẬT" và bật thông báo từ xa. Vẫn không thể phát hiện sự kiện thông báo.
kalim sayyad

1
Tôi gặp sự cố tương tự Chế độ nền được đặt thành "BẬT" và bật thông báo từ xa, nhưng vẫn không nhận được thông báo khi thông báo đến ứng dụng ở chế độ nền
Swapnil Dhotre

@Bao - Tôi nghĩ rằng nó sẽ gây ra từ chối trên Appstore, vì tùy chọn này về cơ bản được sử dụng để tải xuống nội dung liên quan đến thông báo trong nền. Vì vậy, nếu bạn không tải xuống bất kỳ nội dung nào, Apple có thể từ chối ứng dụng của bạn. developer.apple.com/library/ios/documentation/iPhone/Conceptual/…
niks

69

Tôi đã tìm kiếm điều tương tự như bạn và thực sự đã tìm thấy một giải pháp không yêu cầu thông báo từ xa được đánh dấu.

Để kiểm tra xem người dùng đã nhấn hay ứng dụng đang chạy nền hay đang hoạt động, bạn chỉ cần kiểm tra trạng thái ứng dụng trong

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{

    if(application.applicationState == UIApplicationStateActive) {

        //app is currently active, can update badges count here

    }else if(application.applicationState == UIApplicationStateBackground){

        //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

    }else if(application.applicationState == UIApplicationStateInactive){

        //app is transitioning from background to foreground (user taps notification), do what you need when user taps here

    }

Để biết thêm thông tin, hãy kiểm tra:

Tham chiếu khung UIKit> Tham chiếu lớp ứng dụng UIA> UIApplicationState


10
Điều gì về ứng dụng là UIApplicationStateInactive do người dùng tương tác với Trung tâm thông báo (vuốt từ trên xuống) hoặc Trung tâm điều khiển (vuốt từ dưới lên) khi ứng dụng đang ở trên màn hình. Rõ ràng, không có cách nào để biết liệu APNS đã được nhận ở trạng thái Không hoạt động hay người dùng thực sự nhấn vào nó.
Kostia Kim,

1
@KostiaKim Bạn nói đúng, nhưng đó là một trường hợp siêu cạnh ... ngoài ra, câu trả lời này là hợp lệ nhất trong điều kiện phân tách giữa các ứng dụng ở phía trước ... người dùng nhấn vào ... ứng dụng trong nền
Honey

Cảm ơn, loại này làm sáng tỏ mọi thứ. Hãy nhớ rằng để phương thức ủy quyền được gọi khi ứng dụng ở chế độ nền, thông báo đẩy phải bao gồm content-availablekhóa, nhưng sau đó thông báo phải im lặng (tức là không bao gồm âm thanh hoặc huy hiệu) như đã nêu trong tài liệu chính thức .
Nickkk

1
@KostiaKim Tôi thực sự đã có thể khắc phục sự cố không biết liệu trung tâm điều khiển có đang mở hay người dùng thực sự nhấn vào thông báo bằng cách thêm boolean được đặt thành true trong func applicationDidEnterBackground(_ application: UIApplication)và false trong func applicationDidBecomeActive(_ application: UIApplication)điều này cho phép tôi hiển thị trong ứng dụng hay không thông báo khi ứng dụng không hoạt động do trung tâm điều khiển hoặc các danh sách thông báo
DatForis

3
nó làm tôi bối rối tại sao Apple không trình bày một sự kiện khác hoặc chỉ đơn giản là thêm một cờ trong siêu dữ liệu để cho biết rằng người dùng thực sự đã tương tác với thông báo. Việc phải 'suy luận' xem liệu người dùng có thực hiện hành động dựa trên thông tin xung quanh về trạng thái ứng dụng hay không là khá bất hợp lý đối với một chút thông tin quan trọng ảnh hưởng đến kỳ vọng của người dùng về hành vi ứng dụng. Có lẽ điều duy nhất cần làm là tạo một hành động tùy chỉnh để mở ứng dụng với thông tin đó?
Allan Nienhuis

20

Theo iOS / XCode: làm thế nào để biết ứng dụng đó đã được khởi chạy bằng cách nhấp vào thông báo hoặc trên biểu tượng ứng dụng bàn đạp? bạn phải kiểm tra trạng thái ứng dụng trong didReceiveLocalNotification như sau:

if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive)
{
    // user has tapped notification
}
else
{
    // user opened app from app icon
}

Mặc dù nó không hoàn toàn có ý nghĩa đối với tôi, nhưng nó có vẻ hiệu quả.


1
Nó sẽ không hoạt động trong trường hợp này. Tôi đã thử điều đó trước đây. Khi hộp kiểm đó được chọn (xem câu trả lời được chấp nhận của tôi để biết chi tiết), khi thông báo đến, dòng của bạn với nhận xét "// người dùng đã nhấn thông báo" sẽ được nhập, mặc dù người dùng không nhấn vào thông báo (thông báo vừa đến ).
Bao Lei

3
Tôi không đồng ý. Tôi đã chọn "Thông báo từ xa" trong khả năng nền của mình và nó hoạt động theo cách được mô tả trong câu trả lời của tôi. Tôi cũng đã chọn "Tìm nạp nền". Có thể điều đó gây ra sự thay đổi?
Werner Kratochwil

bạn có thể vui lòng +1 câu trả lời của tôi không? ;-) Tôi vẫn cần một số phiếu bầu để tham gia nhiều hơn vào stackoverflow. Thanks a lot
Werner Kratochwil

Yupe, đây là giải pháp. tnx.
Afshin

Lưu ý rằng điều này sẽ là dương tính giả nếu thông báo được gửi trong khi người dùng đang ở trên 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

16

Nếu ai đó muốn nó trong 3.0 nhanh chóng

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
    }

cho nhanh chóng 4

switch UIApplication.shared.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
}

Chúng ta nên thêm mã này vào trình kích hoạt nào, didReceiveRemoteNotification hay didFinishLaunchingWithOptions?
Dashrath

2
Trên didReceiveRemoteNotification
Hamid Shahsavari

@Hamid sh ,,,, Tôi nhận được thông báo đẩy ở tất cả các trạng thái tức là khi ứng dụng ở chế độ nền, nền, đóng (chấm dứt) ..! nhưng vấn đề của tôi là làm thế nào để tăng số lượng huy hiệu khi ứng dụng ở trạng thái nền và trạng thái đóng (kết thúc) ???? Xin vui lòng cho tôi biết chi tiết làm thế nào tôi làm điều đó ....? số huy hiệu ứng dụng của tôi chỉ tăng lên khi ứng dụng ở trạng thái nền .....? nếu có thể xin vui lòng cho tôi biết ngắn gọn .......!
Kiran jadhav,

8

Nếu bạn đã chọn "Chế độ nền"> "Thông báo từ xa" == CÓ, hãy nhấn vào sự kiện thông báo sẽ đến:

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

Nó đã giúp đỡ tôi. Hãy tận hưởng đi nhé :)


Tôi thấy rằng Apple đã thêm điều này nhưng không thể tìm ra cách tải trọng tải tùy chỉnh của thông báo theo cách này.
sudo

Chức năng này được gọi khi ứng dụng ở trạng thái nền và trở nên hoạt động và cũng như khi ứng dụng bắt đầu từ trạng thái bị giết
Nikhil Muskur

@NikhilMuskur chỉ khi "thông báo từ xa" được bật hả bạn?
Zorayr

@Zorayr vâng, đúng vậy
Nikhil Muskur

8

Tôi cũng gặp phải sự cố này - nhưng trên iOS 11 với UserNotifications Framework .

Ở đây đối với tôi nó như thế này:

  • Khởi chạy mới: application:didFinishLaunchingWithOptions:
  • Nhận từ trạng thái kết thúc: application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
  • Đã nhận ở nền trước: userNotificationCenter(_:willPresent:withCompletionHandler:)
  • Đã nhận trong nền: userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:

Đây là cách thực hiện trong iOS 11 +
OhadM

Điều này thật phức tạp 🤦‍♂️
Zorayr

4

Trong trường hợp của tôi, chế độ nền TẮT không tạo ra bất kỳ sự khác biệt nào. Tuy nhiên, khi ứng dụng bị tạm ngưng và người dùng nhấn vào thông báo, tôi có thể xử lý trường hợp này trong phương pháp gọi lại này:

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

}

Đây là cách chính thức mà Apple nói. Theo tài liệu của Apple, nó sẽ được gọi bất cứ khi nào người dùng tương tác với giao diện người dùng thông báo đẩy. Nếu ứng dụng không ở chế độ nền, nó sẽ khởi chạy ứng dụng ở chế độ nền và gọi phương thức này.
Ryan

3

Đối với iOS 10 trở lên, hãy đưa tính năng này vào AppDelegate, để biết thông báo được nhấn (hoạt động ngay cả khi ứng dụng đang đóng hoặc mở)

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
print("notification tapped here")
}

1
Đây là câu trả lời chính xác cho iOS 10+. Giải thích đầy đủ được cung cấp trên một chủ đề khác tại đây: stackoverflow.com/a/41783666/1761357 .
dead_can_dance

2

Có hai Hàm cho xử lý đã nhận PushNotification bên trong PushNotificationManagerlớp:

class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate{

}

Khi tôi thử nghiệm kích hoạt đầu tiên ngay sau khi Thông báo đến

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

    completionHandler(UNNotificationPresentationOptions.alert)

    //OnReceive Notification
    let userInfo = notification.request.content.userInfo
    for key in userInfo.keys {
         Constants.setPrint("\(key): \(userInfo[key])")
    }

    completionHandler([])

}

Và cái thứ hai khi chạm vào Thông báo:

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

    //OnTap Notification
    let userInfo = response.notification.request.content.userInfo
    for key in userInfo.keys {
        Constants.setPrint("\(key): \(userInfo[key])")
    }

    completionHandler()
}

Tôi cũng đã thử nghiệm nó với cả trạng thái BẬT và TẮT của Thông báo từ xa (ở Chế độ nền)


1

SWIFT 5.1

UIApplication.State không hoạt động đối với tôi, vì khi tôi đọc dấu vân tay (phương thức được hiển thị) trong ứng dụng của mình, thông báo cũng được đưa vào thanh trên và người dùng phải nhấp vào nó.

Tôi đã tạo

public static var isNotificationFromApp: Bool = false

trong AppDelegatevà tôi đặt nó trueở bắt đầu của tôi viewControllervà sau đó trong thông báo của tôi storyboard/ viewControllerTôi chỉ kiểm tra xem :)

Hy vọng nó có thể hữu ích


-7

Bạn có thể định cấu hình tải trọng của thông báo đẩy của mình để gọi application:didReceiveRemoteNotification:fetchCompletionHandler:phương thức của đại biểu ứng dụng khi ứng dụng ở chế độ nền. Bạn có thể đặt một số cờ ở đây để khi người dùng khởi chạy ứng dụng của bạn vào lần tiếp theo, bạn có thể thực hiện thao tác của mình.

Từ tài liệu của apple, bạn nên sử dụng các phương pháp này để tải xuống nội dung mới được liên kết với thông báo đẩy. Ngoài ra, để tính năng này hoạt động, bạn phải bật Thông báo từ xa từ chế độ Nền và trọng tải thông báo đẩy của bạn phải chứa content-availablekhóa với giá trị được đặt thành 1. Từ thông tin khác, vui lòng xem Sử dụng Thông báo đẩy để bắt đầu phần Tải xuống từ apple doc tại đây .

Một cách khác là có số lượng huy hiệu trong trọng tải thông báo đẩy. Vì vậy, lần tới khi ứng dụng của bạn khởi chạy, bạn có thể kiểm tra số lượng huy hiệu ứng dụng. Nếu khối lượng của nó lớn hơn 0, hãy thực hiện thao tác của bạn và đồng thời đếm số huy hiệu không / xóa từ máy chủ.

Hy vọng điều này sẽ giúp bạn.


@bhusan bạn đã đọc chi tiết câu hỏi của tôi chưa? Tôi thấy didReceiveRemoteNotification được gọi khi thông báo vừa đến (trước khi người dùng nhấn vào nó). Tôi muốn tìm hiểu xem liệu người dùng có nhấn vào nó hay không.
Bao Lei

Bạn đã không trả lời câu hỏi của OP. Anh ấy không chỉ muốn biết rằng đã có một thông báo. Anh ấy muốn biết liệu người dùng có mở Ứng dụng hay không bằng cách nhấn vào thông báo từ xa đó.
Joe C
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.