Reading the battery level programmatically

A beta-tester was complaining the application was draining its battery. To check if this was really the case, I needed to get the battery level with a better accuracy than just looking at the battery icon. So I used this little routine to check.

This routine is adapted from a post on MacRumors.com.

It uses non-approved calls, so don’t post your application with this code or you may be rejected!

The method I used was:

  • Copy the IOPowerSources.h and IOPSKeys.h from the Simulator into my project
  • Add the libIOKit.A.dylib from the iPhone to my project

To get a copy of the libIOKit.A.dylib without jailbreaking my iPhone, I used FSWalker from Nicolas Seriot, a nifty utility which creates a web server on your iPhone and allows you to navigate your iPhone file system with a web browser.

So launch FSWalker, and with your browser go to http://192.168.2.100:20000/System/Library/Frameworks/IOKit.framework/Versions/A (replace the IP address with the address of your iPhone).
Download the IOKit file and add it to your project with the name « libIOKit.A.dylib ».

#include "IOPowerSources.h"
#include "IOPSKeys.h"

- (double) batteryLevel
{
  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;
}

Don't forget to remove the headers and libIOKit.A.dylib from your code before shipping!