How to accurately obtain the iPhone battery level? - ios

I want to get the battery level,and Accurate to 1%.
I googled and find this,
CFTypeRef blob = IOPSCopyPowerSourcesInfo();
CFArrayRef sources = IOPSCopyPowerSourcesList(blob);
CFDictionaryRef pSource = NULL;
const void *psValue;
int numOfSources = CFArrayGetCount(sources);
if (numOfSources == 0) {
NSLog(#"Error in CFArrayGetCount");
return -1.0f;
}
for (int i = 0 ; i < numOfSources ; i++)
{
pSource = IOPSGetPowerSourceDescription(blob, CFArrayGetValueAtIndex(sources, i));
if (!pSource) {
NSLog(#"Error in IOPSGetPowerSourceDescription");
return -1.0f;
}
psValue = (CFStringRef)CFDictionaryGetValue(pSource, CFSTR(kIOPSNameKey));
int curCapacity = 0;
int maxCapacity = 0;
double percent;
psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSCurrentCapacityKey));
CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
psValue = CFDictionaryGetValue(pSource, CFSTR(kIOPSMaxCapacityKey));
CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
percent = ((double)curCapacity/(double)maxCapacity * 100.0f);
return percent;
}
return -1.0f;
but it's not accurate.
So I am asking for help here.

From UIDevice Class Reference:
You can use the UIDevice instance to obtain information and notifications about changes to the battery’s charge state (described by the batteryState property) and charge level (described by the batteryLevel property).
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
float batteryLevel = [UIDevice currentDevice].batteryLevel;
NSLog(#"battery level: %f", batteryLevel * 100);

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

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

ios - ImageMagick How to code to apply ShepardsDistortion on image

I am new to ImageMagick,and i want to develop an effect of ShepardsDistortion on source image. i gone through many posts and sites, but i didn't find way to implement "ShepardsDistortion" in iOS.
MagickWand *mw = NewMagickWand();
MagickSetFormat(mw, "png");
UIImage *sourceImage=[_sourceImgView image];
NSData *imgData=UIImagePNGRepresentation(sourceImage);
MagickReadImageBlob(mw, [imgData bytes], [imgData length]);
Image *image=GetImageFromMagickWand(mw);
DistortImage(image, ShepardsDistortion, , ,);
I done upto this, but i dont know what to pass as arg in DitortImage(). So if anyone knows then help me.
EDIT:
-(void)distortImage{
MagickWandGenesis();
MagickWand * wand;
MagickBooleanType status;
wand = NewMagickWand();
MagickSetFormat(wand, "png");
status = MagickReadImage(wand,"chess.png");
// Arguments for Shepards
double points[8];
points[0] = 250; // First X point (starting)
points[1] = 250; // First Y point (starting)
points[2] = 50; // First X point (ending)
points[3] = 150; // First Y point (ending)
points[4] = 500; // Second X point (starting)
points[5] = 380; // Second Y point (starting)
points[6] = 600; // Second X point (ending)
points[7] = 460; // Second Y point (ending)
MagickDistortImage(wand,ShepardsDistortion,8,points,MagickFalse);
NSString * tempFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"out.png"];
MagickWriteImage(wand,[tempFilePath cStringUsingEncoding:NSASCIIStringEncoding]);
UIImage * imgObj = [UIImage imageWithContentsOfFile:tempFilePath];
_resultImgView.image=imgObj;
//
// unsigned char * cBlob;
// size_t data_size;
// cBlob = MagickGetImageBlob(wand, &data_size);
// NSData * nsBlob = [NSData dataWithBytes:cBlob length:data_size];
// UIImage *uiImage = [UIImage imageWithData:nsBlob];
// _resultImgView.image=uiImage;
MagickWriteImage(wand,"out.png");
wand=DestroyMagickWand(wand);
MagickWandTerminus();
}
This might help:
MagickWandGenesis();
magick_wand = NewMagickWand();
double points[24];
points[0] = 250;
points[1] = 250;
points[2] = 50;
points[3] = 150;
points[4] = 0;
points[5] = 0;
points[6] = 0;
points[7] = 0;
points[8] = self.frame.width;
points[9] = 0;
points[10] = self.frame.width;
points[11] = 0;
points[12] = self.frame.width;
points[13] = self.frame.height;
points[14] = self.frame.width;
points[15] = self.frame.height;
points[16] = self.frame.width;
points[17] = self.frame.height;
points[18] = self.frame.width;
points[19] = self.frame.height;
points[20] = 0;
points[21] = self.frame.height;
points[22] = 0;
points[23] = self.frame.height;
NSData * dataObject = UIImagePNGRepresentation([UIImage imageNamed:#"Imagemagick-logo.png"]);//UIImageJPEGRepresentation([imageViewButton imageForState:UIControlStateNormal], 90);
MagickBooleanType status;
status = MagickReadImageBlob(magick_wand, [dataObject bytes], [dataObject length]);
if (status == MagickFalse) {
ThrowWandException(magick_wand);
}
// posterize the image, this filter uses a configuration file, that means that everything in IM should be working great
status = MagickDistortImage(magick_wand,ShepardsDistortion,24,points,MagickFalse);
//status = MagickOrderedPosterizeImage(magick_wand, "h8x8o");
if (status == MagickFalse) {
ThrowWandException(magick_wand);
}
size_t my_size;
unsigned char * my_image = MagickGetImageBlob(magick_wand, &my_size);
NSData * data = [[NSData alloc] initWithBytes:my_image length:my_size];
free(my_image);
magick_wand = DestroyMagickWand(magick_wand);
MagickWandTerminus();
UIImage * image = [[UIImage alloc] initWithData:data];
[data release];
[imageViewButton setImage:image forState:UIControlStateNormal];
[image release];
Arguments are passed to DistortImage as the start of a list of doubles, and size information about the list. Example:
size_t SizeOfPoints = 8;
double Points[SizeOfPoints];
DistortImage(image,
ShepardsDistoration,
SizeOfPoints,
Points,
MagickFalse,
NULL
);
In your example, you seem to be mixing MagickWand & MagickCore methods; which, seems unnecessary and confusing. I would keep this distortion simple, and only use MagickWand's MagickDistortImage method. Here's a example in c
int main(int argc. const char **argv)
{
MagickWandGenesis();
MagickWand * wand;
MagickBooleanType status;
wand = NewMagickWand();
status = MagickReadImage(wand,"logo:");
// Arguments for Shepards
double points[8];
// 250x250 -> 50x150
points[0] = 250; // First X point (starting)
points[1] = 250; // First Y point (starting)
points[2] = 50; // First X point (ending)
points[3] = 150; // First Y point (ending)
// 500x380 -> 600x460
points[4] = 500; // Second X point (starting)
points[5] = 380; // Second Y point (starting)
points[6] = 600; // Second X point (ending)
points[7] = 460; // Second Y point (ending)
MagickDistortImage(wand,ShepardsDistortion,8,points,MagickFalse);
MagickWriteImage(wand,"out.png");
wand=DestroyMagickWand(wand);
MagickWandTerminus();
return 0;
}
Resulting in a distorted translated image (details)
Edit
For iOS, you can use NSTemporaryDirectory (like in this answer), or create an image dynamically using NSData (like in this question).
Example with temporary path:
NSString * tempFilePath = [NSTemporaryDirectory()
stringByAppendingPathComponent:#"out.png"];
MagickWriteImage(self.wand,
[tempFilePath cStringUsingEncoding:NSASCIIStringEncoding]);
UIImage * imgObj = [UIImage imageWithContentsOfFile:tempFilePath];
And an example with NSData + blob
unsigned char * cBlob;
size_t data_size;
cBlob = MagickGetImageBlob(wand, &data_size);
NSData * nsBlob = [NSData dataWithBytes:cBlob length:data_size];
UIImage * uiImage = [UIImage imageWithData:nsBlob];

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