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對應的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對應的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對應函數(shù)(_mIOServiceMathcing)地址指針
// 調(diào)用IOKit的IOServiceMathcing函數(shù)崔慧,獲取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;
}
/**
函數(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];
}
實驗結果:
demo程序獲取電池當前電量惶室,最大電量,電壓玄货。
如圖分別采樣90s皇钞,和112s兩個時間節(jié)點的電量信息
90s采樣截圖
120s采樣截圖
遇到的問題:由于電池的物理特性,獲取的當前電池電量松捉,最大電池電量的值會發(fā)生變化夹界。如最大電池某個采樣點為1500,下個采樣點為1000隘世;其次上一時刻的當前電量可能會大于這一時刻的電量可柿。
基于上訴原因鸠踪,需要當前電量和最大電池電量配合使用才能較正確的表現(xiàn)當前電池電量情況,即剩余電量百分比(當前電池電量/最大電池電量)