iOS代碼層獲取電量

1.加載動態(tài)鏈接庫

iOS是給予Linux內(nèi)核,在Linux調(diào)用如下函數(shù)來加載動態(tài)鏈接庫: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下的動態(tài)鏈接庫文件,并返回一個句柄;其中flag有如下值:

#define RTLD_LAZY   0x1  //對于動態(tài)庫未定義的變量不執(zhí)行解析
#define RTLD_NOW    0x2  //解析每個未定義變量的地址,若解析不出來,拋NULL異常
#define RTLD_LOCAL  0x4  //使得庫中的解析的定義變量只在當前可以使用
#define RTLD_GLOBAL 0x8 //使得庫中的解析的定義變量在隨后的其它的鏈接庫中變得可以使用

dlerror:返回錯誤信息
dlsym:通過句柄和連接符名稱獲取函數(shù)名或者變量名,一般用于調(diào)用私有的API或者私有變量
dlclose:卸載打開的動態(tài)鏈接庫

2.獲取電量

為了獲取電量mAh的形式,需要使用IOKit.framework。但是此類庫為私有類庫,所以使用的時候需要動態(tài)引用。偽代碼如下:

a)動態(tài)鏈接IOKit.framework,獲取并定義函數(shù)指針和變量地址

// 初始化電量管理函數(shù)
- (BOOL) batteryMgInit{
    
// 1.   動態(tài)獲取IOKit句柄,選擇RTLD_NOW模式
   _handleIOKit =dlopen(NT_IOKIT_DYLIB_PATH, RTLD_NOW);
    if (!_handleIOKit) {
        return NO;
    }
// 2.   通過IOKit句柄,動態(tài)獲取kIOMasterPortDefault對應(yīng)的mach port
    _kIOMasterPortDefault = (mach_port_t *)dlsym(_handleIOKit, "kIOMasterPortDefault");
    
// 3.   通過IOKit句柄,動態(tài)獲取主IOServiceMatching變量
    _mIOServiceMathcing = (NT_IO_SERVICE_MATCHING)dlsym(_handleIOKit, "IOServiceMatching");
    
// 4.   通過IOKit句柄,動態(tài)獲取IOServiceGetMatchingService對應(yīng)的mach port
    _mIOServiceGetMatchingService = (NT_IO_SERVICE_GET_MATCHING_SERVICE)dlsym(_handleIOKit, "IOServiceGetMatchingService");
    
// 5.   通過IOKit句柄,動態(tài)獲取主IORegistryEntryCreateCFProperties函數(shù)地址
    _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)獲取電量參數(shù)

- (void) updateBatteryInfo {
    CFMutableDictionaryRef matching, properties = NULL;
    mach_port_t entry = 0;
//  獲取電量管理對象,_mIOServiceMathcing為動態(tài)獲取IOKit對應(yīng)函數(shù)(_mIOServiceMathcing)地址指針

//  調(diào)用IOKit的IOServiceMathcing函數(shù),獲取IOPMPowerSource對應(yīng)的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;
    }
    

/**
    函數(shù)原型:
    func IORegistryEntryCreateCFProperties(_ entry: io_registry_entry_t,
                                           _ properties: UnsafeMutablePointer<Unmanaged<CFMutableDictionary>?>!,
                                           _ allocator: CFAllocator!,
                                           _ options: IOOptionBits) -> kern_return_t
    IORegistryEntryCreateCFProperties:根據(jù)注冊對象句柄,將對象屬性存入字典 ***/
    kern_return_t rt = _mIORegistryEntryCreateCFProperties(entry, &properties, NULL, 0);
    if (rt) {
        return;
    }
    
    //  properties提取參數(shù)
    [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];
}

實驗結(jié)果:

demo程序獲取電池當前電量,最大電量,電壓。
如圖分別采樣90s,和112s兩個時間節(jié)點的電量信息


image.png

90s采樣截圖


5.png

120s采樣截圖

6.png

遇到的問題:由于電池的物理特性,獲取的當前電池電量,最大電池電量的值會發(fā)生變化。如最大電池某個采樣點為1500,下個采樣點為1000;其次上一時刻的當前電量可能會大于這一時刻的電量。
基于上訴原因,需要當前電量和最大電池電量配合使用才能較正確的表現(xiàn)當前電池電量情況,即剩余電量百分比(當前電池電量/最大電池電量)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容