Відображення банера сповіщень про iOS, коли ваша програма відкрита і на першому плані?


123

Коли офіційний додаток Apple iOS Messages відкрито і на першому плані, нові повідомлення від інших контактів викликають запас, нативну банер попередження про iOS. Дивіться зображення нижче.

Це можливо в сторонніх програмах в App Store? Місцеві та / або надсилання повідомлень для вашого додатка, коли ваш додаток відкрито і на першому плані ?

Під час тестування мого додатка надходять сповіщення, але не відображається інтерфейс сповіщення про iOS .

Але така поведінка буде побачити в офіційному додатку Повідомлення Apple:

Повідомлення відкриті та на першому плані.  Все ще відображається сповіщення про сповіщення.

У Посібнику з локального та віддаленого сповіщення повідомляється:

Коли операційна система доставляє локальне або віддалене сповіщення, а цільова програма не працює на передньому плані , вона може представити сповіщення користувачеві через попередження , номер значка значка або звук.

Якщо додаток працює на передньому плані під час доставки сповіщення, делегат додатка отримує місцеве або віддалене сповіщення.

Так що так, ми можемо отримувати дані сповіщень, перебуваючи на передньому плані. Але я не бачу способу подати вбудований інтерфейс сповіщень про сповіщення iOS .

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo 
{
    // I know we still receive the notification `userInfo` payload in the foreground.
    // This question is about displaying the stock iOS notification alert UI.

    // Yes, one *could* use a 3rd party toast alert framework. 
    [self use3rdPartyToastAlertFrameworkFromGithub]
}

Тоді в Повідомленнях використовується приватний API для відображення попередження на передньому плані?

Для цього питання, будь ласка, не пропонуйте жодних сторонніх спливаючих сповіщень про github чи ін. Мене цікавить лише те, якщо це можна зробити, використовуючи інтерфейс сповіщень про запас iOS Local або Push Notification, коли ваш програма відкрита і на першому плані .

Відповіді:


152

iOS 10 додає UNUserNotificationCenterDelegateпротокол для обробки сповіщень, коли ваша програма на першому плані.

UNUserNotificationCenterDelegateПротокол визначає методи для отримання повідомлень і для обробки дій. Коли ваша програма стоїть на передньому плані, повідомлення, що надходять, надсилаються об’єкту делегата, а не відображаються автоматично за допомогою системних інтерфейсів.

Швидкий:

optional func userNotificationCenter(_ center: UNUserNotificationCenter, 
                     willPresent notification: UNNotification, 
      withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void)

Завдання-C:

- (void)userNotificationCenter:(UNUserNotificationCenter *)center 
       willPresentNotification:(UNNotification *)notification 
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler;

У UNNotificationPresentationOptions прапори дозволяють задати , UNNotificationPresentationOptionAlertщоб відобразити попередження , використовуючи текст наданого повідомленням.

Це важливо, оскільки дозволяє відображати попередження, коли ваш додаток відкрито та на передньому плані , що є новим для iOS 10.


Приклад коду:

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Set UNUserNotificationCenterDelegate
        UNUserNotificationCenter.current().delegate = self
        
        return true
    }
    
}

// Conform to UNUserNotificationCenterDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {
    
    func userNotificationCenter(_ center: UNUserNotificationCenter,
           willPresent notification: UNNotification,
           withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
    {
        completionHandler(.alert)
    }
    
}

4
Чи можете ви надати зразок робочого коду, де система відображає вхідне повідомлення про передній план, як ніби програма, де фон?
azmeuk

1
@azmeuk Перевір мою відповідь ...
chengsam

8
Не забудьте додати UNUserNotificationCenter.current().delegate = selfв application(_:willFinishLaunchingWithOptions:)або application(_:didFinishLaunchingWithOptions:)методу
DENISS Федотову

3
Також переконайтесь, що у вас немає пристрою в режимі " Не турбуйте", інакше сповіщення будуть видимі в Центрі сповіщень, але вони не будуть представлені на передньому плані над вашою заявкою
Джадент

2
мої 2 центи: не пропустіть: імпортувати UserNotifications. !
ingconti

94

Для відображення банерного повідомлення, коли додаток на передньому плані, використовуйте наступний метод.

iOS 10+, Swift 3+ :

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.alert, .badge, .sound])
}

1
Ого, всюди, де я читав, люди говорили, що це неможливо. Я такий радий, що знайшов цю відповідь, вона працює саме так, як я і очікував! Коли програма запущена, натискання сповіщень тепер показує точно так, як було б, якби програма була у фоновому режимі. Дякую!
Torre Lasley

1
Куди йде цей фрагмент? У додаткуДелегат чи десь ще?
Йоав Р.

@YoavR. AppDelegate
chengsam

Я використав той самий код. Але я не знаю, чому повідомлення не відображається, коли додаток вийшов на перший план.
Boominadha Prakash M

2
Chengsam, можливо, ви хочете це виправити: його не потрібно ставити в AppDelegate. Він повинен бути поставлений для будь-якого об'єкта, який відповідає UNUserNotificationCenterDelegate. Зважаючи на це, більшість розробників AppDelegateдотримуються їх UNUserNotificationCenterDelegate. @YoavR.
Мед

16

Редагувати:

Сповіщення про передній план тепер можливі в iOS 10! Будь ласка, дивіться цю відповідь .

Для iOS 9 і нижче:

Здається, неможливо показати попередження про сповіщення про запаси iOS, коли ваша програма відкрита і на першому плані. Messages.app повинен використовувати приватний API.

Система не відображає жодних сповіщень, значків програми та не відтворює звуків, коли програма вже передовий. - Документи UILocalNotification

Ці UIApplicationDelegateметоди будуть все ще можна назвати, що дозволяє ваш додаток , щоб відповісти на локальному або віддаленому повідомлення:

application:didReceiveLocalNotification:
application:didReceiveRemoteNotification:

Однак основний користувальницький інтерфейс сповіщень про iOS про сповіщення про iOS не відображатиметься так, як це є в Messages.app Apple, який повинен використовувати приватний API.

Найкраще, що ви можете зробити - це розгорнути власний банер попередження або використовувати наявний фреймворк:

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo 
{    
    // Use a 3rd party toast alert framework to display a banner 
    [self toastAlertFromGithub]
}

Я відкрив радар для такої поведінки тут: rdar://22313177


3
Як тоді це робити WhatsApp та інші відомі додатки?
Мачадо

@tardoandre маєте скріншот? Я припускаю, що це наслідує попередження про запас iOS на власні погляди.
пкемб

2
Ви повинні включити посилання, toastAlertFromGithubякщо ви пропонуєте цю бібліотеку третьої сторони використовувати!
Ketan Parmar

14

Щоб відображати сповіщення, поки програма відкрита, нам потрібно обробляти її вручну. Тож, що я роблю нижче, - це обробляти повідомлення, щойно надійшло.

Додайте все нижче в AppDelegate.m

  1. Обробляти дзвінок для повідомлення
  2. Створіть подання, додайте AppIcon, повідомлення з повідомленнями та покажіть його як анімацію
  3. Додати сенсор розпізнавання, щоб зняти його, якщо торкнутися або видалити за 5 секунд з анімацією.

Дайте мені знати, чи це нормальне рішення. Добре працював для мене, але я не впевнений, чи це правильний шлях.

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


NSString *notifMessage = [[userInfo objectForKey:@"aps"] objectForKey:@"alert"];

//Define notifView as UIView in the header file
[_notifView removeFromSuperview]; //If already existing

_notifView = [[UIView alloc] initWithFrame:CGRectMake(0, -70, self.window.frame.size.width, 80)];
[_notifView setBackgroundColor:[UIColor blackColor]];

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10,15,30,30)];
imageView.image = [UIImage imageNamed:@"AppLogo.png"];

UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 15, self.window.frame.size.width - 100 , 30)];
myLabel.font = [UIFont fontWithName:@"Helvetica" size:10.0];
myLabel.text = notifMessage;

[myLabel setTextColor:[UIColor whiteColor]];
[myLabel setNumberOfLines:0];

[_notifView setAlpha:0.95];

//The Icon
[_notifView addSubview:imageView];

//The Text
[_notifView addSubview:myLabel];

//The View
[self.window addSubview:_notifView];

UITapGestureRecognizer *tapToDismissNotif = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                    action:@selector(dismissNotifFromScreen)];
tapToDismissNotif.numberOfTapsRequired = 1;
tapToDismissNotif.numberOfTouchesRequired = 1;

[_notifView addGestureRecognizer:tapToDismissNotif];


[UIView animateWithDuration:1.0 delay:.1 usingSpringWithDamping:0.5 initialSpringVelocity:0.1 options:UIViewAnimationOptionCurveEaseIn animations:^{

    [_notifView setFrame:CGRectMake(0, 0, self.window.frame.size.width, 60)];

} completion:^(BOOL finished) {


}];


//Remove from top view after 5 seconds
[self performSelector:@selector(dismissNotifFromScreen) withObject:nil afterDelay:5.0];


return;


}

//If the user touches the view or to remove from view after 5 seconds
- (void)dismissNotifFromScreen{

[UIView animateWithDuration:1.0 delay:.1 usingSpringWithDamping:0.5 initialSpringVelocity:0.1 options:UIViewAnimationOptionCurveEaseIn animations:^{

    [_notifView setFrame:CGRectMake(0, -70, self.window.frame.size.width, 60)];

} completion:^(BOOL finished) {


}];


}

3
Це може бути хорошою відповіддю для створення власного сповіщення, але воно не показує сповіщення Stock iOS, як показано на знімку екрана.
пкамб

Привіт, дякую за добрі слова. Так, це не виглядатиме так (якщо ви говорите про зовнішній вигляд), оскільки показане вище на зображенні - це iOS-повідомлення, а те, що використовується за допомогою коду, - звичай. Ми можемо повторити зовнішній вигляд у погляді. Я думаю, що у WhatsApp є акуратний вигляд із розмиттям фону тощо
Hafeez

1
Хтось вниз проголосував :(. Було б приємно почути, чому
!?

2
Я зробив, як код в цій відповіді (приємно , хоча це може бути) на насправді не відповісти на питання , запитав: показуючи акції IOS тосту банер всередині програми. Є інші питання щодо ТА, де ця відповідь була б чудовою.
пкамб

1
Дякую pkamb за уточнення, має сенс. Я пропустив слово "запас", я думаю.
Хафез

10

Ось код для отримання Push Notification, коли додаток на передньому плані чи на відкритій сцені, iOS 10 та Swift 2.3

@available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void)
{
     completionHandler([UNNotificationPresentationOptions.Alert,UNNotificationPresentationOptions.Sound,UNNotificationPresentationOptions.Badge])
}

Якщо вам потрібно отримати доступ до userInfo з коду використання сповіщення: notification.request.content.userInfo

Метод userNotificationCenter(_:willPresent:withCompletionHandler:)викликається лише в тому випадку, якщо ви додали до атрибута корисного навантаження content-available:1. Кінцева корисна навантаження повинна бути приблизно такою:

{
     "aps":{
          "alert":"Testing.. (7)",
          "badge":1,"sound":"default"
     },
     "content-available":1
}

1
userNotificationCenter(_:willPresent:withCompletionHandler:)буде викликано, коли ваш додаток працює на передньому плані. Тому НЕ має значення з " вмістом доступним ", який пов'язаний з " фоновим доступом ".
Світанок

9
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.body = body;
content.userInfo = userInfo;
content.sound = [UNNotificationSound defaultSound];
[content setValue:@(YES) forKeyPath:@"shouldAlwaysAlertWhileAppIsForeground"];

UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"Notif" content:content trigger:nil];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
    DLog(@"Error:%@", error);
}];

Я можу показувати push-повідомлення, коли програма активна для iOS 10.

  1. Поштове сповіщення від сервера повинно бути беззвучним .

  2. Коли ви отримуєте віддалене повідомлення від сервера, ви надсилаєте локальне сповіщення та встановлюєте значення для keyPath: shouldAlwaysAlertWhileAppIsForeground = True


у швидкому 2 - це так content.setValue("YES", forKeyPath: "shouldAlwaysAlertWhileAppIsForeground"), правда? (із "Так" і неправда)
Йоав Р.

Увага: Це призведе до збою програми під IOS 12. Див обговорення тут: stackoverflow.com/questions/41373321 / ...
Matt Bearson

5

Ви можете обробляти сповіщення самостійно та показувати власні сповіщення. Такі програми, як Viber, Whatsapp та BisPhone, використовують цей підхід.

Одним із прикладів стороннього користувацького попередження є CRToast .

Спробуйте запланувати місцеве сповіщення, коли ваш додаток на передньому плані, і ви побачите, що не з’являється попередження про запас iOS:

if (application.applicationState == UIApplicationStateActive ) {
     UILocalNotification *localNotification = [[UILocalNotification alloc] init];
    localNotification.userInfo = userInfo;
    localNotification.soundName = UILocalNotificationDefaultSoundName;
    localNotification.alertBody = message;
    localNotification.fireDate = [NSDate date];
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}

Дякуємо, але просто шукаємо відповіді, використовуючи попередження про сповіщення про запаси iOS.
pamamb

1
добре , але я думаю , що ви не можете зробити це, а також подивитися на це посилання: stackoverflow.com/questions/14872088 / ...
Мо Farhand

6
@matt Я намагаюся тримати це питання на тему: показ попередження про запас iOS на першому плані. Багато інших питань "найкращих тостів". Відповідь "Ні, ви не можете показати попередження про iOS на передньому плані" була б цілком прийнятною, і я прийму цю відповідь, поки це не стане можливим у майбутній версії iOS.
pkamb

4

Версія Swift 3

Це показує попередження, коли програма стоїть на передньому плані.

if #available(iOS 10.0, *)
{
    // need to setup the global notification delegate somewhere when your app starts
    //
    UNUserNotificationCenter.current().delegate = applicationDelegate

    // to show a message
    //
    let content = UNMutableNotificationContent()
    content.body = "MESSAGE"

    let request = UNNotificationRequest(identifier: "fred", content: content, trigger: nil)
    UNUserNotificationCenter.current().add(request)
    {
       error in // called when message has been sent

       debugPrint("Error: \(error)")
    }
}

Реалізація ApplicationDelegate UNUserNotificationCenterDelegate

@available(iOS 10.0, *)
public func userNotificationCenter(_ center : UNUserNotificationCenter, willPresent notification : UNNotification, withCompletionHandler completionHandler : @escaping (UNNotificationPresentationOptions) -> Void)
{
    completionHandler([.alert]) // only-always show the alert
}

просто щоб бути впевненим ... ти маєш на увазі, оскільки з iOS 10 ти можеш також показувати сповіщення / банери / звуки на передньому плані, як і у фоновому режимі?
Мед

Де я можу помістити вищевказану кодуючу частину? в чи отриманоРум'яткове повідомлення?
user1960169

@Leslie Godwin працюватиме на ios 8.0 для показу сповіщень на передньому плані
Діліп Тіварі

2

Щоб показати місцеве сповіщення, це найкращий варіант. потрібно менше коду, щоб Райт "BRYXBanner" https://cocoapods.org/pods/BRYXBanner

let banner = Banner(title: "title", subtitle: "subtitle", image: UIImage(named: "addContact"), backgroundColor: UIColor(red:137.0/255.0, green:172.0/255.0, blue:2.0/255.0, alpha:1.000))
    banner.dismissesOnTap = true
    banner.show(duration: 1.0)

Ця BRYXBannerструктура , здається, не використовувати акції повідомлення банер IOS.
пкамб

1

Якщо ваша мета розгортання> = iOS10, використовуйте UNUserNotification, як нижче-

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
    {
        // Change this to your preferred presentation option
        completionHandler([.alert, .sound])
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.