Ответ 1
... Или отправить уведомление любым другим способом?
Да. Вы можете сделать эту работу с фоновым (запуском) демоном, который запускает уведомление (не обязательно UILocalNotification
). Когда уведомление показывает пользователю предупреждение, ваш демон может затем решить открыть обычное приложение пользовательского интерфейса (или нет).
Создайте демон запуска.
Это лучший учебник, который я нашел. Демон запуска запускается при загрузке телефона и выполняется все время как неграфический фоновый процесс. Оттуда вы можете запланировать проверку обновлений. (У меня есть класс HelloDaemon
, который выполняет всю свою работу в методе run:
):
int main(int argc, char *argv[]) {
@autoreleasepool {
HelloDaemon* daemon = [[HelloDaemon alloc] init];
// start a timer so that the process does not exit.
NSTimer* timer = [[NSTimer alloc] initWithFireDate: [NSDate date]
interval: 1.0
target: daemon
selector: @selector(run:)
userInfo: nil
repeats: NO];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer: timer forMode: NSDefaultRunLoopMode];
[runLoop run];
}
return 0;
}
Демоны могут нормально использовать NSTimer
, поэтому планируйте еще один таймер (в пределах run:
), чтобы проверить, что обновления загружаются, когда захотите.
Уведомлять пользователя из Daemon
Если демон решает, что пользователь должен быть уведомлен, вы можете либо:
1) откройте полное приложение пользовательского интерфейса.
#include <dlfcn.h>
#define SBSERVPATH "/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices"
-(void) openApp {
// the SpringboardServices.framework private framework can launch apps,
// so we open it dynamically and find SBSLaunchApplicationWithIdentifier()
void* sbServices = dlopen(SBSERVPATH, RTLD_LAZY);
int (*SBSLaunchApplicationWithIdentifier)(CFStringRef identifier, Boolean suspended) = dlsym(sbServices, "SBSLaunchApplicationWithIdentifier");
int result = SBSLaunchApplicationWithIdentifier(CFSTR("com.mycompany.AppName"), false);
dlclose(sbServices);
}
Этот код требует права com.apple.springboard.launchapplications
для вашего демона, чтобы использовать его успешно. См. здесь для добавления права. Вам нужен файл entitlements.xml для исполняемого файла daemon, например:
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.springboard.launchapplications</key>
<true/>
</dict>
</plist>
2) показать простое окно предупреждений от вашего демона, уведомив пользователя о событии и предложив им открыть приложение пользовательского интерфейса
#include "CFUserNotification.h"
-(void) showAlert {
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
[dict setObject: @"Alert!" forKey: (__bridge NSString*)kCFUserNotificationAlertHeaderKey];
[dict setObject: @"Updates Ready!" forKey: (__bridge NSString*)kCFUserNotificationAlertMessageKey];
[dict setObject: @"View" forKey:(__bridge NSString*)kCFUserNotificationDefaultButtonTitleKey];
[dict setObject: @"Cancel" forKey:(__bridge NSString*)kCFUserNotificationAlternateButtonTitleKey];
SInt32 error = 0;
CFUserNotificationRef alert =
CFUserNotificationCreate(NULL, 0, kCFUserNotificationPlainAlertLevel, &error, (__bridge CFDictionaryRef)dict);
CFOptionFlags response;
// we block, waiting for a response, for up to 10 seconds
if((error) || (CFUserNotificationReceiveResponse(alert, 10, &response))) {
NSLog(@"alert error or no user response after 10 seconds");
} else if((response & 0x3) == kCFUserNotificationAlternateResponse) {
// user clicked on Cancel ... just do nothing
NSLog(@"cancel");
} else if((response & 0x3) == kCFUserNotificationDefaultResponse) {
// user clicked on View ... so, open the UI App
NSLog(@"view");
[self openApp];
}
CFRelease(alert);
}
Вам понадобится заголовок CFUserNotification.h
, чтобы использовать код так, как я делал выше. Вы можете найти его по googling, или см. Здесь здесь. Этот старый wiki-документ также показывает некоторую полезную информацию для использования CFUserNotification
из приложений iOS.
Ответ который я связал с KennyTM выше, также показывает, как вы можете сделать всплывающее всплывающее окно, даже если устройство заблокировано.