Попросите разрешения для локальных уведомлений в iOS 8, но все еще есть поддержка приложений iOS 7
У меня есть приложение, которое использует локальные уведомления. В iOS 7 все работает нормально, но в iOS 8 приложение должно запрашивать у пользователя разрешение на отображение уведомлений. Чтобы запросить разрешение в iOS 8, я использую:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
Он отлично работает в Xcode 6 и iOS 8. Когда я открываю тот же проект в Xcode 5, ошибка является семантической проблемой. "Использование необъявленного идентификатора" UIUserNotificationSettings "."
Как я могу заставить приложение работать с iOS 7 и 8 и корректно работать с уведомлениями в обеих версиях.
Ответы
Ответ 1
Следующий ответ дает несколько предположений:
- При использовании Xcode 6 приложение должно правильно создать базовый SDK iOS 8, и он должен правильно строить базовый SDK iOS 7 при использовании Xcode 5.
- Приложение должно поддерживать целевой объект развертывания iOS 7 (или ранее) независимо от базовой версии SDK и Xcode.
код:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// None of the code should even be compiled unless the Base SDK is iOS 8.0 or later
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
// The following line must only run under iOS 8. This runtime check prevents
// it from running if it doesn't exist (such as running under iOS 7 or earlier).
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
#endif
}
Все это описано в Руководстве по совместимости SDK Apple .
Ответ 2
Я реализовал просто -
if([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
[[UIApplication sharedApplication] registerForRemoteNotifications];
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
} else {
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge];
}
Ответ 3
Если вы все еще хотите скомпилировать файлы с более старыми SDK или имеете специальную причину, вы можете попытаться вызвать весь материал динамически:
#ifdef __IPHONE_8_0
#define USING_IOS8_SDK
#else // iOS <8 SDK compatibility definitions
#define UIUserNotificationTypeNone (0)
#define UIUserNotificationTypeBadge (1 << 0)
#define UIUserNotificationTypeSound (1 << 1)
#define UIUserNotificationTypeAlert (1 << 2)
#endif
...
if ([_sharedApplication respondsToSelector:NSSelectorFromString(@"registerUserNotificationSettings:")])
{
NSUInteger settingsParam = (UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound);
id categoriesParam = nil;
#ifdef USING_IOS8_SDK
// Perform direct call when using iOS 8 SDK
[_sharedApplication registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:settingsParam categories:categoriesParam]];
#else
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
// Do the dynamic stuff
// Get UIUserNotificationSettings class reference
Class settings = NSClassFromString(@"UIUserNotificationSettings");
if (settings) {
// Prepare class selector
SEL sel = NSSelectorFromString(@"settingsForTypes:categories:");
// Obtain a method signature of selector on UIUserNotificationSettings class
NSMethodSignature *signature = [settings methodSignatureForSelector:sel];
// Create an invocation on a signature -- must be used because of primitive (enum) arguments on selector
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.selector = sel;
invocation.target = settings;
// Set arguments
[invocation setArgument:&settingsParam atIndex:2];
[invocation setArgument:&categoriesParam atIndex:3];
// Obtain an instance by firing an invocation
NSObject *settingsInstance;
[invocation invoke];
[invocation getReturnValue:&settingsInstance];
// Retain an instance so it can live after quitting method and prevent crash :-)
CFRetain((__bridge CFTypeRef)(settingsInstance));
// Finally call the desired method with proper settings
if (settingsInstance)
[_sharedApplication performSelector:NSSelectorFromString(@"registerUserNotificationSettings:") withObject:settingsInstance];
}
#pragma clang diagnostic pop
#endif
}
Это должно отлично скомпилироваться в iOS 7 SDK и эффективно работать на устройствах iOS 8, игнорируется на старых.
Перенос проекта на iOS 8 SDK - это еще одно решение, но есть еще варианты.
Ответ 4
Пока этот фрагмент кода работает для меня, и его простое повторное использование:
//-- Set Notification
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
else
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)];
}
Ответ 5
if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
[application registerUserNotificationSettings:settings];
}
Ответ 6
Вы можете попробовать что-то вроде этого:
if (NSClassFromString(@"UIUserNotificationSettings") != nil) {
// your iOS 8 code here
#define isiOS8
}
else {
#undef isiOS8
}
#ifdef isiOS8
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
#endif
Это немного запутаннее, но он отлично работает.
** EDIT ** Улучшенный исправленный код