在越狱设备上本地拉取通知 [英] pull notification locally on jailbroken device

查看:104
本文介绍了在越狱设备上本地拉取通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Since the iOS framework doesn't allow local notifications to execute code before they are posted, I'm looking for a way to achieve it on a jailbroken device.


  • 是否在越狱设备上内置功能,以安排代码执行而无需用户进行交互?

  • 代码应下载更新并确定是否用户应该收到通知。

  • 想要使用推送通知,这需要外部服务器将其推送给用户。

  • Is there built in functionally on a jailbroken device to schedule code execution with no need for the user to interact?
  • The code should download updates and determine if the user should receive a notification.
  • I don't want to use push notifications, which requires an external server to push them to the user.

更新

好吧,我成功创造了一个守护进程,它在启动时启动并保持运行。
但是,发布通知需要 UIApplication 对象。根据文档,这个单例是由 UIApplicationMain()方法,对于常规应用程序,由 main()调用。由于我希望通知由守护进程发布,因此单例为零。

Well, I've managed to create a daemon which launches on start-up and keeps itself running. However, posting notifications requires the UIApplication object. According to the documentation this singleton is created by the UIApplicationMain() method which, for a regular application is called by main(). Since I want the notification be posted by a daemon, the singleton is nil.

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

Can I create an instance of UIApplication? Or post the notification any other way?

我试过调用 UIApplicationMain()然后在app appate中发布通知,以及杀死应用程序,但这显示黑屏暂时;我想它启动了应用程序。此外,当应用程序无法启动时(当手机尚未完全启动时),它会导致守护程序崩溃。

I've tried calling UIApplicationMain() and then posting the notification in the app delegate, as well as killing the application, but this shows a black screen for a moment; I guess its launching the application. Moreover, it causes the daemon to crash when app launching is impossible (when the phone is yet to fully boot).

这是代码的草图

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应用程序(或不)。

Yes. You can make this work with a background (launch) daemon that triggers a notification (not necessarily a UILocalNotification). When the notification shows the user an alert, your daemon can then decide to open a normal UI application (or not).

这是我找到的最佳教程。启动守护程序在手机启动时启动,并作为非图形后台进程一直运行。从那里,您可以安排检查更新。 (我有一个 HelloDaemon 类,它在 run:方法中完成所有工作):

This is the best tutorial I've found. The launch daemon starts when the phone boots, and runs all the time as a non-graphical background process. From there, you can schedule your check for updates. (I have a HelloDaemon class which does all its work in the run: method):

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 通常情况下,安排另一个计时器(在运行:内),以便随时检查下载更新。

Daemons can use NSTimer normally, so schedule another timer (within run:) to check for updates to download whenever you want.

如果守护程序决定通知用户 ,则可以:

If the daemon decides that the user should be notified, then you can either:

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

1) open the full UI application.

#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。启动应用程序您的守护程序成功使用它的权利。 请参阅此处以添加权利。你的daemon 可执行文件需要一个entitlements.xml文件,如下所示:

This code requires the com.apple.springboard.launchapplications entitlement for your daemon to use it successfully. See here for adding an entitlement. You'd need an entitlements.xml file for your daemon executable, like this:

<!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)显示,通知用户该事件,并提示他们打开UI应用程序

2) show a simple alert window from your daemon, notifying the user of the event, and prompting them to open the UI app

#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 标头以我上面的方式使用代码。你可以通过谷歌搜索找到一个,或者在这里看到一个。此较旧的wiki文档还显示了一些使用 CFUserNotification的好信息

You'll need a CFUserNotification.h header to use the code the way I did above. You can find one by googling, or see one here. This older wiki document also shows some good information for using CFUserNotification from iOS apps.

我链接到的答案上面的KennyTM 还显示了如何设置警报弹出窗口,即使设备已被锁定。

The answer I linked to from KennyTM above also shows how you can make your alert popup show, even if the device is locked.

这篇关于在越狱设备上本地拉取通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆