2

I have a SpringBoard hook which listens to Distributed notifications. Various other apps I have hooked post notification which are received in SpringBoard.

If I pass userInfo as null, SpringBoard receives notifications from all apps. If I pass CFDictionaryRef as userInfo, SpringBoard receives notifications from only SpringBoard and SystemApps. However user apps are not able to send notifications. (Or rather not received by Springboard).

CFDictionaryRef is innocent and not the culprit because I am able to pass it when sender and receiver are system apps.

Is there a restriction that User Apps cannot send userInfo object to System Apps?

EDIT: Attaching the code. I compile it using iOSOpenDev. Rely on NSLog to debug. Scenario 1: If you touch SpringBoard, you would see 2 logs for notification send and notification received. Scenario 2: Invoke any system app like clock etc, you would see both logs. Scenario 3: Any app from app store, like SketchBookX etc, and only one log will be printed for notification send. Its not received.

I have tried all flavors of CFNotificationCenterPostNotification but nothing works.

#import <UIKit/UIKit.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFNotificationCenter.h>
#include "GraphicsServices/GSEvent.h"

#define GS_EVENT_TYPE_OFFSET 2
#define HOME_DOWN 1000
#define HOME_UP 1001
#define VOL_DOWN_KEY_DOWN 1008
#define VOL_DOWN_KEY_UP 1009

extern "C" CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void);


void LogEvent(CFNotificationCenterRef center,
          void *observer,
          CFStringRef name,
          const void *object,
          CFDictionaryRef userInfo)
{

NSString *str = [[NSString alloc]initWithFormat:@"%@,%@,%d,%d,%d,%d,%d\r\n",
     (NSString*)CFDictionaryGetValue(userInfo,@"strWindow"),
     (NSString*)CFDictionaryGetValue(userInfo,@"strView"),
     [(NSNumber*)CFDictionaryGetValue(userInfo,@"phase") intValue],
     [(NSNumber*)CFDictionaryGetValue(userInfo,@"xInView") intValue],
     [(NSNumber*)CFDictionaryGetValue(userInfo,@"yInView") intValue],
     [(NSNumber*)CFDictionaryGetValue(userInfo,@"xInWindow") intValue],
     [(NSNumber*)CFDictionaryGetValue(userInfo,@"yInWindow") intValue]];

    NSLog(@"Area51 Notification Received: %@",str);
}

%hook UIApplication
-(void) sendEvent:(UIEvent*)event
{

if(  [NSStringFromClass([event class]) isEqualToString:@"UITouchesEvent"] )
{

    NSSet *touches = [event allTouches];

    NSEnumerator *enumerator = [touches objectEnumerator];
    id value;

    while ((value = [enumerator nextObject])) {
        UITouch *touch = value;
        NSString *strViewClassName;
        if(!touch.view)
            strViewClassName = @" ";
        else
            strViewClassName = [NSString stringWithString:NSStringFromClass([[touch view] class])];

        CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL,0,&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

        CFDictionaryAddValue(dictionary, @"phase", [NSNumber numberWithInt:[touch phase]] );
        CFDictionaryAddValue(dictionary, @"strWindow", NSStringFromClass([[touch window] class]) );
        CFDictionaryAddValue(dictionary, @"strView", strViewClassName);
        CFDictionaryAddValue(dictionary, @"xInView", [NSNumber numberWithInt:[touch locationInView:touch.view].x]) ;
        CFDictionaryAddValue(dictionary, @"yInView", [NSNumber numberWithInt:[touch locationInView:touch.view].y]) ;
        CFDictionaryAddValue(dictionary, @"xInWindow", [NSNumber numberWithInt:[touch locationInView:nil].x]) ;
        CFDictionaryAddValue(dictionary, @"yInWindow", [NSNumber numberWithInt:[touch locationInView:nil].y]) ;

        CFNotificationCenterPostNotificationWithOptions(
             CFNotificationCenterGetDistributedCenter(),
             (CFStringRef)@"RecordTouch",
             NULL,
             dictionary,
             kCFNotificationDeliverImmediately|kCFNotificationPostToAllSessions);

            NSLog(@"Area 51: Notification Send for App: %@",[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] );

    }

}

%orig;
}

%end

%hook SpringBoard
-(void)applicationDidFinishLaunching:(UIApplication*) application
{

CFNotificationCenterAddObserver(
    CFNotificationCenterGetDistributedCenter(),
    NULL,
    LogEvent,
    NULL,
    NULL,
    CFNotificationSuspensionBehaviorDeliverImmediately);

NSLog(@"Area51: ObserverAdded");

%orig;
}

%end

__attribute__((constructor)) void area51init() {

%init;
}
TorukMakto
  • 2,066
  • 2
  • 24
  • 38
  • Please post the code you're using to send notifications, and the code you use to listen for them. – Nate Aug 10 '13 at 09:34
  • @Nate - I have added the code. Hope it helps. – TorukMakto Aug 11 '13 at 05:46
  • Hmmm. I can't see anything wrong. I'd start with a simpler example. First, make sure when you have **no** dictionary (`userInfo`), the notification always succeeds. Then, add a simple dictionary, with just one string key, and one string value. Build complexity from there. See what causes it to fail. You might try starting from another example (e.g. [this one for OSX](http://skype4pidgin.googlecode.com/svn/trunk/skype_messaging_carbon2.c)). Process of elimination :( – Nate Aug 17 '13 at 08:03
  • @Nate - Without, dictionary it works. The point I send dictionary, it stops working. (A very simple dictionary also doesn't work). – TorukMakto Aug 19 '13 at 04:58
  • @Nate - Sorry, I have not got chance to try it. I will be trying it over weekend. Will surely let you know.. – TorukMakto Aug 21 '13 at 04:16
  • @Jailbroken, were you able to find a solution for the dictionary? I saw the same issue. – gran_profaci Jan 03 '17 at 22:27

1 Answers1

0

The problem seems to be that userInfo is ignored (and thus NULL) when using a Darwin Notification Center as center. Source

Also see this thread.

Community
  • 1
  • 1
Clawish
  • 2,934
  • 3
  • 24
  • 28