Accessing Objective C NSDictionary Values in Swift - ios

I am working on a project using Neurosky MindWave to create an IOS app. I am using the ThinkGear SDK for IOS available here: http://developer.neurosky.com/docs/doku.php?id=beta
The project reads values from the MindWave device and stores them in a NSDictionary in Objective C implementation file. I am trying to access these values in my Swift file to control 3D animations in SceneKit.
Here's the set up in the header file:
// the eSense values
typedef struct {
int attention;
int meditation;
} ESenseValues;
// the EEG power bands
typedef struct {
int delta;
int theta;
int lowAlpha;
int highAlpha;
int lowBeta;
int highBeta;
int lowGamma;
int highGamma;
} EEGValues;
#interface RootViewController : UITableViewController <TGAccessoryDelegate> {
short rawValue;
int rawCount;
int buffRawCount;
int blinkStrength;
int poorSignalValue;
int heartRate;
float respiration;
int heartRateAverage;
int heartRateAcceleration;
ESenseValues eSenseValues;
EEGValues eegValues;
bool logEnabled;
NSFileHandle * logFile;
NSString * output;
UIView * loadingScreen;
NSThread * updateThread;
}
// TGAccessoryDelegate protocol methods
- (void)accessoryDidConnect:(EAAccessory *)accessory;
- (void)accessoryDidDisconnect;
- (void)dataReceived:(NSDictionary *)data;
- (UIImage *)updateSignalStatus;
- (void)initLog;
- (void)writeLog;
#property (nonatomic, retain) IBOutlet UIView * loadingScreen;
Here's the Objective C code which stores the values in a dictionary:
// This method gets called by the TGAccessoryManager when data is received from the
// ThinkGear-enabled device.
- (void)dataReceived:(NSDictionary *)data {
[data retain];
NSString * temp = [[NSString alloc] init];
NSDate * date = [NSDate date];
// check to see whether the eSense values are there. if so, we assume that
// all of the other data (aside from raw) is there. this is not necessarily
// a safe assumption.
if([data valueForKey:#"eSenseAttention"]){
eSenseValues.attention = [[data valueForKey:#"eSenseAttention"] intValue];
eSenseValues.meditation = [[data valueForKey:#"eSenseMeditation"] intValue];
temp = [temp stringByAppendingFormat:#"%f: Attention: %d\n", [date timeIntervalSince1970], eSenseValues.attention];
temp = [temp stringByAppendingFormat:#"%f: Meditation: %d\n", [date timeIntervalSince1970], eSenseValues.meditation];
eegValues.delta = [[data valueForKey:#"eegDelta"] intValue];
eegValues.theta = [[data valueForKey:#"eegTheta"] intValue];
eegValues.lowAlpha = [[data valueForKey:#"eegLowAlpha"] intValue];
eegValues.highAlpha = [[data valueForKey:#"eegHighAlpha"] intValue];
eegValues.lowBeta = [[data valueForKey:#"eegLowBeta"] intValue];
eegValues.highBeta = [[data valueForKey:#"eegHighBeta"] intValue];
eegValues.lowGamma = [[data valueForKey:#"eegLowGamma"] intValue];
eegValues.highGamma = [[data valueForKey:#"eegHighGamma"] intValue];
}
if(logEnabled) {
[output release];
output = [[NSString stringWithString:temp] retain];
[self performSelectorOnMainThread:#selector(writeLog) withObject:nil waitUntilDone:NO];
}
//[temp release];
// release the parameter
[data release];
}
Whenever I try to get any of these values I get "Use of unresolved identifier" or similar error. I am trying to display them as 3D text in SceneKit:
override func viewDidLoad() {
super.viewDidLoad()
// Create Scene
let scene = SCNScene()
let myText = SCNText(string: attention , extrusionDepth: 5)
myText.font = UIFont(name: "Optima", size: 1)
let myTextNode = SCNNode(geometry: myText)
myTextNode.position = SCNVector3(x: -2, y: -1, z: -7)
myTextNode.orientation = SCNQuaternion(x: 0.1, y: 0, z: 0.5, w: 0)
scene.rootNode.addChildNode(myTextNode)
}
I'm very new to IOS development and have been working on how to do this for nearly a week now. Any clues on being able to access the values would be very much appreciated.

Related

How to reduce the set of colors in Objective-C

I'm very, very new to Objective-C (this is for a React Native app), and I am trying to pare down a list of colors and remove duplicates.
I've got this so far:
... code related to pulling pixels from an image
float flexibility = 2;
float range = 60;
NSMutableArray * colors = [NSMutableArray new];
float x = 0;
float y = 0;
for (int n = 0; n<(width*height); n++){
int index = (bytesPerRow * y) + x * bytesPerPixel;
int red = rawData[index];
int green = rawData[index + 1];
int blue = rawData[index + 2];
int alpha = rawData[index + 3];
NSArray * a = [NSArray arrayWithObjects:[NSString stringWithFormat:#"%i",red],[NSString stringWithFormat:#"%i",green],[NSString stringWithFormat:#"%i",blue],[NSString stringWithFormat:#"%i",alpha], nil];
[colors addObject:a];
y++;
if (y==height){
y=0;
x++;
}
}
free(rawData);
Now the script I am basing this off of has some code to pare down the list:
NSMutableDictionary * colourCounter = [NSMutableDictionary new];
//count the occurences in the array
NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:colors];
for (NSString *item in countedSet) {
NSUInteger count = [countedSet countForObject:item];
[colourCounter setValue:[NSNumber numberWithInteger:count] forKey:item];
}
//sort keys highest occurrence to lowest
NSArray *orderedKeys = [colourCounter keysSortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2){
return [obj2 compare:obj1];
}];
//checks if the colour is similar to another one already included
NSMutableArray * ranges = [NSMutableArray new];
for (NSString * key in orderedKeys){
NSArray * rgb = [key componentsSeparatedByString:#","];
int r = [rgb[0] intValue];
int g = [rgb[1] intValue];
int b = [rgb[2] intValue];
bool exclude = false;
for (NSString * ranged_key in ranges){
NSArray * ranged_rgb = [ranged_key componentsSeparatedByString:#","];
int ranged_r = [ranged_rgb[0] intValue];
int ranged_g = [ranged_rgb[1] intValue];
int ranged_b = [ranged_rgb[2] intValue];
if (r>= ranged_r-range && r<= ranged_r+range){
if (g>= ranged_g-range && g<= ranged_g+range){
if (b>= ranged_b-range && b<= ranged_b+range){
exclude = true;
}
}
}
}
if (!exclude){ [ranges addObject:key]; }
}
//return ranges array here if you just want the ordered colours high to low
NSMutableArray * colourArray = [NSMutableArray new];
for (NSString * key in ranges){
NSArray * rgb = [key componentsSeparatedByString:#","];
float r = [rgb[0] floatValue];
float g = [rgb[1] floatValue];
float b = [rgb[2] floatValue];
UIColor * colour = [UIColor colorWithRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f];
[colourArray addObject:colour];
}
//if you just want an array of images of most common to least, return here
//return [NSDictionary dictionaryWithObject:colourArray forKey:#"colours"];
I ultimately want to return this colourArray (the original library uses colour, I use color, so you'll sometimes see one or the other spelling - I'll probably standardize it to color when finished).
However, whenever I use this code, RN generates an error:
As far as I can tell, this is due to calling a function that doesn't exist? Is there something I am missing here, or calling incorrectly?

IOS How record midi file with Midi input callback?

I try to record midi file with an Ipad.
My Ipad is pluged with the usb output of my electric piano.
I have read the apple core midi documentation and I have understand that :
For record a file, I should create a MusicSequence. So that I try to do but It doesn't work :(
Here is my code:
Firstly, I setup my midi connection:
-(void) setupMIDI {
MIDIClientRef client = nil;
MIDIClientCreate(CFSTR("Core MIDI to System Sounds Demo"), MyMIDINotifyProc, (__bridge void *)(self), &client);
inputPort = nil;
MIDIInputPortCreate(client, CFSTR("Input port"), MyMIDIReadProc, (__bridge void *)(self), &inputPort);
sequence = nil;
NewMusicSequence(&(sequence));
unsigned long sourceCount = MIDIGetNumberOfSources();
[self appendToTextView:[NSString stringWithFormat:#"%ld sources\n", sourceCount]];
for (int i = 0; i < sourceCount; ++i) {
MIDIEndpointRef src = MIDIGetSource(i);
CFStringRef endpointName = NULL;
OSStatus nameErr = MIDIObjectGetStringProperty(src, kMIDIPropertyName, &endpointName);
if (noErr == nameErr) {
[self appendToTextView: [NSString stringWithFormat:#" source %d: %#\n", i, endpointName]];
}
MIDIPortConnectSource(inputPort, src, NULL);
MusicSequenceSetMIDIEndpoint(sequence, src);
}
}
After that, I receive my Midi event with MyMIDIReadProc which is a callback function of my input port :
static void MyMIDIReadProc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon)
{
AppViewController *vc = (__bridge AppViewController*) refCon;
MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
for (int i=0; i < pktlist->numPackets; i++) {
Byte midiStatus = packet->data[0];
Byte midiCommand = midiStatus >> 4;
// is it a note-on or note-off
if ((midiCommand == 0x09) ||
(midiCommand == 0x08)) {
Byte note = packet->data[1] & 0x7F;
Byte velocity = packet->data[2] & 0x7F;
NSLog(#"midiCommand=%d. Note=%d, Velocity=%d\n", midiCommand, note, velocity);
MIDINoteMessage noteMessage;
noteMessage.releaseVelocity = 0;
noteMessage.velocity = velocity;
noteMessage.note = note;
MusicTrackNewMIDINoteEvent(vc->musicTrack, packet->timeStamp, &noteMessage);
packet = MIDIPacketNext(packet);
}
}
I try to transform MIDIPklist on MIDINoteMessage to add it on my track.
When I have finished that, I create the file with this function :
-(void) createMidiFile
{
// init sequence
NewMusicSequence(&sequence);
CFURLRef pathUrl = (__bridge CFURLRef)[NSURL fileURLWithPath:self.path];
//set track to sequence
MusicSequenceNewTrack(sequence, &musicTrack);
// write sequence in file
MusicSequenceFileCreate(sequence,
pathUrl,
kMusicSequenceFile_MIDIType,
kMusicSequenceFileFlags_EraseFile,
0);
}
The file has been created but the data aren't correct. It have every time the same size.
Thanks if you can help me to debug that ! I don't understand what I have to do to fill the track and sequence object for create a good mid file...
Sorry for my english guys.. :)
I'm trying to solve same problem. From what I can see - the MIDINoteMessage needs to have a duration which corresponds to the delta of note on and subsequent note off call. You have to keep track of this.
The callback should be performed on main thread and you need to be using CACurrentMediaTime to stash the times midi timestamps prior to dumping out the midi file. Some of the code below.
The other alternative approach was sourced from apple forums
"Create a MusicSequence, add a MusicTrack to it, add some midi events to the track via MusicTrackNewMidiNoteEvent, set that MusicSequence on a newly created MusicPlayer, and start the player. Now that you have that player playing you can query it for the current time in beats via the MusicPlayerGetTime function. Set that time for the MusicTimeStamp for midi messages you send to MusicTrackNewMidiNoteEvent.
**Important Note - You MUST populate the MusicTrack for the MusicPlayer that you are querying for the time stamp, or it won't play! You'll get an error (probably (-50) depending on if you set everything else up correctly). I did this with a loop, adding a message with a time stamp starting at zero, going up to four. I would guess that you don't even have to go that high, but the Track has to have something for the player to play. Don't worry about it running off the end since all we want It for is the MusicTimeStamp. The MusicPlayer will continue playing until you tell it to stop."
This code is the closest I've come to answer - although this is targeting IOS.
https://github.com/benweitzman/ReTune/blob/ee47009999298c2b03527302c3fb6d7be17b10e2/Return4/ViewController.m
#interface NoteObject : NSObject
#property (nonatomic) int time;
#property (nonatomic) int note;
#property (nonatomic) int velocity;
#property (nonatomic) bool noteOn;
#end
- (void) midiSource:(PGMidiSource*)midi midiReceived:(const MIDIPacketList *)packetList
{
[self performSelectorOnMainThread:#selector(addString:)
withObject:#"MIDI received:"
waitUntilDone:NO];
const MIDIPacket *packet = &packetList->packet[0];
for (int i = 0; i < packetList->numPackets; ++i)
{
//[self performSelectorOnMainThread:#selector(addString:)
// withObject:[self StringFromPacket:packet]
// waitUntilDone:NO];
if (packet->length == 3) {
if ((packet->data[0]&0xF0) == 0x90) {
if (packet->data[2] != 0) {
[self noteOn:packet->data[1] withVelocity:packet->data[2]];
} else {
[self noteOff:packet->data[1]];
}
} else if ((packet->data[0]&0xF0) == 0x80) {
[self noteOff:packet->data[1]];
}
}
packet = MIDIPacketNext(packet);
}
}
- (void) noteOff:(int)noteValue {
//NSLog(#"off");
if (noteValue>=0 && noteValue<127) {
ALSource * source = [sources objectAtIndex:noteValue];
ALSource *loopSource = [loopSources objectAtIndex:noteValue];
if (source.playing || loopSource.playing) {
[[fadingOut objectAtIndex:noteValue] release];
[fadingOut replaceObjectAtIndex:noteValue withObject:[[NSNumber alloc] initWithBool:YES]];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
float timeDone = 0;
float duration = 0.2;
float timeStep = 0.01;
float valStep = source.gain*timeStep/duration;
float loopStep = loopSource.gain*timeStep/duration;
while (timeDone < duration) {
if (![[fadingOut objectAtIndex:noteValue] boolValue]) break;
source.gain -= valStep;
loopSource.gain -= loopStep;
[NSThread sleepForTimeInterval:timeStep];
timeDone += timeStep;
}
if ([[fadingOut objectAtIndex:noteValue] boolValue]) {
[source stop];
[loopSource stop];
}
//source.gain = 1;
});
if (recording) {
double currentTime = CACurrentMediaTime();
int deltaTime = (int)(currentTime*1000-recordTimer*1000);
NoteObject * recordedNote = [[NoteObject alloc] init];
recordedNote.note = noteValue;
recordedNote.time = deltaTime;
recordedNote.noteOn = false;
[recordedNotes addObject:recordedNote];
recordTimer = currentTime;
}
}
}
}
- (void) finishFadeIn:(ALSource*)source {
}
- (void) noteOn:(int)noteValue withVelocity:(int)velocity {
if (noteValue>=0 && noteValue<127) {
if (recording) {
double currentTime = CACurrentMediaTime();
int deltaTime = (int)(currentTime*1000-recordTimer*1000);
NoteObject * recordedNote = [[NoteObject alloc] init];
recordedNote.note = noteValue;
recordedNote.time = deltaTime;
recordedNote.noteOn = true;
[recordedNotes addObject:recordedNote];
recordTimer = currentTime;
}
while(loadingScale || changingPitch);
float pitchToPlay = [[ratios objectAtIndex:noteValue] floatValue];
[[fadingOut objectAtIndex:noteValue] release];
[fadingOut replaceObjectAtIndex:noteValue withObject:[[NSNumber alloc] initWithBool:NO]];
ALSource * source = [sources objectAtIndex:noteValue];
[source stop];
source.gain = velocity/127.0f;
source.pitch = pitchToPlay;
[source play:[buffers objectAtIndex:noteValue]];
if ([loopBuffers objectAtIndex:noteValue] != (id)[NSNull null]) {
ALSource *loopSource = [loopSources objectAtIndex:noteValue];
[loopSource stop];
loopSource.gain = 0;
loopSource.pitch = source.pitch;
[loopSource play:[loopBuffers objectAtIndex:noteValue] loop:YES];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
float timeDone = 0;
float duration = [(ALBuffer*)[buffers objectAtIndex:noteValue] duration]-.4;
float timeStep = 0.01;
float valStep = source.gain*timeStep/duration;
float loopStep = valStep;
while (timeDone < duration) {
if ([[fadingOut objectAtIndex:noteValue] boolValue]) break;
source.gain -= valStep;
loopSource.gain += loopStep;
[NSThread sleepForTimeInterval:timeStep];
timeDone += timeStep;
}
/*if ([[fadingOut objectAtIndex:noteValue] boolValue]) {
[source stop];
[loopSource stop];
}*/
//source.gain = 1;
});
}
/*
[source play];*/
//[[sources objectAtIndex:noteValue] play:toPlay gain:velocity/127.0f pitch:pitchToPlay pan:0.0f loop:FALSE];
}
}

Is there api for get infor about network usage of an app?

i want to create an app that show all app installed on the device and info about network usage of that app. Is there api for get infor about network usage?
Your own app can find out how much data the device as a how as used by using the code below, but there's no way of knowing how much each particular app has used. Apps like My Data Manager used to give you a breakdown per app but a) that wasn't totally accurate and b) it now longer does this now with iOS 7. There's another app that sends the data through VPN to its server and in the screenshots on the app store makes it look like it can give a breakdown per app, but that's spin but in reality it just can't except for a few and with some interaction from the user. Basically there is no guaranteed accurate way of doing it per every app.
Also there is no guaranteed accurate way of knowing all installed apps. There are some mechanisms to do a good guess of what is installed based against a database but no way of knowing definitely what is installed
#include <arpa/inet.h>
#include <net/if.h>
#include <ifaddrs.h>
#include <net/if_dl.h>
- (void) getDataUsage
{
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate: self.timeThatDataMonitoringStarted];
NSLog(#"********* GETTING DATA USAGE. Elapsed time: %f **************",elapsedTime);
NSArray *data = [self getDataCounters];
NSNumber *wifiSentSinceBoot = (NSNumber*)data[0];
NSNumber *wifiReceivedSinceBoot = (NSNumber*)data[1];
NSNumber *wwanSentSinceBoot = (NSNumber*)data[2];
NSNumber *wwanReceivedSinceBoot = (NSNumber*)data[3];
int wifiSentSinceBootAsInt = [wifiSentSinceBoot intValue];
int wifiReceivedSinceBootAsInt = [wifiReceivedSinceBoot intValue];
int wWanSentSinceBootAsInt = [wwanSentSinceBoot intValue];
int wWanReceivedSinceBootAsInt = [wwanReceivedSinceBoot intValue];
static int initialWifiSent;
static int initialWifiReceived;
static int initialWWanSent;
static int initialWWanReceived;
if (!self.initialDataValuesSet)
{
self.initialDataValuesSet = YES;
initialWifiSent = wifiSentSinceBootAsInt;
initialWifiReceived = wifiReceivedSinceBootAsInt;
initialWWanSent = wWanSentSinceBootAsInt;
initialWWanReceived = wWanReceivedSinceBootAsInt;
}
int wifiSentSinceLastRetrieval = wifiSentSinceBootAsInt - initialWifiSent;
int wifiReceivedSinceLastRetrieval = wifiReceivedSinceBootAsInt - initialWifiReceived;
int wWanSentSinceLastRetrieval = wWanSentSinceBootAsInt - initialWWanSent;
int wWanReceivedSinceLastRetrieval = wWanReceivedSinceBootAsInt - initialWWanReceived;
uint dataUsed = wifiSentSinceLastRetrieval + wifiReceivedSinceLastRetrieval + wWanSentSinceLastRetrieval + wWanReceivedSinceLastRetrieval;
NSLog(#"Total data: %d", dataUsed);
}
- (NSArray *) getDataCounters
{
BOOL success;
struct ifaddrs *addrs;
const struct ifaddrs *cursor;
const struct if_data *networkStatisc;
int WiFiSent = 0;
int WiFiReceived = 0;
int WWANSent = 0;
int WWANReceived = 0;
NSString *name=[[NSString alloc]init];
success = getifaddrs(&addrs) == 0;
if (success)
{
cursor = addrs;
while (cursor != NULL)
{
name=[NSString stringWithFormat:#"%s",cursor->ifa_name];
// NSLog(#"ifa_name %s == %#\n", cursor->ifa_name,name);
// names of interfaces: en0 is WiFi ,pdp_ip0 is WWAN
if (cursor->ifa_addr->sa_family == AF_LINK)
{
if ([name hasPrefix:#"en"])
{
networkStatisc = (const struct if_data *) cursor->ifa_data;
WiFiSent+=networkStatisc->ifi_obytes;
WiFiReceived+=networkStatisc->ifi_ibytes;
// NSLog(#"WiFiSent %d ==%d",WiFiSent,networkStatisc->ifi_obytes);
// NSLog(#"WiFiReceived %d ==%d",WiFiReceived,networkStatisc->ifi_ibytes);
}
if ([name hasPrefix:#"pdp_ip"])
{
networkStatisc = (const struct if_data *) cursor->ifa_data;
WWANSent+=networkStatisc->ifi_obytes;
WWANReceived+=networkStatisc->ifi_ibytes;
// NSLog(#"WWANSent %d ==%d",WWANSent,networkStatisc->ifi_obytes);
// NSLog(#"WWANReceived %d ==%d",WWANReceived,networkStatisc->ifi_ibytes);
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
return [NSArray arrayWithObjects:[NSNumber numberWithInt:WiFiSent], [NSNumber numberWithInt:WiFiReceived],[NSNumber numberWithInt:WWANSent],[NSNumber numberWithInt:WWANReceived], nil];
}

How to use ProgressMonitor function of ImageMagick on iOS?

I am using Image Magick on ios and I have converted some command lines used on my server into a ConvertImageCommand. Everything work well.
I have added the -monitor as an argument to the command so I can see every tiny progress on my image (loading, resizing, cropping, etc)
However, I would like to display a progress bar to inform the user on the progress of the image process.
I am looking for a very simple example on how to use the progress monitor function...
SetImageProgressMonitor(Image *,const MagickProgressMonitor,void *),
SetImageInfoProgressMonitor(ImageInfo *,const MagickProgressMonitor,void *);
Can somebody help me ?
Here is the code:
- (void)ExecuteCommand {
/*
command is an array which contains all the elements of the ImageMagick command.
example:
command (
convert,
imgSource.jpg,
"-blur",
"0x2.5",
"-paint",
5,
imgSaved.jpg
)
*/
ImageInfo *imageInfo = AcquireImageInfo();
int nbArgs = command.count;
char **argv = (char **)malloc((nbArgs + 1) * sizeof(char*));
for (unsigned i = 0; i < nbArgs; i++)
{
NSString *argString = [command objectAtIndex:i];
argv[i] = strdup([argString UTF8String]);
}
argv[nbArgs] = NULL;
progress_monitor_method = SetImageInfoProgressMonitor(imageInfo, &MonitorProgress, self);
ConvertImageCommand(imageInfo, nbArgs, argv, NULL, AcquireExceptionInfo());
if (argv != NULL)
{
for (unsigned index = 0; argv[index] != NULL; index++) {
free(argv[index]);
}
free(argv);
}
}
MagickBooleanType MonitorProgress(const char *text,const MagickOffsetType offset,const MagickSizeType extent,void *client_data) {
IM_TestViewController *IMVC = client_data;
float prog = offset;
float tot = extent;
NSNumber *value = [NSNumber numberWithFloat:prog/tot];
[IMVC performSelectorInBackground:#selector(updateProgressBar:) withObject:value] ;
NSLog(#"Action : %# %lld on %lld", [NSString stringWithCString:text encoding:NSUTF8StringEncoding], offset, extent);
return MagickTrue;
}
- (void)updateProgressBar:(NSNumber *)value {
self.progressBar.progress = [value floatValue];
}

how to determine which apps are background and which app is foreground on iOS by application id

Using the method described in this question, I can get a list of apps running on an iOS device.
I know PIDs and have access to their kinfo_proc structures.
How can I determine which are foreground processes and which are background (assuming my app is background)?
I tried to find this out base on information in kinfo_proc (see 1st link), via kp_proc.p_priority, but it looks like it is not possible to infer background/foreground state from priority.
I don't really care if this works correctly for AppStore Review but I would prefer a method that will work without a jailbreak(i.e. Private APIs are ok but which ones?). I want this to work at least on iOS 5
I considered writing a simple MobileSubstrate extension, injecting it into all apps and just hook everyone's applicationDidBecomeActive, but this requires a jailbreak and is too invasive.
Well, looks like some usage of nm and IDA on SpringBoardServices binary from simulator helped me on this.
Following code works on iOS 5.0.1 running on iPod Touch 4, iPhone 4 and iPad1 WiFi(all non-JB)
Of course you should never try to submit that to AppStore
- (NSArray*) getActiveApps
{
mach_port_t *p;
void *uikit = dlopen(UIKITPATH, RTLD_LAZY);
int (*SBSSpringBoardServerPort)() =
dlsym(uikit, "SBSSpringBoardServerPort");
p = (mach_port_t *)SBSSpringBoardServerPort();
dlclose(uikit);
void *sbserv = dlopen(SBSERVPATH, RTLD_LAZY);
NSArray* (*SBSCopyApplicationDisplayIdentifiers)(mach_port_t* port, BOOL runningApps,BOOL debuggable) =
dlsym(sbserv, "SBSCopyApplicationDisplayIdentifiers");
//SBDisplayIdentifierForPID - protype assumed,verification of params done
void* (*SBDisplayIdentifierForPID)(mach_port_t* port, int pid,char * result) =
dlsym(sbserv, "SBDisplayIdentifierForPID");
//SBFrontmostApplicationDisplayIdentifier - prototype assumed,verification of params done,don't call this TOO often(every second on iPod touch 4G is 'too often,every 5 seconds is not)
void* (*SBFrontmostApplicationDisplayIdentifier)(mach_port_t* port,char * result) =
dlsym(sbserv, "SBFrontmostApplicationDisplayIdentifier");
//Get frontmost application
char frontmostAppS[256];
memset(frontmostAppS,sizeof(frontmostAppS),0);
SBFrontmostApplicationDisplayIdentifier(p,frontmostAppS);
NSString * frontmostApp=[NSString stringWithFormat:#"%s",frontmostAppS];
//NSLog(#"Frontmost app is %#",frontmostApp);
//get list of running apps from SpringBoard
NSArray *allApplications = SBSCopyApplicationDisplayIdentifiers(p,NO, NO);
//Really returns ACTIVE applications(from multitasking bar)
/* NSLog(#"Active applications:");
for(NSString *identifier in allApplications) {
// NSString * locName=SBSCopyLocalizedApplicationNameForDisplayIdentifier(p,identifier);
NSLog(#"Active Application:%#",identifier);
}
*/
//get list of all apps from kernel
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
size_t miblen = 4;
size_t size;
int st = sysctl(mib, miblen, NULL, &size, NULL, 0);
struct kinfo_proc * process = NULL;
struct kinfo_proc * newprocess = NULL;
do {
size += size / 10;
newprocess = realloc(process, size);
if (!newprocess){
if (process){
free(process);
}
return nil;
}
process = newprocess;
st = sysctl(mib, miblen, process, &size, NULL, 0);
} while (st == -1 && errno == ENOMEM);
if (st == 0){
if (size % sizeof(struct kinfo_proc) == 0){
int nprocess = size / sizeof(struct kinfo_proc);
if (nprocess){
NSMutableArray * array = [[NSMutableArray alloc] init];
for (int i = nprocess - 1; i >= 0; i--){
int ruid=process[i].kp_eproc.e_pcred.p_ruid;
int uid=process[i].kp_eproc.e_ucred.cr_uid;
//short int nice=process[i].kp_proc.p_nice;
//short int u_prio=process[i].kp_proc.p_usrpri;
short int prio=process[i].kp_proc.p_priority;
NSString * processID = [[NSString alloc] initWithFormat:#"%d", process[i].kp_proc.p_pid];
NSString * processName = [[NSString alloc] initWithFormat:#"%s", process[i].kp_proc.p_comm];
BOOL systemProcess=YES;
if (ruid==501)
systemProcess=NO;
char * appid[256];
memset(appid,sizeof(appid),0);
int intID,intID2;
intID=process[i].kp_proc.p_pid,appid;
SBDisplayIdentifierForPID(p,intID,appid);/
NSString * appId=[NSString stringWithFormat:#"%s",appid];
if (systemProcess==NO)
{
if ([appId isEqualToString:#""])
{
//final check.if no appid this is not springboard app
NSLog(#"(potentially system)Found process with PID:%# name %#,isSystem:%d,Priority:%d",processID,processName,systemProcess,prio);
}
else
{
BOOL isFrontmost=NO;
if ([frontmostApp isEqualToString:appId])
{
isFrontmost=YES;
}
NSNumber *isFrontmostN=[NSNumber numberWithBool:isFrontmost];
NSDictionary * dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processName,appId,isFrontmostN, nil]
forKeys:[NSArray arrayWithObjects:#"ProcessID", #"ProcessName",#"AppID",#"isFrontmost", nil]];
NSLog(#"PID:%#, name: %#, AppID:%#,isFrontmost:%d",processID,processName,appId,isFrontmost);
[array addObject:dict];
}
}
}
free(process);
return array;
}
}
}
dlclose(sbserv);
}
Of course 2nd loop is not strictly necessary but I needed non-localized names & PIDs too.
Great answer! But there is a small typo in your code, it should be:
First make sure that SBSERVPATH is defined and the correct header files are included:
#import <sys/sysctl.h>
#import <dlfcn.h>
#define SBSERVPATH "/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices"
Then first find the correct SB port:
mach_port_t *port;
void *lib = dlopen(SBSERVPATH, RTLD_LAZY);
int (*SBSSpringBoardServerPort)() =
dlsym(lib, "SBSSpringBoardServerPort");
port = (mach_port_t *)SBSSpringBoardServerPort();
dlclose(lib);
And then find the active app:
mach_port_t * port = [self getSpringBoardPort];
// open springboard lib
void *lib = dlopen(SBSERVPATH, RTLD_LAZY);
// retrieve function SBFrontmostApplicationDisplayIdentifier
void *(*SBFrontmostApplicationDisplayIdentifier)(mach_port_t *port, char *result) =
dlsym(lib, "SBFrontmostApplicationDisplayIdentifier");
// reserve memory for name
char appId[256];
memset(appId, 0, sizeof(appId));
// retrieve front app name
SBFrontmostApplicationDisplayIdentifier(port, appId);
// close dynlib
dlclose(lib);
This is what works for me on all IOS devices:
#define UIKITPATH "/System/Library/Framework/UIKit.framework/UIKit"
#define SBSERVPATH "/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices"
- (NSArray*) getActiveApps
{
mach_port_t *p;
void *uikit = dlopen(UIKITPATH, RTLD_LAZY);
int (*SBSSpringBoardServerPort)() =
dlsym(uikit, "SBSSpringBoardServerPort");
p = (mach_port_t *)SBSSpringBoardServerPort();
dlclose(uikit);
if(self.frameWorkPath == nil || self.frameWorkPath.length == 0)
{
self.frameWorkPath = #SBSERVPATH;
self.frameWorkPath = [self.frameWorkPath stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
}
const char *cString = [self.frameWorkPath cStringUsingEncoding:NSUTF8StringEncoding];
//const char *bar = [self.frameWorkPath UTF8String];
void *sbserv = dlopen(cString, RTLD_LAZY);
NSArray* (*SBSCopyApplicationDisplayIdentifiers)(mach_port_t* port, BOOL runningApps,BOOL debuggable) =
dlsym(sbserv, "SBSCopyApplicationDisplayIdentifiers");
//SBDisplayIdentifierForPID - protype assumed,verification of params done
void* (*SBDisplayIdentifierForPID)(mach_port_t* port, int pid,char * result) =
dlsym(sbserv, "SBDisplayIdentifierForPID");
//SBFrontmostApplicationDisplayIdentifier - prototype assumed,verification of params done,don't call this TOO often(every second on iPod touch 4G is 'too often,every 5 seconds is not)
void* (*SBFrontmostApplicationDisplayIdentifier)(mach_port_t* port,char * result) =
dlsym(sbserv, "SBFrontmostApplicationDisplayIdentifier");
//Get frontmost application
char frontmostAppS[512];
memset(frontmostAppS,sizeof(frontmostAppS),0);
SBFrontmostApplicationDisplayIdentifier(p,frontmostAppS);
NSString * frontmostApp=[NSString stringWithFormat:#"%s",frontmostAppS];
if([self iOsMajorVersion] >= 7){
NSNumber *topmost = [NSNumber numberWithBool:YES];
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
NSMutableArray * splitted = [frontmostApp componentsSeparatedByString:#"."];
if(frontmostApp.length > 0 && splitted != nil && splitted.count > 1 && topmost.boolValue == YES){
NSString *appname = [splitted lastObject];
[dict setObject:[appname capitalizedString] forKey:#"ProcessName"];
[dict setObject:frontmostApp forKey:#"ProcessID"];
[dict setObject:frontmostApp forKey:#"AppID"];
[dict setObject:topmost forKey:#"isFrontmost"];
NSLog(#"Running TOPMOST App %#",dict);
return #[dict];
}
else{
return nil;
}
}
//NSLog(#"Frontmost app is %#",frontmostApp);
//get list of running apps from SpringBoard
NSArray *allApplications = SBSCopyApplicationDisplayIdentifiers(p,NO, NO);
//Really returns ACTIVE applications(from multitasking bar)
NSLog(#"Active applications:");
for(NSString *identifier in allApplications) {
// NSString * locName=SBSCopyLocalizedApplicationNameForDisplayIdentifier(p,identifier);
NSLog(#"Active Application:%#",identifier);
}
//get list of all apps from kernel
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
size_t miblen = 4;
size_t size;
int st = sysctl(mib, miblen, NULL, &size, NULL, 0);
struct kinfo_proc * process = NULL;
struct kinfo_proc * newprocess = NULL;
do {
size += size / 10;
newprocess = realloc(process, size);
if (!newprocess){
if (process){
free(process);
}
return nil;
}
process = newprocess;
st = sysctl(mib, miblen, process, &size, NULL, 0);
} while (st == -1 && errno == ENOMEM);
if (st == 0){
if (size % sizeof(struct kinfo_proc) == 0){
int nprocess = size / sizeof(struct kinfo_proc);
if (nprocess){
NSMutableArray * array = [[NSMutableArray alloc] init];
for (int i = nprocess - 1; i >= 0; i--){
int ruid=process[i].kp_eproc.e_pcred.p_ruid;
int uid=process[i].kp_eproc.e_ucred.cr_uid;
//short int nice=process[i].kp_proc.p_nice;
//short int u_prio=process[i].kp_proc.p_usrpri;
short int prio=process[i].kp_proc.p_priority;
NSString * processID = [[NSString alloc] initWithFormat:#"%d", process[i].kp_proc.p_pid];
NSString * processName = [[NSString alloc] initWithFormat:#"%s", process[i].kp_proc.p_comm];
BOOL systemProcess=YES;
if (ruid==501){
systemProcess=NO;
}
char * appid[256];
memset(appid,sizeof(appid),0);
int intID,intID2;
intID=process[i].kp_proc.p_pid,appid;
SBDisplayIdentifierForPID(p,intID,appid);
NSString * appId=[NSString stringWithFormat:#"%s",appid];
if (systemProcess==NO)
{
if ([appId isEqualToString:#""])
{
//final check.if no appid this is not springboard app
//NSLog(#"(potentially system)Found process with PID:%# name %#,isSystem:%d,Priority:%d",processID,processName,systemProcess,prio);
}
else
{
BOOL isFrontmost=NO;
if ([frontmostApp isEqualToString:appId])
{
isFrontmost=YES;
}
NSNumber *isFrontmostN=[NSNumber numberWithBool:isFrontmost];
NSDictionary * dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processName,appId,isFrontmostN, nil]
forKeys:[NSArray arrayWithObjects:#"ProcessID", #"ProcessName",#"AppID",#"isFrontmost", nil]];
NSLog(#"PID:%#, name: %#, AppID:%#,isFrontmost:%d",processID,processName,appId,isFrontmost);
[array addObject:dict];
}
}
}
free(process);
return array;
}
}
}
dlclose(sbserv);
}

Resources