Подтвердить что ты не робот

Вытащить уведомление локально на джейлбрейк-устройстве

Так как инфраструктура iOS не позволяет локальным уведомлениям выполнять код до их размещения, я ищу способ его достижения на устройстве, взломанном на джейлбрейке.

  • Функционально ли встроено вредоносное устройство для планирования выполнения кода, без необходимости взаимодействия с пользователем?
  • Код должен загружать обновления и определять, должен ли пользователь получать уведомление.
  • Я не хочу использовать push-уведомления, для чего внешний сервер должен нажимать на пользователя.

Обновление

Ну, мне удалось создать демона, который запускается при запуске и продолжает работать. Однако для отправки уведомлений требуется объект UIApplication. Согласно documentation этот синглтон создается методом UIApplicationMain(), который для обычного приложения вызывается main(). Поскольку я хочу, чтобы уведомление было опубликовано демоном, singleton равен нулю.

Могу ли я создать экземпляр UIApplication? Или отправить уведомление любым другим способом?

Я попробовал позвонить UIApplicationMain(), а затем опубликовать уведомление в делегате приложения, а также убить приложение, но на этот раз отображается черный экран; Думаю, его запуск приложения. Кроме того, это приводит к сбою демона, когда запуск приложения невозможен (когда телефон еще не загружен).

Вот эскиз кода

int main(){
   if(launchedBySpringBoard || launchedBynotification)
      UIApplicationMain(...);
   else if(launchedByDaeamon)
      StartRunLoop();
}

void triggerdByRunLoopEveryXhours(){
    downloadData();
    if(isNewData())
       postNotification();
}
4b9b3361

Ответ 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 выше, также показывает, как вы можете сделать всплывающее всплывающее окно, даже если устройство заблокировано.

Ответ 2

Прежде всего, позвольте мне сказать, что BigLex дает довольно интересную информацию. Тем не менее, я никогда не пытался написать деамон для взломанного iphone. Таким образом, я не знаю ограничений (и похоже, что есть некоторые - как UIApplication sharedApplication - nil.

Пара мыслей:

фоновый

1) В случае, если вы планируете распространять через Cydia (что означает, что приложения будут находиться на системном томе), вы можете использовать два режима недокумента:

"continuos" (этот будет продолжать работать в фоновом режиме) "unboundedTaskCompletion" (этот будет иметь неограниченное время, если вы сделаете [UIApplication beginBackgroundTaskWithExpirationHandler]

Вы можете посмотреть пример Info.plist здесь, в котором используется континет.

2) Есть и другие способы получить постоянный фон (который не требует даже джейлбрейка устройства).

В качестве примера, общий метод заключается в том, чтобы запускать тихий звук в цикле. Здесь приведен пример того, как это сделать.

Просто имейте в виду, что этот метод не будет приниматься в App Store.

3) В случае, если устройство будет работать с маршрутом 1) или 2), у вас будет доступ к [UIApplication sharedApplication) для отправки локальных уведомлений

4) Вам может быть интересно взглянуть на Backgrounder. Я считаю, что он реализовал возможности фоновой работы для джейлбрейк-устройств. Однако он может быть устаревшим.

Проблемы с демоном с использованием UIApplication

5) Что касается проблем с демонами. Если вы внимательно прочитаете, что статья, вы увидите

Первое, что нужно отметить, - это нехорошо использовать Класс UIApplication для запуска вашего демона (требуется больше памяти, чем мы необходимо), поэтому мы собираемся написать наш собственный основной метод.

Итак, код был оптимизирован для памяти. Тем не менее, я уверен, что вы можете заменить его на общий код приложения iOS:

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

В результате я думаю, что у вас должен быть синтаксис UIApplication и он должен иметь возможность публиковать локальные уведомления.

Да... Он съедет добавление X килобайт памяти, но кто заботится (если вы не используете 100 таких демонов)

Ответ 3

просто гадать, это не реальный ответ, но, возможно, вы можете использовать функцию подключения MobileSubstrate для подключения к процессу обработки уведомлений ОС и сообщить os, чтобы выполнить некоторый код, чтобы проверить, поступило ли уведомление из вашего приложения, и, если это в случае, проверить наличие обновления и решить, должен ли он показывать уведомление?

Или, может быть, вы можете запустить фоновый процесс, который каждые X минут проверяет, есть ли какое-либо обновление, и если это так устанавливает локальное уведомление. Не уверен, как вы могли это сделать, хотя.