How to use ProgressMonitor function of ImageMagick on iOS? - 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];
}

Related

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];
}
}

Creating Random Alpha numeric on IOS

i'm java programmer that 'must' move on to obj-C for a while,
i got some confuse when generating random alphanumeric code... here my javacode:
PS: i want to generate code like this :Gh12PU67, AC88pP13, Bk81gH89
private String generateCode(){
String code = "";
Random r = new Random();
char[] c = new char[]{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
for(int i = 0; i<4; i++){
int uplow = r.nextInt(2);
String temp = ""+ c[r.nextInt(c.length)];
if(uplow==1)
code = code + temp.toUpperCase();
else
code = code + temp;
if((i+1)%2==0){
code += r.nextInt(10);
code += r.nextInt(10);
}
}
return code;
}
then i create on OBJ-C
-(void)generateCode{
NSString *alphabet = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:4];
for (NSUInteger i = 0U; i < 4; i++) {
u_int32_t r = arc4random() % [alphabet length];
unichar c = [alphabet characterAtIndex:r];
[s appendFormat:#"%C", c];
}
NSLog(#"s-->%#",s);
}
but i got "HpNz" for result AC88pP13 insted that hve pattern String,string, numeric,numeric, lowescase string,numeric,numeric...
that case screw my life for 3 days...
Your Objective-C code looks good, but (as #Wain correctly said in a comment above),
the Java function function contains logic to insert 2 digits after 2 letters, which you
have not replicated in the Objective-C method.
I would make that logic slightly less obscure and write it as
- (void)generateCode
{
static NSString *letters = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY";
static NSString *digits = #"0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:8];
for (NSUInteger i = 0; i < 2; i++) {
uint32_t r;
// Append 2 random letters:
r = arc4random_uniform((uint32_t)[letters length]);
[s appendFormat:#"%C", [letters characterAtIndex:r]];
r = arc4random_uniform((uint32_t)[letters length]);
[s appendFormat:#"%C", [letters characterAtIndex:r]];
// Append 2 random digits:
r = arc4random_uniform((uint32_t)[digits length]);
[s appendFormat:#"%C", [digits characterAtIndex:r]];
r = arc4random_uniform((uint32_t)[digits length]);
[s appendFormat:#"%C", [digits characterAtIndex:r]];
}
NSLog(#"s-->%#",s);
}
Remark (from the man page):
arc4random_uniform(length) is preferred over arc4random() % length,
as it avoids "modulo bias" when the upper bound is not a power of two.
Remark: A more verbatim translation of the Java code code += r.nextInt(10);
to Objective-C would be
r = arc4random_uniform(10);
[s appendString:[#(r) stringValue]];
which creates a NSNumber object #(r) from the random number, and then
converts that to a string.
if you want a secure random string you should use this code:
#define ASCII_START_NUMERS 0x30
#define ASCII_END_NUMERS 0x39
#define ASCII_START_LETTERS_A 0x41
#define ASCII_END_LETTERS_Z 0x5A
#define ASCII_START_LETTERS_a 0x61
#define ASCII_END_LETTERS_z 0x5A
-(NSString *)getRandomString:(int)length {
NSMutableString *result = [[NSMutableString alloc]init];
while (result.length != length) {
NSMutableData* data = [NSMutableData dataWithLength:1];
SecRandomCopyBytes(kSecRandomDefault, 1, [data mutableBytes]);
Byte currentChar = 0;
[data getBytes:&currentChar length:1];
NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (currentChar > ASCII_START_NUMERS && currentChar < ASCII_END_NUMERS) { // 0 to 0
[result appendString:s];
continue;
}
if (currentChar > ASCII_START_LETTERS_A && currentChar < ASCII_END_LETTERS_Z) { // A to Z
[result appendString:s];
continue;
}
if (currentChar > ASCII_START_LETTERS_a && currentChar < ASCII_END_LETTERS_z) { // a to z
[result appendString:s];
continue;
}
}
return result;
}

Base 62 conversion in Objective-C

I spent much too much time trying to find an implementation for base 62 conversion for Objective-C. I am sure this is a terrible example and there must be an elegant, super-efficient way to do this, but this works, please edit or answer to improve it! But I wanted to help people searching for this to have something that will work. There doesn't appear to be anything specific to be found for an Objective-C implementation.
#implementation Base62Converter
+(int)decode:(NSString*)string
{
int num = 0;
NSString * alphabet = #"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0, len = [string length]; i < len; i++)
{
NSRange range = [alphabet rangeOfString:[string substringWithRange:NSMakeRange(i,1)]];
num = num * 62 + range.location;
}
return num;
}
+(NSString*)encode:(int)num
{
NSString * alphabet = #"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
NSMutableString * precursor = [NSMutableString stringWithCapacity:3];
while (num > 0)
{
[precursor appendString:[alphabet substringWithRange:NSMakeRange( num % 62, 1 )]];
num /= 62;
}
// http://stackoverflow.com/questions/6720191/reverse-nsstring-text
NSMutableString *reversedString = [NSMutableString stringWithCapacity:[precursor length]];
[precursor enumerateSubstringsInRange:NSMakeRange(0,[precursor length])
options:(NSStringEnumerationReverse |NSStringEnumerationByComposedCharacterSequences)
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[reversedString appendString:substring];
}];
return reversedString;
}
#end
Your code is fine. If anything, make it more generic. Here is a recursive version for any base (same code):
#import <Foundation/Foundation.h>
#interface BaseConversion : NSObject
+(NSString*) formatNumber:(NSUInteger)n toBase:(NSUInteger)base;
+(NSString*) formatNumber:(NSUInteger)n usingAlphabet:(NSString*)alphabet;
#end
#implementation BaseConversion
// Uses the alphabet length as base.
+(NSString*) formatNumber:(NSUInteger)n usingAlphabet:(NSString*)alphabet
{
NSUInteger base = [alphabet length];
if (n<base){
// direct conversion
NSRange range = NSMakeRange(n, 1);
return [alphabet substringWithRange:range];
} else {
return [NSString stringWithFormat:#"%#%#",
// Get the number minus the last digit and do a recursive call.
// Note that division between integer drops the decimals, eg: 769/10 = 76
[self formatNumber:n/base usingAlphabet:alphabet],
// Get the last digit and perform direct conversion with the result.
[alphabet substringWithRange:NSMakeRange(n%base, 1)]];
}
}
+(NSString*) formatNumber:(NSUInteger)n toBase:(NSUInteger)base
{
NSString *alphabet = #"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 62 digits
NSAssert([alphabet length]>=base,#"Not enough characters. Use base %ld or lower.",(unsigned long)[alphabet length]);
return [self formatNumber:n usingAlphabet:[alphabet substringWithRange:NSMakeRange (0, base)]];
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
NSLog(#"%#",[BaseConversion formatNumber:3735928559 toBase:16]); // deadbeef
return EXIT_SUCCESS;
}
}
A Swift 3 version: https://gist.github.com/j4n0/056475333d0ddfe963ac5dc44fa53bf2
You could improve your encode method in such a way that reversing the final string is not necessary:
+ (NSString *)encode:(NSUInteger)num
{
NSString *alphabet = #"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSUInteger base = [alphabet length];
NSMutableString *result = [NSMutableString string];
while (num > 0) {
NSString *digit = [alphabet substringWithRange:NSMakeRange(num % base, 1)];
[result insertString:digit atIndex:0];
num /= base;
}
return result;
}
Of course, this could also be generalized for arbitrary bases or alphabets, as suggested by #Jano in his answer.
Note that this method (as well as your original encode method) returns an empty string for num = 0, so you might want to consider this case separately (or just replace while (num > 0) { ... } by do { ... } while (num > 0).
For more efficiency, one could avoid all intermediate NSString objects altogether, and work with plain C strings:
+ (NSString *)encode:(NSUInteger)num
{
static const char *alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSUInteger base = 62;
char result[20]; // sufficient room to encode 2^64 in Base-62
char *p = result + sizeof(result);
*--p = 0; // NULL termination
while (num > 0) {
*--p = alphabet[num % base];
num /= base;
}
return [NSString stringWithUTF8String:p];
}

Parsing a NSString to a byte array

I need to parse an NSString to a byte array and am having some trouble doing it. I have a padded byte array in a method and convert that into a mutablestring, then I have a method that needs to place those numbers back into a byte array.
In C# it would be as simple as:
do
{
val = byte.Parse(str.Substring(i, 3));
byteArr[j++] = val;
i += 3;
}
Here is the code snippit Note** Ive been trying a lot of different things in the do loop so its a mess in there right now:
-(NSData*) StrToByteArray: (NSString*)str
{
NSLog(#"StrToByteArray. String: %#", str);
if([str length]==0)
NSLog(#"Invailid String");
int val;
Byte byteArr[[str length]/3];
int i = 0;
int j = 0;
NSRange range;
do {
range = NSMakeRange(i, 3);
val = (int)[str substringFromIndex:i];
NSLog(#"StrToByteArray. VAR: %i", val);
byteArr[j++] = val;
NSLog(#"byteArr: %i",byteArr[i]);
i+=3;
}while(i<str.length);
NSData* wrappedByteArr = [NSData dataWithBytes:&byteArr length: sizeof(byteArr)];
return wrappedByteArr;
}
Here is the loop that makes the padded string:
for(int i = 0; i<=len;i++)
{
val = byteArr[i];
NSLog(#"byteArr to string original: %i", val);
if(val<(Byte)10)
{
[tempStr appendString:(#"00")];
[tempStr appendString:[NSString stringWithFormat:#"%d",val]];
}
else if(val<(Byte)100)
{
[tempStr appendString:(#"0")];
[tempStr appendString:[NSString stringWithFormat:#"%d",val]];
}
else {
[tempStr appendString:[NSString stringWithFormat:#"%d",val]];
}
}
NSLog(#"string: %#", tempStr);
return tempStr;
Take 2
Now that I know what the data looks like and how you want to parse it, I would approach it like this:
- (NSData *) parseStringToData:(NSString *) str
{
if ([str length] % 3 != 0)
{
// raise an exception, because the string's length should be a multiple of 3.
}
NSMutableData *result = [NSMutableData dataWithLength:[str length] / 3];
unsigned char *buffer = [result mutableBytes];
for (NSUInteger i = 0; i < [result length]; i++)
{
NSString *byteString = [str substringWithRange:NSMakeRange(i * 3, 3)];
buffer[i] = [byteString intValue];
}
return result;
}
Edit:
Your padding method could be simplified as well by providing the correct format specifier that automatically pads integers.
for(int i = 0; i<=len;i++)
{
val = byteArr[i];
NSLog(#"byteArr to string original: %i", val);
[tempStr appendFormat:#"%03d", val];
}

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