美文网首页iOS基础篇
关于iOS电量检测和分析的调研

关于iOS电量检测和分析的调研

作者: child_cool | 来源:发表于2019-06-20 10:39 被阅读0次

    一、私有方法获取电量相关的信息

    • 可以获取的信息: 电池的健康程度、电池容量、是否充电、电源类型、传输类型等
    #include <dlfcn.h>
    - (NSDictionary*)fetchBatteryInfo
    {
        mach_port_t *kIOMasterPortDefault;
        
        kern_return_t (*ioRegistryEntryCreateCFProperties)(mach_port_t entry, CFMutableDictionaryRef *properties, CFAllocatorRef allocator, UInt32 options) = NULL;
        
        mach_port_t (*ioServiceGetMatchingService)(mach_port_t masterPort, CFDictionaryRef matching CF_RELEASES_ARGUMENT) = NULL;
        
        CFMutableDictionaryRef (*ioServiceMatching)(const char *name) = NULL;
        
        CFTypeRef (*ioPSCopyPowerSourcesInfo)(void) = NULL;
        
        CFArrayRef (*ioPSCopyPowerSourcesList)(CFTypeRef blob) = NULL;
        
        CFDictionaryRef (*ioPSGetPowerSourceDescription)(CFTypeRef blob, CFTypeRef ps) = NULL;
        
        CFMutableDictionaryRef powerSourceService = NULL;
        mach_port_t platformExpertDevice = 0;
    
        var handle = dlopen("/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit", RTLD_LAZY);
        
        ioRegistryEntryCreateCFProperties = dlsym(handle, "IORegistryEntryCreateCFProperties");
        kIOMasterPortDefault = dlsym(handle, "kIOMasterPortDefault");
        ioServiceMatching = dlsym(handle, "IOServiceMatching");
        ioServiceGetMatchingService = dlsym(handle, "IOServiceGetMatchingService");
        
        ioPSCopyPowerSourcesInfo = dlsym(handle, "IOPSCopyPowerSourcesInfo");
        ioPSCopyPowerSourcesList = dlsym(handle, "IOPSCopyPowerSourcesList");
        ioPSGetPowerSourceDescription = dlsym(handle, "IOPSGetPowerSourceDescription");
        
        if (ioRegistryEntryCreateCFProperties != NULL &&
            ioServiceMatching != NULL &&
            ioServiceGetMatchingService != NULL)
        {
            powerSourceService = ioServiceMatching("IOPMPowerSource");
            platformExpertDevice = ioServiceGetMatchingService(*kIOMasterPortDefault, powerSourceService);
        }
        
        NSMutableDictionary *batteryInfo = nil;
        
        if(powerSourceService != NULL && platformExpertDevice != 0)
        {
            CFMutableDictionaryRef prop = NULL;
            ioRegistryEntryCreateCFProperties(platformExpertDevice, &prop, 0, 0);
            if(prop != NULL)
            {
                batteryInfo = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary*)prop];
                CFRelease(prop);
            }
        }
        
        var blob = ioPSCopyPowerSourcesInfo();
        var sources = ioPSCopyPowerSourcesList(blob);
        CFDictionaryRef pSource = NULL;
    
        var numOfSources = CFArrayGetCount(sources);
        for(CFIndex i = 0; i < numOfSources; I++)
        {
            pSource = ioPSGetPowerSourceDescription(blob, CFArrayGetValueAtIndex(sources, i));
            if(pSource != NULL)
            {
                if(batteryInfo == nil)
                    batteryInfo = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary*)pSource];
                else
                    [batteryInfo setValuesForKeysWithDictionary:(NSDictionary*)pSource];
                
                break;
            }
        }
        
        dlclose(handle);
        CFRelease(blob);
        CFRelease(sources);
        
        return batteryInfo;
    }
    
    • 越高版本的数据越少,苹果审核很难通过
    • iOS 12.2 iPhone X 结果如下
    {
        "Battery Provides Time Remaining" = 1;
        BatteryHealth = Poor;
        BatteryHealthCondition = "Check Battery";
        BatteryInstalled = 1;
        "Current Capacity" = 100;
        ExternalConnected = 1;
        "Is Charged" = 1;
        "Is Charging" = 0;
        "Is Present" = 1;
        "Max Capacity" = 100;
        Name = "InternalBattery-0";
        "Power Source ID" = 2424931;
        "Power Source State" = "AC Power";
        "Raw External Connected" = 1;
        "Show Charging UI" = 1;
        "Time to Empty" = 0;
        "Time to Full Charge" = 0;
        "Transport Type" = Internal;
        Type = InternalBattery;
    }
    
    • ios 10.3 iPhone 5c
    {
        AdapterInfo = 16384;
        AtCriticalLevel = 0;
        "Battery Provides Time Remaining" = 1;
        BatteryHealth = Good;
        Current = 1000;
        "Current Capacity" = 87;
        CurrentCapacity = 1131;
        DesignCycleCount = 300;
        ExternalChargeCapable = 1;
        ExternalConnected = 1;
        FullyCharged = 0;
        IOClass = AppleARMPMUCharger;
        "Is Charging" = 1;
        "Is Finishing Charge" = 0;
        "Is Present" = 1;
        IsCharging = 1;
        "Max Capacity" = 100;
        MaxCapacity = 1300;
        Name = "InternalBattery-0";
        "Power Source ID" = 4063331;
        "Power Source State" = "AC Power";
        "Raw External Connected" = 1;
        "Show Charging UI" = 1;
        "Time to Empty" = 0;
        "Time to Full Charge" = 0;
        "Transport Type" = Internal;
        Type = InternalBattery;
        Voltage = 4178;
    }
    

    二、sysdiagnose

    • 证书下载地址
    • 安装方式
    • 安装完成后在不重启手机的情况下,等待10到30分钟。
    • 通过 iTunes同步到电脑上。
    • 去 ~/Library/Logs/CrashReporter/MobileDevice 目录下,打开 powerlog_xxxx.PLSQL 文件
    • 可以获取到最近几天的所有电量信息


      image.png

    三、系统提供接口

    • 可以获取到整体的电池利用率,以及充电状态
     // #import <UIKit / UIDevice.h> 
       UIDevice * device = [UIDevice currentDevice ];
       device.batteryMonitoringEnabled = YES ;
       //。的UIDevice返回的batteryLevel的范围在0到1之间
       NSUInteger batteryLevel = device.batteryLevel * 100 ;
       //获取充电状态
       UIDeviceBatteryState state = device.batteryState;
       if(state == UIDeviceBatteryStateCharging || state == UIDeviceBatteryStateFull){
            //正在充电和电池已满 
       }
    

    四、Ecergy Log

    • iOS设置选项 - >开发者选项 - >日志记录 - >开始录制


      image.png
    • 进行需要测试电量的场景操作后进入开发者选项点击停止录制

    • iOS设备和Mac连接

    • 打开仪器,选择能量诊断

    • 选择文件>从设备导入记录的数据


      image.png
    • 结合 Time Profiler 工具,可以大概定位能耗比较高的代码,参考地址

    五、Energy Impact

    • 可以大致确定程序运行中的能耗情况, 结合 Time Profiler 工具进行代码定位

    • 真机运行项目,选择Energy Impact


      image.png
    • 蓝色表示--合理,黄色--表示程序比较耗电,红色--表示仅仅轻度使用你的程序,就会很耗电.

    • 图表中Utilization栏中是表示瞬时耗电情况

    • 图表中Average栏中,表示平均耗电情况

    • 图表中Energy Impact中cost(蓝色)表示运行项目代码需要电量,Overhead(红色)表示开销,包括CPU的唤起,无线电模组(蓝牙&WiFi),和其他系统资源的调用等

    • 灰色表示有电量消耗,白色表示没有电量消耗

    • 影响电量的五个因素,

      • CPU : 使用率超过20%就会快速耗干电池电量.高效使用CPU,并且当用户出现模糊输入时快速做出不做事情的反应.
      • Network : 网络活动会唤起需要长时间周期性供电的无线电模组,可以分批次进行网络请求,来降低开销.
      • Location : 精密&高频的的定位会增加开销,需要按需使用.
      • GPU : 图形处理器(显卡的处理器),乱使用GPU会导致交互差,并且降低电池寿命.
      • Background : 后台状态App仍会消耗电量,App要按需执行后台操作,并使用延迟APIs来保证系统运算高效执行.另外,在app进入后台状态是,立即减少动作,并且通知系统一次这些动作已经完成.

    相关文章

      网友评论

        本文标题:关于iOS电量检测和分析的调研

        本文链接:https://www.haomeiwen.com/subject/kgxlqctx.html