ios - 在越狱设备上本地拉取通知

标签 ios notifications jailbreak

由于 iOS 框架不允许本地通知在发布之前执行代码,因此我正在寻找一种在越狱设备上实现它的方法。

  • 越狱设备上是否有内置功能来安排代码执行而无需用户交互?
  • 代码应下载更新并确定用户是否应收到通知。
  • 不想使用推送通知,这需要外部服务器将它们推送给用户。

更新

好吧,我已经设法创建了一个在启动时启动并保持自身运行的守护进程。 但是,发布通知需要 UIApplication 对象。根据documentation此单例由 UIApplicationMain() 方法创建,对于常规应用程序,该方法由 main() 调用。由于我希望通知由守护程序发布,因此单例为 nil。

我可以创建 UIApplication 的实例吗?或者以其他方式发布通知?

我试过调用 UIApplicationMain() 然后在应用程序委托(delegate)中发布通知,并终止应用程序,但这会暂时显示黑屏;我猜它正在启动应用程序。此外,当应用程序无法启动时(当手机尚未完全启动时),它会导致守护程序崩溃。

这里是代码草图

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

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

最佳答案

... Or post the notification any other way?

。您可以使用触发通知的后台(启动)守护进程(不一定 UILocalNotification)使它工作。当通知向用户显示警报时,您的守护程序可以决定打开(或不打开)普通 UI 应用程序。

构建启动守护进程。

This is the best tutorial I've found .启动守护进程在手机启动时启动,并一直作为非图形后台进程运行。从那里,您可以安排检查更新。 (我有一个 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: 内)检查更新,以便随时下载。

从守护进程通知用户

如果守护进程决定应该通知用户,那么您可以:

1) 打开完整的 UI 应用程序。

#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 权限,您的守护程序才能成功使用它。 See here for adding an entitlement .您需要一个 entitlements.xml 文件用于您的守护程序可执行文件,如下所示:

<!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) 显示 simple alert window从您的守护程序,通知用户该事件,并提示他们打开 UI 应用

#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 header 才能按照我上面的方式使用代码。你可以通过谷歌搜索找到一个,或see one here .这older wiki document还显示了一些关于在 iOS 应用程序中使用 CFUserNotification 的有用信息。

answer I linked to from KennyTM above还展示了如何使警报弹出窗口显示,即使设备已锁定也是如此。

关于ios - 在越狱设备上本地拉取通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15025174/

相关文章:

ios - 主观 iPhone/Core 数据设置民意调查

ios - 类型 'UITextField' 没有成员 'textDidBeginEditingNotification'

ios - 如何分析 iOS 应用程序以在 theos 中进行调整

iphone - 如何在未加入 iPhone Developer Program 的情况下在越狱的 iPhone 上构建和安装应用程序?

android - 通知将无法使用通知管理器和 notification.builder

ios - Theos实例方法调用

ios - 如何禁用特定 UITableViewCell 的图像?

自定义键盘中不支持 iOS CBManagerState.

Objective-C XMPPFramework 离线队列

laravel - 测试通知后数据库通知不显示