iOS代码层获取电量

1.加载动态链接库

iOS是给予Linux内核,在Linux调用如下函数来加载动态链接库:dlopen,dlsym,dlclose,dlerror

void * dlopen(const char  *filename, int flag);
char * dlerror(void);
void * dlsym(void *handle, const *symbol);
int dlclose(void *handle)

dlopen:以指定模式flag打开指定路径filename下的动态链接库文件,并返回一个句柄;其中flag有如下值:

#define RTLD_LAZY   0x1  //对于动态库未定义的变量不执行解析
#define RTLD_NOW    0x2  //解析每个未定义变量的地址,若解析不出来,抛NULL异常
#define RTLD_LOCAL  0x4  //使得库中的解析的定义变量只在当前可以使用
#define RTLD_GLOBAL 0x8 //使得库中的解析的定义变量在随后的其它的链接库中变得可以使用

dlerror:返回错误信息
dlsym:通过句柄和连接符名称获取函数名或者变量名,一般用于调用私有的API或者私有变量
dlclose:卸载打开的动态链接库

2.获取电量

为了获取电量mAh的形式,需要使用IOKit.framework。但是此类库为私有类库,所以使用的时候需要动态引用。伪代码如下:

a)动态链接IOKit.framework,获取并定义函数指针和变量地址

// 初始化电量管理函数
- (BOOL) batteryMgInit{
    
// 1.   动态获取IOKit句柄,选择RTLD_NOW模式
   _handleIOKit =dlopen(NT_IOKIT_DYLIB_PATH, RTLD_NOW);
    if (!_handleIOKit) {
        return NO;
    }
// 2.   通过IOKit句柄,动态获取kIOMasterPortDefault对应的mach port
    _kIOMasterPortDefault = (mach_port_t *)dlsym(_handleIOKit, "kIOMasterPortDefault");
    
// 3.   通过IOKit句柄,动态获取主IOServiceMatching变量
    _mIOServiceMathcing = (NT_IO_SERVICE_MATCHING)dlsym(_handleIOKit, "IOServiceMatching");
    
// 4.   通过IOKit句柄,动态获取IOServiceGetMatchingService对应的mach port
    _mIOServiceGetMatchingService = (NT_IO_SERVICE_GET_MATCHING_SERVICE)dlsym(_handleIOKit, "IOServiceGetMatchingService");
    
// 5.   通过IOKit句柄,动态获取主IORegistryEntryCreateCFProperties函数地址
    _mIORegistryEntryCreateCFProperties = (NT_IO_REGISTRY_ENTRY_CREATE_CF_PROPERTIES)dlsym(_handleIOKit, "IORegistryEntryCreateCFProperties");
    
// 6.   GT_PFN_IOOBJECTRELEASE为int类型
    _mIOObjectRelease = (NT_IO_OBJECT_RELEASE)dlsym(_handleIOKit, "IOObjectRelease");
    
    
    if (_kIOMasterPortDefault &&
        _mIOServiceMathcing &&
        _mIOServiceGetMatchingService &&
        _mIORegistryEntryCreateCFProperties &&
        _mIOObjectRelease
        ) {
        return YES;
    }
    
    return YES;
}

b)获取电量参数

- (void) updateBatteryInfo {
    CFMutableDictionaryRef matching, properties = NULL;
    mach_port_t entry = 0;
//  获取电量管理对象,_mIOServiceMathcing为动态获取IOKit对应函数(_mIOServiceMathcing)地址指针

//  调用IOKit的IOServiceMathcing函数,获取IOPMPowerSource对应的matching字典
    matching = _mIOServiceMathcing("IOPMPowerSource");
    if (!matching) {
        return;
    }
    
//
//    func IOServiceGetMatchingService(_ masterPort: mach_port_t,
//                                     _ matching: CFDictionary!) -> io_service_t
//    查询匹配matching的IOService注册对象,
    entry = _mIOServiceGetMatchingService(*_kIOMasterPortDefault, matching);
    if (!entry) {
        return;
    }
    

/**
    函数原型:
    func IORegistryEntryCreateCFProperties(_ entry: io_registry_entry_t,
                                           _ properties: UnsafeMutablePointer<Unmanaged<CFMutableDictionary>?>!,
                                           _ allocator: CFAllocator!,
                                           _ options: IOOptionBits) -> kern_return_t
    IORegistryEntryCreateCFProperties:根据注册对象句柄,将对象属性存入字典 ***/
    kern_return_t rt = _mIORegistryEntryCreateCFProperties(entry, &properties, NULL, 0);
    if (rt) {
        return;
    }
    
    //  properties提取参数
    [self updateBatteryItem: (__bridge NSDictionary *)properties];
    CFRelease( properties );
    _mIOObjectRelease( entry );
    
    return;
    
}



- (void) updateBatteryItem:(NSDictionary *)dic{
    
    self.batteryUnit.preCurrentCapacity = self.batteryUnit.currentCapacity;
    
    NSNumber *currentCapacity = [dic objectForKey: @"CurrentCapacity"];
    self.batteryUnit.currentCapacity = [currentCapacity intValue];
    
    NSNumber *maxCapacity = [dic objectForKey: @"MaxCapacity"];
    self.batteryUnit.maxCapacity = [maxCapacity intValue];
    
    NSNumber *voltage = [dic objectForKey:@"Voltage"];
    self.batteryUnit.voltage = [voltage intValue];
}

实验结果:

demo程序获取电池当前电量,最大电量,电压。
如图分别采样90s,和112s两个时间节点的电量信息


image.png

90s采样截图


5.png

120s采样截图

6.png

遇到的问题:由于电池的物理特性,获取的当前电池电量,最大电池电量的值会发生变化。如最大电池某个采样点为1500,下个采样点为1000;其次上一时刻的当前电量可能会大于这一时刻的电量。
基于上诉原因,需要当前电量和最大电池电量配合使用才能较正确的表现当前电池电量情况,即剩余电量百分比(当前电池电量/最大电池电量)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容