簡體   English   中英

在越獄設備上本地拉取通知

[英]pull notification locally on jailbroken device

由於iOS框架在發布之前不允許本地通知執行代碼,因此我正在尋找一種在越獄設備上實現代碼的方法。

  • 是否在越獄設備上內置功能以安排代碼執行而無需用戶進行交互?
  • 代碼應下載更新並確定用戶是否應收到通知。
  • 不想用推送通知,這需要一個外部服務器,以他們推給用戶。

更新

好吧,我已經成功創建了一個守護進程,它在啟動時啟動並保持運行。 但是,發布通知需要UIApplication對象。 根據文檔,這個單例由UIApplicationMain()方法創建,對於常規應用程序,由main()調用。 由於我希望通知由守護進程發布,因此單例是零。

我可以創建UIApplication的實例嗎? 或者以其他方式發布通知?

我試過調用UIApplicationMain() ,然后在app delegate中發布通知,以及殺死應用程序,但這顯示了一個黑屏暫時; 我想它啟動了應用程序。 此外,當應用程序無法啟動時(當手機尚未完全啟動時),它會導致守護程序崩潰。

這是代碼的草圖

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

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

...或者以其他方式發布通知?

是的 您可以使用觸發通知的后台(啟動)守護程序( 不一定UILocalNotification )來完成此操作。 當通知向用戶顯示警報時,您的守護程序可以決定打開正常的UI應用程序(或不打開)。

構建一個啟動守護進程。

這是我發現的最好的教程 啟動守護程序在手機啟動時啟動,並作為非圖形后台進程一直運行。 從那里,您可以安排檢查更新。 (我有一個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: NSTimer以檢查是否需要隨時下載更新。

從Daemon通知用戶

如果守護程序決定應該通知用戶,那么您可以:

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權利成功使用它。 請參閱此處以添加權利 您需要一個用於守護程序可執行文件的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)從守護程序顯示一個簡單的警報窗口 ,通知用戶該事件,並提示他們打開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頭來像我上面那樣使用代碼。 你可以通過谷歌搜索找到一個,或在這里看到一個 這個較舊的wiki文檔還顯示了使用iOS應用程序中的CFUserNotification一些很好的信息。

我從上面的KennyTM鏈接答案也顯示了如何設置警報彈出窗口,即使設備已被鎖定。

首先,我要說BigLex提供了非常有趣的信息。 但是,我從未試圖為越獄的iPhone寫一個守護神。 所以,我不知道有限制(看起來有一些 - 像UIApplication sharedApplication是零。

幾個想法:

Backgrounding

1)如果您計划通過Cydia進行分發(意味着應用程序最終將在系統卷上),您可以使用兩種無證文檔:

“continuos”(這個將繼續在后台運行)“unboundedTaskCompletion”(這個將有無限的時間,如果你會做[UIApplication beginBackgroundTaskWithExpirationHandler]

你可以在這里看一下使用continouse的示例Info.plist。

2)還有其他方法可以獲得永久性背景(甚至不需要設備越獄)。

例如,常見的方法是在循環上運行靜音。 以下是如何執行此操作的示例。

請注意,此方法不會被App Store接受。

3)在這種情況下,如果您使用路由1)或2),您將可以訪問[UIApplication sharedApplication]發布本地通知

4)您可能有興趣看一下Backgrounder 我相信它為越獄設備實現了后台功能。 但是,它可能已經過時了。

守護進程UIApplication的問題

5)關於守護進程的問題。 如果你仔細閱讀那篇文章,你會看到

首先要注意的是,使用UIApplication類來啟動守護進程(它需要的內存比我們需要的多)是不好的,所以我們將編寫自己的main方法。

因此,那里的代碼針對內存進行了優化。 但是,我很確定您可以使用常見的iOS應用程序代碼替換它:

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

因此,我認為你應該有UIApplication單例,並且應該能夠發布本地通知。

是的...它會消耗額外的X千字節內存,但誰在乎(如果你沒有運行100個這樣的守護進程)

只是猜測,這不是一個真正的答案,但也許你可以使用MobileSubstrate的掛鈎功能來連接操作系統的通知處理過程並告訴操作系統執行一些代碼來檢查通知是否來自你的應用程序,如果是這樣的話,檢查更新並確定是否應顯示通知?

或者也許您可以啟動一個后台進程,每隔X分鍾檢查一次是否有任何更新,如果是,則立即設置本地通知。 不知道你怎么能這樣做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM