目录
电量消耗概述
电量消耗来源
graph TB
A[电量消耗] --> B[CPU]
A --> C[网络]
A --> D[定位]
A --> E[屏幕]
A --> F[后台任务]
A --> G[传感器]
B --> B1[主线程占用]
B --> B2[后台计算]
B --> B3[频繁唤醒]
C --> C1[频繁请求]
C --> C2[大数据传输]
C --> C3[长连接]
D --> D1[GPS 定位]
D --> D2[持续定位]
D --> D3[高精度定位]
E --> E1[高亮度]
E --> E2[高刷新率]
E --> E3[复杂动画]
F --> F1[后台刷新]
F --> F2[推送唤醒]
F --> F3[音频播放]
G --> G1[加速度计]
G --> G2[陀螺仪]
G --> G3[磁力计]
style A fill:#FF6B6B
style B fill:#FFA07A
style C fill:#FFD93D
style D fill:#6BCF7F
style E fill:#4D96FF
style F fill:#9D84B7
style G fill:#F38181
电量消耗占比
pie title iOS 应用电量消耗分布
"CPU" : 30
"网络" : 25
"定位" : 20
"屏幕" : 15
"后台任务" : 5
"传感器" : 5
电量等级划分
| 等级 | 电量消耗 | 用户感知 | 优化优先级 |
|---|---|---|---|
| 优秀 | < 5% / 小时 | 无感知 | P3 |
| 良好 | 5-10% / 小时 | 轻微感知 | P2 |
| 一般 | 10-15% / 小时 | 明显感知 | P1 |
| 较差 | 15-20% / 小时 | 强烈感知 | P0 |
| 很差 | > 20% / 小时 | 严重发热 | P0 |
电量监控方案
监控架构
graph TB
A[电量监控系统] --> B[实时监控]
A --> C[数据采集]
A --> D[数据分析]
A --> E[告警系统]
B --> B1[电量变化]
B --> B2[充电状态]
B --> B3[电池健康]
C --> C1[CPU 使用率]
C --> C2[网络流量]
C --> C3[定位使用]
C --> C4[后台活动]
D --> D1[耗电排行]
D --> D2[异常检测]
D --> D3[趋势分析]
E --> E1[实时告警]
E --> E2[日报周报]
E --> E3[优化建议]
style A fill:#4ECDC4
style B fill:#FF6B6B
style C fill:#FFA07A
style D fill:#95E1D3
style E fill:#F38181
1. 电量监控管理器
swift
import UIKit
import Foundation
class BatteryMonitor {
static let shared = BatteryMonitor()
// 监控数据
private var batteryLevel: Float = 1.0
private var batteryState: UIDevice.BatteryState = .unknown
private var isMonitoring = false
// 历史记录
private var batteryHistory: [BatteryRecord] = []
private let maxHistoryCount = 1000
// 监控间隔
private var monitoringTimer: Timer?
private let monitoringInterval: TimeInterval = 60 // 60秒
struct BatteryRecord: Codable {
let timestamp: Date
let level: Float
let state: String
let temperature: Float?
let voltage: Float?
let current: Float?
}
private init() {
setupBatteryMonitoring()
}
// MARK: - Setup
private func setupBatteryMonitoring() {
// 启用电池监控
UIDevice.current.isBatteryMonitoringEnabled = true
// 监听电量变化
NotificationCenter.default.addObserver(
self,
selector: #selector(batteryLevelDidChange),
name: UIDevice.batteryLevelDidChangeNotification,
object: nil
)
// 监听充电状态变化
NotificationCenter.default.addObserver(
self,
selector: #selector(batteryStateDidChange),
name: UIDevice.batteryStateDidChangeNotification,
object: nil
)
}
// MARK: - Monitoring Control
func startMonitoring() {
guard !isMonitoring else { return }
isMonitoring = true
// 立即记录一次
recordBatteryStatus()
// 定时记录
monitoringTimer = Timer.scheduledTimer(
withTimeInterval: monitoringInterval,
repeats: true
) { [weak self] _ in
self?.recordBatteryStatus()
}
print("🔋 电量监控已启动")
}
func stopMonitoring() {
isMonitoring = false
monitoringTimer?.invalidate()
monitoringTimer = nil
print("🔋 电量监控已停止")
}
// MARK: - Battery Status
@objc private func batteryLevelDidChange() {
batteryLevel = UIDevice.current.batteryLevel
print("🔋 电量变化: \(Int(batteryLevel * 100))%")
// 检查低电量
if batteryLevel < 0.2 && batteryLevel > 0 {
notifyLowBattery()
}
recordBatteryStatus()
}
@objc private func batteryStateDidChange() {
batteryState = UIDevice.current.batteryState
let stateString = batteryStateString(batteryState)
print("🔋 充电状态变化: \(stateString)")
recordBatteryStatus()
}
private func recordBatteryStatus() {
let record = BatteryRecord(
timestamp: Date(),
level: UIDevice.current.batteryLevel,
state: batteryStateString(UIDevice.current.batteryState),
temperature: getBatteryTemperature(),
voltage: getBatteryVoltage(),
current: getBatteryCurrent()
)
batteryHistory.append(record)
// 限制历史记录数量
if batteryHistory.count > maxHistoryCount {
batteryHistory.removeFirst()
}
// 保存到本地
saveBatteryHistory()
}
// MARK: - Battery Info
func getCurrentBatteryLevel() -> Float {
return UIDevice.current.batteryLevel
}
func getCurrentBatteryState() -> UIDevice.BatteryState {
return UIDevice.current.batteryState
}
func isCharging() -> Bool {
let state = UIDevice.current.batteryState
return state == .charging || state == .full
}
private func batteryStateString(_ state: UIDevice.BatteryState) -> String {
switch state {
case .unknown:
return "未知"
case .unplugged:
return "未充电"
case .charging:
return "充电中"
case .full:
return "已充满"
@unknown default:
return "未知"
}
}
// MARK: - Battery Metrics (需要私有 API 或估算)
private func getBatteryTemperature() -> Float? {
// iOS 不提供公开 API 获取电池温度
// 可以通过 IOKit 私有 API 获取(不推荐上架 App Store)
return nil
}
private func getBatteryVoltage() -> Float? {
// iOS 不提供公开 API 获取电池电压
return nil
}
private func getBatteryCurrent() -> Float? {
// iOS 不提供公开 API 获取电池电流
return nil
}
// MARK: - Battery Analysis
// 计算电量消耗速率(%/小时)
func calculateBatteryDrainRate() -> Float? {
guard batteryHistory.count >= 2 else { return nil }
let recentRecords = batteryHistory.suffix(10)
guard let firstRecord = recentRecords.first,
let lastRecord = recentRecords.last else {
return nil
}
let timeDiff = lastRecord.timestamp.timeIntervalSince(firstRecord.timestamp)
guard timeDiff > 0 else { return nil }
let levelDiff = firstRecord.level - lastRecord.level
let hoursDiff = Float(timeDiff / 3600)
let drainRate = (levelDiff / hoursDiff) * 100
return drainRate
}
// 预估剩余使用时间(小时)
func estimateRemainingTime() -> Float? {
guard let drainRate = calculateBatteryDrainRate(),
drainRate > 0 else {
return nil
}
let currentLevel = UIDevice.current.batteryLevel * 100
let remainingTime = currentLevel / drainRate
return remainingTime
}
// 获取电量消耗报告
func getBatteryReport() -> BatteryReport {
let currentLevel = UIDevice.current.batteryLevel
let drainRate = calculateBatteryDrainRate()
let remainingTime = estimateRemainingTime()
return BatteryReport(
currentLevel: currentLevel,
drainRate: drainRate,
remainingTime: remainingTime,
isCharging: isCharging(),
recordCount: batteryHistory.count
)
}
struct BatteryReport {
let currentLevel: Float
let drainRate: Float?
let remainingTime: Float?
let isCharging: Bool
let recordCount: Int
func description() -> String {
var desc = """
========== 电量报告 ==========
当前电量: \(Int(currentLevel * 100))%
充电状态: \(isCharging ? "充电中" : "未充电")
"""
if let drainRate = drainRate {
desc += "\n消耗速率: \(String(format: "%.2f", drainRate))%/小时"
}
if let remainingTime = remainingTime {
desc += "\n预计剩余: \(String(format: "%.1f", remainingTime)) 小时"
}
desc += "\n记录数量: \(recordCount)"
desc += "\n===========================\n"
return desc
}
}
// MARK: - Notifications
private func notifyLowBattery() {
print("⚠️ 低电量警告")
// 发送通知
NotificationCenter.default.post(
name: NSNotification.Name("LowBatteryWarning"),
object: nil
)
}
// MARK: - Persistence
private func saveBatteryHistory() {
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
if let data = try? encoder.encode(batteryHistory) {
UserDefaults.standard.set(data, forKey: "BatteryHistory")
}
}
private func loadBatteryHistory() {
guard let data = UserDefaults.standard.data(forKey: "BatteryHistory") else {
return
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
if let history = try? decoder.decode([BatteryRecord].self, from: data) {
batteryHistory = history
}
}
// MARK: - Export
func exportBatteryHistory() -> String {
var csv = "时间,电量(%),状态\n"
for record in batteryHistory {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let timeString = dateFormatter.string(from: record.timestamp)
csv += "\(timeString),\(Int(record.level * 100)),\(record.state)\n"
}
return csv
}
}
2. CPU 监控
swift
import Foundation
class CPUMonitor {
static let shared = CPUMonitor()
private var monitoringTimer: Timer?
private var cpuHistory: [CPURecord] = []
struct CPURecord {
let timestamp: Date
let usage: Double
let threads: Int
}
private init() {}
// 开始监控
func startMonitoring(interval: TimeInterval = 1.0) {
monitoringTimer = Timer.scheduledTimer(
withTimeInterval: interval,
repeats: true
) { [weak self] _ in
self?.recordCPUUsage()
}
}
// 停止监控
func stopMonitoring() {
monitoringTimer?.invalidate()
monitoringTimer = nil
}
// 获取当前 CPU 使用率
func getCurrentCPUUsage() -> Double {
var totalUsage: Double = 0
var threadsList: thread_act_array_t?
var threadsCount = mach_msg_type_number_t(0)
let threadsResult = task_threads(mach_task_self_, &threadsList, &threadsCount)
guard threadsResult == KERN_SUCCESS,
let threads = threadsList else {
return 0
}
for index in 0...stride)
)
return totalUsage
}
// 记录 CPU 使用情况
private func recordCPUUsage() {
let usage = getCurrentCPUUsage()
let threads = getThreadCount()
let record = CPURecord(
timestamp: Date(),
usage: usage,
threads: threads
)
cpuHistory.append(record)
// 限制历史记录
if cpuHistory.count > 1000 {
cpuHistory.removeFirst()
}
// 检查异常
if usage > 80 {
print("⚠️ CPU 使用率过高: \(String(format: "%.1f", usage))%")
}
}
// 获取线程数量
private func getThreadCount() -> Int {
var threadsList: thread_act_array_t?
var threadsCount = mach_msg_type_number_t(0)
let result = task_threads(mach_task_self_, &threadsList, &threadsCount)
if result == KERN_SUCCESS {
vm_deallocate(
mach_task_self_,
vm_address_t(UInt(bitPattern: threadsList)),
vm_size_t(Int(threadsCount) * MemoryLayout.stride)
)
return Int(threadsCount)
}
return 0
}
// 获取平均 CPU 使用率
func getAverageCPUUsage(duration: TimeInterval = 60) -> Double {
let cutoffTime = Date().addingTimeInterval(-duration)
let recentRecords = cpuHistory.filter { $0.timestamp > cutoffTime }
guard !recentRecords.isEmpty else { return 0 }
let totalUsage = recentRecords.reduce(0) { $0 + $1.usage }
return totalUsage / Double(recentRecords.count)
}
}
3. 网络监控
swift
import Foundation
class NetworkMonitor {
static let shared = NetworkMonitor()
private var totalBytesSent: Int64 = 0
private var totalBytesReceived: Int64 = 0
private var lastCheckTime: Date = Date()
private var monitoringTimer: Timer?
struct NetworkStats {
let bytesSent: Int64
let bytesReceived: Int64
let uploadSpeed: Double // KB/s
let downloadSpeed: Double // KB/s
}
private init() {}
// 开始监控
func startMonitoring(interval: TimeInterval = 1.0) {
// 初始化基准值
updateNetworkStats()
monitoringTimer = Timer.scheduledTimer(
withTimeInterval: interval,
repeats: true
) { [weak self] _ in
self?.updateNetworkStats()
}
}
// 停止监控
func stopMonitoring() {
monitoringTimer?.invalidate()
monitoringTimer = nil
}
// 获取网络统计信息
func getNetworkStats() -> NetworkStats? {
var ifaddr: UnsafeMutablePointer?
guard getifaddrs(&ifaddr) == 0 else {
return nil
}
defer { freeifaddrs(ifaddr) }
var bytesSent: Int64 = 0
var bytesReceived: Int64 = 0
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next }
guard let interface = ptr?.pointee else { continue }
let name = String(cString: interface.ifa_name)
// 只统计 WiFi 和蜂窝网络
if name.hasPrefix("en") || name.hasPrefix("pdp_ip") {
if let data = interface.ifa_data?.assumingMemoryBound(to: if_data.self).pointee {
bytesSent += Int64(data.ifi_obytes)
bytesReceived += Int64(data.ifi_ibytes)
}
}
}
// 计算速度
let now = Date()
let timeDiff = now.timeIntervalSince(lastCheckTime)
let uploadSpeed = Double(bytesSent - totalBytesSent) / timeDiff / 1024
let downloadSpeed = Double(bytesReceived - totalBytesReceived) / timeDiff / 1024
totalBytesSent = bytesSent
totalBytesReceived = bytesReceived
lastCheckTime = now
return NetworkStats(
bytesSent: bytesSent,
bytesReceived: bytesReceived,
uploadSpeed: uploadSpeed,
downloadSpeed: downloadSpeed
)
}
private func updateNetworkStats() {
guard let stats = getNetworkStats() else { return }
// 检查异常流量
if stats.uploadSpeed > 100 || stats.downloadSpeed > 100 {
print("⚠️ 网络流量异常 - 上传: \(String(format: "%.1f", stats.uploadSpeed)) KB/s, 下载: \(String(format: "%.1f", stats.downloadSpeed)) KB/s")
}
}
}
CPU 优化
CPU 优化策略
graph TB
A[CPU 优化] --> B[减少计算]
A --> C[异步处理]
A --> D[缓存结果]
A --> E[降低频率]
B --> B1[算法优化]
B --> B2[减少循环]
B --> B3[避免重复计算]
C --> C1[后台线程]
C --> C2[GCD 优化]
C --> C3[Operation Queue]
D --> D1[内存缓存]
D --> D2[磁盘缓存]
D --> D3[计算结果缓存]
E --> E1[降低刷新率]
E --> E2[延迟执行]
E --> E3[批量处理]
style A fill:#4ECDC4
style B fill:#FF6B6B
style C fill:#FFA07A
style D fill:#95E1D3
style E fill:#F38181
1. 定时器优化
swift
class OptimizedTimer {
private var timer: DispatchSourceTimer?
private let queue: DispatchQueue
init(queue: DispatchQueue = .global(qos: .utility)) {
self.queue = queue
}
// 使用 DispatchSourceTimer 替代 Timer
func startTimer(interval: TimeInterval,
leeway: DispatchTimeInterval = .milliseconds(100),
handler: @escaping () -> Void) {
let timer = DispatchSource.makeTimerSource(queue: queue)
timer.schedule(
deadline: .now() + interval,
repeating: interval,
leeway: leeway // 允许系统延迟,节省电量
)
timer.setEventHandler(handler: handler)
timer.resume()
self.timer = timer
}
func stop() {
timer?.cancel()
timer = nil
}
deinit {
stop()
}
}
// 使用示例
class SomeViewController: UIViewController {
private let optimizedTimer = OptimizedTimer()
override func viewDidLoad() {
super.viewDidLoad()
// 使用优化的定时器
optimizedTimer.startTimer(interval: 1.0) {
// 定时任务
print("Timer fired")
}
}
deinit {
optimizedTimer.stop()
}
}
2. 图片处理优化
swift
class ImageProcessor {
static let shared = ImageProcessor()
private let processingQueue = DispatchQueue(
label: "com.app.imageProcessing",
qos: .utility
)
private let cache = NSCache()
private init() {
cache.countLimit = 100
cache.totalCostLimit = 50 * 1024 * 1024 // 50MB
}
// 异步处理图片
func processImage(_ image: UIImage,
size: CGSize,
completion: @escaping (UIImage?) -> Void) {
let cacheKey = "\(size.width)x\(size.height)" as NSString
// 检查缓存
if let cachedImage = cache.object(forKey: cacheKey) {
completion(cachedImage)
return
}
// 后台处理
processingQueue.async {
let processedImage = self.resize(image, to: size)
// 缓存结果
if let processedImage = processedImage {
self.cache.setObject(processedImage, forKey: cacheKey)
}
DispatchQueue.main.async {
completion(processedImage)
}
}
}
private func resize(_ image: UIImage, to size: CGSize) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
defer { UIGraphicsEndImageContext() }
image.draw(in: CGRect(origin: .zero, size: size))
return UIGraphicsGetImageFromCurrentImageContext()
}
// 降采样大图片
func downsampleImage(at url: URL, to size: CGSize) -> UIImage? {
let options: [CFString: Any] = [
kCGImageSourceCreateThumbnailFromImageIfAbsent: true,
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceShouldCacheImmediately: true,
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height)
]
guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil),
let image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) else {
return nil
}
return UIImage(cgImage: image)
}
}
3. 列表滚动优化
swift
class OptimizedTableViewController: UITableViewController {
private var data: [String] = []
private let cellReuseIdentifier = "Cell"
override func viewDidLoad() {
super.viewDidLoad()
// 1. 预估行高,避免实时计算
tableView.estimatedRowHeight = 44
tableView.rowHeight = UITableView.automaticDimension
// 2. 注册 cell
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 3. 复用 cell
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath)
// 4. 避免在 cellForRow 中进行复杂计算
cell.textLabel?.text = data[indexPath.row]
// 5. 异步加载图片
if let imageURL = getImageURL(for: indexPath.row) {
cell.imageView?.image = UIImage(named: "placeholder")
ImageLoader.shared.loadImage(from: imageURL) { image in
// 检查 cell 是否被复用
if let currentCell = tableView.cellForRow(at: indexPath) {
currentCell.imageView?.image = image
}
}
}
return cell
}
// 6. 延迟加载
override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
loadVisibleCells()
}
}
override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
loadVisibleCells()
}
private func loadVisibleCells() {
// 只加载可见 cell 的数据
}
private func getImageURL(for index: Int) -> URL? {
// 返回图片 URL
return nil
}
}
// 图片加载器
class ImageLoader {
static let shared = ImageLoader()
private let cache = NSCache()
private let loadingQueue = DispatchQueue(label: "com.app.imageLoading", qos: .utility)
func loadImage(from url: URL, completion: @escaping (UIImage?) -> Void) {
// 检查缓存
if let cachedImage = cache.object(forKey: url as NSURL) {
completion(cachedImage)
return
}
// 后台加载
loadingQueue.async {
guard let data = try? Data(contentsOf: url),
let image = UIImage(data: data) else {
DispatchQueue.main.async {
completion(nil)
}
return
}
// 缓存图片
self.cache.setObject(image, forKey: url as NSURL)
DispatchQueue.main.async {
completion(image)
}
}
}
}
网络优化
网络优化策略
graph TB
A[网络优化] --> B[减少请求]
A --> C[优化传输]
A --> D[智能调度]
A --> E[缓存策略]
B --> B1[请求合并]
B --> B2[批量处理]
B --> B3[取消无效请求]
C --> C1[数据压缩]
C --> C2[增量更新]
C --> C3[协议优化]
D --> D1[WiFi 优先]
D --> D2[延迟执行]
D --> D3[后台上传]
E --> E1[本地缓存]
E --> E2[过期策略]
E --> E3[预加载]
style A fill:#4ECDC4
style B fill:#FF6B6B
style C fill:#FFA07A
style D fill:#95E1D3
style E fill:#F38181
1. 网络请求优化
swift
class NetworkOptimizer {
static let shared = NetworkOptimizer()
private var pendingRequests: [String: [Request]] = [:]
private let batchInterval: TimeInterval = 0.5
struct Request {
let url: URL
let completion: (Result) -> Void
}
private init() {}
// 批量请求
func batchRequest(url: URL, completion: @escaping (Result) -> Void) {
let key = url.host ?? ""
let request = Request(url: url, completion: completion)
if pendingRequests[key] == nil {
pendingRequests[key] = []
// 延迟执行,收集更多请求
DispatchQueue.main.asyncAfter(deadline: .now() + batchInterval) {
self.executeBatchRequests(for: key)
}
}
pendingRequests[key]?.append(request)
}
private func executeBatchRequests(for key: String) {
guard let requests = pendingRequests[key], !requests.isEmpty else {
return
}
pendingRequests[key] = nil
print("📦 批量执行 \(requests.count) 个请求")
// 执行批量请求
for request in requests {
URLSession.shared.dataTask(with: request.url) { data, response, error in
if let error = error {
request.completion(.failure(error))
} else if let data = data {
request.completion(.success(data))
}
}.resume()
}
}
// 根据网络状态调整策略
func shouldExecuteRequest() -> Bool {
// 检查网络类型
let networkType = getNetworkType()
switch networkType {
case .wifi:
return true
case .cellular:
// 蜂窝网络下,检查是否允许
return UserDefaults.standard.bool(forKey: "AllowCellularData")
case .none:
return false
}
}
enum NetworkType {
case wifi
case cellular
case none
}
private func getNetworkType() -> NetworkType {
// 实现网络类型检测
return .wifi
}
}
2. 后台上传优化
swift
class BackgroundUploader {
static let shared = BackgroundUploader()
private lazy var session: URLSession = {
let config = URLSessionConfiguration.background(withIdentifier: "com.app.backgroundUpload")
config.isDiscretionary = true // 允许系统选择最佳时机
config.sessionSendsLaunchEvents = true
return URLSession(configuration: config, delegate: self, delegateQueue: nil)
}()
private init() {}
// 后台上传
func upload(fileURL: URL, to uploadURL: URL) {
var request = URLRequest(url: uploadURL)
request.httpMethod = "POST"
let task = session.uploadTask(with: request, fromFile: fileURL)
task.earliestBeginDate = Date().addingTimeInterval(60) // 延迟1分钟
task.countOfBytesClientExpectsToSend = 1024 * 1024 // 预估大小
task.countOfBytesClientExpectsToReceive = 1024
task.resume()
print("📤 后台上传任务已创建")
}
}
extension BackgroundUploader: URLSessionDelegate, URLSessionTaskDelegate {
func urlSession(_ session: URLSession,
task: URLSessionTask,
didCompleteWithError error: Error?) {
if let error = error {
print("❌ 上传失败: \(error)")
} else {
print("✅ 上传成功")
}
}
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
print("✅ 后台上传任务完成")
}
}
定位优化
定位优化策略
graph TB
A[定位优化] --> B[降低精度]
A --> C[减少频率]
A --> D[智能切换]
A --> E[延迟启动]
B --> B1[使用低精度]
B --> B2[避免GPS]
B --> B3[WiFi定位]
C --> C1[增加间隔]
C --> C2[距离过滤]
C --> C3[按需定位]
D --> D1[前后台切换]
D --> D2[场景适配]
D --> D3[电量感知]
E --> E1[延迟初始化]
E --> E2[用户触发]
E --> E3[批量定位]
style A fill:#4ECDC4
style B fill:#FF6B6B
style C fill:#FFA07A
style D fill:#95E1D3
style E fill:#F38181
1. 定位管理器优化
swift
import CoreLocation
class OptimizedLocationManager: NSObject {
static let shared = OptimizedLocationManager()
private let locationManager = CLLocationManager()
private var isMonitoring = false
// 定位回调
var locationUpdateHandler: ((CLLocation) -> Void)?
private override init() {
super.init()
setupLocationManager()
}
private func setupLocationManager() {
locationManager.delegate = self
// 1. 使用低精度定位
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
// 2. 设置距离过滤器
locationManager.distanceFilter = 100 // 移动100米才更新
// 3. 允许后台定位(如需要)
locationManager.allowsBackgroundLocationUpdates = false
// 4. 暂停自动更新
locationManager.pausesLocationUpdatesAutomatically = true
// 5. 活动类型
locationManager.activityType = .other
}
// 请求权限
func requestAuthorization() {
let status = CLLocationManager.authorizationStatus()
switch status {
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .authorizedWhenInUse, .authorizedAlways:
print("✅ 已授权定位")
case .denied, .restricted:
print("❌ 定位权限被拒绝")
@unknown default:
break
}
}
// 开始定位
func startUpdatingLocation() {
guard !isMonitoring else { return }
// 检查电量
let batteryLevel = UIDevice.current.batteryLevel
if batteryLevel < 0.2 && batteryLevel > 0 {
// 低电量模式:降低精度
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
locationManager.distanceFilter = 500
print("⚡️ 低电量模式:降低定位精度")
}
locationManager.startUpdatingLocation()
isMonitoring = true
print("📍 开始定位")
}
// 停止定位
func stopUpdatingLocation() {
locationManager.stopUpdatingLocation()
isMonitoring = false
print("📍 停止定位")
}
// 单次定位(更省电)
func requestSingleLocation() {
locationManager.requestLocation()
print("📍 请求单次定位")
}
// 区域监控(地理围栏)
func startMonitoringRegion(center: CLLocationCoordinate2D, radius: CLLocationDistance) {
let region = CLCircularRegion(
center: center,
radius: radius,
identifier: "CustomRegion"
)
region.notifyOnEntry = true
region.notifyOnExit = true
locationManager.startMonitoring(for: region)
print("📍 开始区域监控")
}
// 重要位置变化(最省电)
func startMonitoringSignificantLocationChanges() {
locationManager.startMonitoringSignificantLocationChanges()
print("📍 开始监控重要位置变化")
}
}
extension OptimizedLocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
print("📍 位置更新: \(location.coordinate.latitude), \(location.coordinate.longitude)")
locationUpdateHandler?(location)
}
func locationManager(_ manager: CLLocationManager,
didFailWithError error: Error) {
print("❌ 定位失败: \(error.localizedDescription)")
}
func locationManager(_ manager: CLLocationManager,
didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .authorizedWhenInUse, .authorizedAlways:
print("✅ 定位权限已授予")
case .denied, .restricted:
print("❌ 定位权限被拒绝")
default:
break
}
}
func locationManagerDidPauseLocationUpdates(_ manager: CLLocationManager) {
print("⏸️ 定位已暂停(自动)")
}
func locationManagerDidResumeLocationUpdates(_ manager: CLLocationManager) {
print("▶️ 定位已恢复")
}
}
2. 定位策略选择
swift
class LocationStrategy {
enum Strategy {
case highAccuracy // 高精度(GPS)
case balanced // 平衡模式
case lowPower // 省电模式
case significantChange // 重要变化
}
static func selectStrategy(batteryLevel: Float,
isCharging: Bool,
userPreference: Strategy?) -> Strategy {
// 用户偏好优先
if let preference = userPreference {
return preference
}
// 充电时使用高精度
if isCharging {
return .highAccuracy
}
// 根据电量选择
if batteryLevel < 0.2 {
return .significantChange
} else if batteryLevel < 0.5 {
return .lowPower
} else {
return .balanced
}
}
static func applyStrategy(_ strategy: Strategy,
to locationManager: CLLocationManager) {
switch strategy {
case .highAccuracy:
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
case .balanced:
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.distanceFilter = 100
case .lowPower:
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
locationManager.distanceFilter = 500
case .significantChange:
// 使用重要位置变化监控
locationManager.stopUpdatingLocation()
locationManager.startMonitoringSignificantLocationChanges()
}
}
}
后台任务优化
后台任务策略
graph TB
A[后台任务优化] --> B[后台刷新]
A --> C[后台下载]
A --> D[后台上传]
A --> E[后台处理]
B --> B1[降低频率]
B --> B2[批量处理]
B --> B3[智能调度]
C --> C1[延迟下载]
C --> C2[WiFi优先]
C --> C3[断点续传]
D --> D1[延迟上传]
D --> D2[压缩数据]
D --> D3[批量上传]
E --> E1[后台任务]
E --> E2[推送唤醒]
E --> E3[音频播放]
style A fill:#4ECDC4
style B fill:#FF6B6B
style C fill:#FFA07A
style D fill:#95E1D3
style E fill:#F38181
1. 后台刷新优化
swift
import UIKit
class BackgroundTaskManager {
static let shared = BackgroundTaskManager()
private var backgroundTask: UIBackgroundTaskIdentifier = .invalid
private init() {}
// 注册后台刷新
func registerBackgroundRefresh() {
UIApplication.shared.setMinimumBackgroundFetchInterval(
UIApplication.backgroundFetchIntervalMinimum
)
}
// 执行后台刷新
func performBackgroundFetch(completion: @escaping (UIBackgroundFetchResult) -> Void) {
print("🔄 开始后台刷新")
// 检查电量
let batteryLevel = UIDevice.current.batteryLevel
if batteryLevel < 0.2 && batteryLevel > 0 {
print("⚡️ 低电量,跳过后台刷新")
completion(.noData)
return
}
// 执行刷新任务
fetchNewData { hasNewData in
if hasNewData {
completion(.newData)
} else {
completion(.noData)
}
}
}
private func fetchNewData(completion: @escaping (Bool) -> Void) {
// 实现数据获取逻辑
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
completion(true)
}
}
// 开始后台任务
func beginBackgroundTask() {
backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
self?.endBackgroundTask()
}
}
// 结束后台任务
func endBackgroundTask() {
if backgroundTask != .invalid {
UIApplication.shared.endBackgroundTask(backgroundTask)
backgroundTask = .invalid
}
}
}
// AppDelegate 中使用
extension AppDelegate {
func application(_ application: UIApplication,
performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
BackgroundTaskManager.shared.performBackgroundFetch(completion: completionHandler)
}
func applicationDidEnterBackground(_ application: UIApplication) {
// 开始后台任务
BackgroundTaskManager.shared.beginBackgroundTask()
// 执行必要的清理工作
performCleanup {
BackgroundTaskManager.shared.endBackgroundTask()
}
}
private func performCleanup(completion: @escaping () -> Void) {
// 保存数据、清理缓存等
DispatchQueue.global().async {
// 清理工作
Thread.sleep(forTimeInterval: 2)
DispatchQueue.main.async {
completion()
}
}
}
}
2. 后台 URLSession
swift
class BackgroundSessionManager: NSObject {
static let shared = BackgroundSessionManager()
private lazy var session: URLSession = {
let config = URLSessionConfiguration.background(withIdentifier: "com.app.background")
// 配置后台会话
config.isDiscretionary = true // 允许系统优化
config.sessionSendsLaunchEvents = true
config.shouldUseExtendedBackgroundIdleMode = true
return URLSession(configuration: config, delegate: self, delegateQueue: nil)
}()
private var completionHandlers: [String: () -> Void] = [:]
private override init() {
super.init()
}
// 后台下载
func downloadFile(from url: URL, completion: @escaping () -> Void) {
let task = session.downloadTask(with: url)
// 设置最早开始时间(延迟执行)
task.earliestBeginDate = Date().addingTimeInterval(60)
completionHandlers[task.taskIdentifier.description] = completion
task.resume()
print("📥 后台下载任务已创建")
}
// 处理后台事件
func handleEventsForBackgroundURLSession(identifier: String,
completionHandler: @escaping () -> Void) {
completionHandlers[identifier] = completionHandler
}
}
extension BackgroundSessionManager: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL) {
print("✅ 下载完成: \(location)")
// 处理下载的文件
// ...
}
func urlSession(_ session: URLSession,
task: URLSessionTask,
didCompleteWithError error: Error?) {
if let error = error {
print("❌ 任务失败: \(error)")
}
// 调用完成回调
if let handler = completionHandlers[task.taskIdentifier.description] {
handler()
completionHandlers.removeValue(forKey: task.taskIdentifier.description)
}
}
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
print("✅ 后台会话完成")
DispatchQueue.main.async {
if let handler = self.completionHandlers[session.configuration.identifier!] {
handler()
self.completionHandlers.removeValue(forKey: session.configuration.identifier!)
}
}
}
}
渲染优化
1. 动画优化
swift
class AnimationOptimizer {
// 使用 CADisplayLink 优化动画
static func optimizeAnimation(duration: TimeInterval,
animations: @escaping (CGFloat) -> Void,
completion: (() -> Void)? = nil) {
let displayLink = CADisplayLink(target: self, selector: #selector(updateAnimation))
var startTime: CFTimeInterval?
var progress: CGFloat = 0
displayLink.add(to: .main, forMode: .common)
// 降低帧率以节省电量
if #available(iOS 15.0, *) {
displayLink.preferredFrameRateRange = CAFrameRateRange(
minimum: 30,
maximum: 60,
preferred: 60
)
} else {
displayLink.preferredFramesPerSecond = 30
}
}
@objc private static func updateAnimation(displayLink: CADisplayLink) {
// 更新动画
}
// 暂停不可见视图的动画
static func pauseAnimationsForInvisibleViews(in view: UIView) {
if view.window == nil {
view.layer.speed = 0
}
}
// 恢复动画
static func resumeAnimations(in view: UIView) {
view.layer.speed = 1
}
}
2. 屏幕刷新率优化
swift
class DisplayOptimizer {
static let shared = DisplayOptimizer()
private init() {}
// 根据场景调整刷新率
func adjustFrameRate(for scenario: Scenario) {
if #available(iOS 15.0, *) {
let range: CAFrameRateRange
switch scenario {
case .video:
// 视频播放:固定60fps
range = CAFrameRateRange(minimum: 60, maximum: 60, preferred: 60)
case .scrolling:
// 滚动:30-120fps
range = CAFrameRateRange(minimum: 30, maximum: 120, preferred: 120)
case .static:
// 静态内容:降低刷新率
range = CAFrameRateRange(minimum: 10, maximum: 30, preferred: 30)
case .lowPower:
// 低电量模式:最低刷新率
range = CAFrameRateRange(minimum: 10, maximum: 30, preferred: 10)
}
// 应用到 CADisplayLink 或动画
print("🖥️ 调整刷新率: \(range)")
}
}
enum Scenario {
case video
case scrolling
case static
case lowPower
}
}
传感器优化
1. 传感器管理
swift
import CoreMotion
class SensorManager {
static let shared = SensorManager()
private let motionManager = CMMotionManager()
private var isMonitoring = false
private init() {}
// 开始监控传感器
func startMonitoring() {
guard !isMonitoring else { return }
// 检查电量
let batteryLevel = UIDevice.current.batteryLevel
// 根据电量调整采样频率
if batteryLevel < 0.2 && batteryLevel > 0 {
motionManager.accelerometerUpdateInterval = 1.0 // 低频
} else {
motionManager.accelerometerUpdateInterval = 0.1 // 正常频率
}
// 开始更新
motionManager.startAccelerometerUpdates(to: .main) { data, error in
guard let data = data else { return }
self.handleAccelerometerData(data)
}
isMonitoring = true
print("📱 传感器监控已启动")
}
// 停止监控
func stopMonitoring() {
motionManager.stopAccelerometerUpdates()
motionManager.stopGyroUpdates()
motionManager.stopMagnetometerUpdates()
isMonitoring = false
print("📱 传感器监控已停止")
}
private func handleAccelerometerData(_ data: CMAccelerometerData) {
// 处理加速度计数据
}
// 使用 CMMotionActivityManager(更省电)
func startActivityMonitoring() {
let activityManager = CMMotionActivityManager()
activityManager.startActivityUpdates(to: .main) { activity in
guard let activity = activity else { return }
if activity.walking {
print("🚶 用户正在走路")
} else if activity.running {
print("🏃 用户正在跑步")
} else if activity.stationary {
print("🧍 用户静止")
}
}
}
}
完整监控方案
综合监控面板
swift
class PowerMonitoringDashboard: UIViewController {
private let batteryMonitor = BatteryMonitor.shared
private let cpuMonitor = CPUMonitor.shared
private let networkMonitor = NetworkMonitor.shared
private var dashboardView: UIView!
private var metricsLabels: [UILabel] = []
private var updateTimer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
startMonitoring()
}
private func setupUI() {
view.backgroundColor = .systemBackground
// 创建仪表板视图
dashboardView = UIView()
dashboardView.backgroundColor = UIColor.systemGray6
dashboardView.layer.cornerRadius = 12
dashboardView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(dashboardView)
NSLayoutConstraint.activate([
dashboardView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
dashboardView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
dashboardView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
dashboardView.heightAnchor.constraint(equalToConstant: 300)
])
// 创建指标标签
let metrics = ["电量", "CPU", "网络", "定位", "后台任务"]
var previousLabel: UILabel?
for metric in metrics {
let label = UILabel()
label.text = "\(metric): --"
label.font = .monospacedSystemFont(ofSize: 14, weight: .regular)
label.translatesAutoresizingMaskIntoConstraints = false
dashboardView.addSubview(label)
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: dashboardView.leadingAnchor, constant: 20),
label.trailingAnchor.constraint(equalTo: dashboardView.trailingAnchor, constant: -20)
])
if let previous = previousLabel {
label.topAnchor.constraint(equalTo: previous.bottomAnchor, constant: 15).isActive = true
} else {
label.topAnchor.constraint(equalTo: dashboardView.topAnchor, constant: 20).isActive = true
}
metricsLabels.append(label)
previousLabel = label
}
}
private func startMonitoring() {
// 启动各项监控
batteryMonitor.startMonitoring()
cpuMonitor.startMonitoring(interval: 1.0)
networkMonitor.startMonitoring(interval: 1.0)
// 定时更新UI
updateTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
self?.updateMetrics()
}
}
private func updateMetrics() {
// 更新电量
let batteryLevel = batteryMonitor.getCurrentBatteryLevel()
let batteryReport = batteryMonitor.getBatteryReport()
var batteryText = "电量: \(Int(batteryLevel * 100))%"
if let drainRate = batteryReport.drainRate {
batteryText += " (\(String(format: "%.1f", drainRate))%/h)"
}
metricsLabels[0].text = batteryText
// 更新CPU
let cpuUsage = cpuMonitor.getCurrentCPUUsage()
metricsLabels[1].text = "CPU: \(String(format: "%.1f", cpuUsage))%"
// 更新网络
if let networkStats = networkMonitor.getNetworkStats() {
let networkText = "网络: ↑\(String(format: "%.1f", networkStats.uploadSpeed)) ↓\(String(format: "%.1f", networkStats.downloadSpeed)) KB/s"
metricsLabels[2].text = networkText
}
// 更新定位
```swift
// 更新定位
metricsLabels[3].text = "定位: \(OptimizedLocationManager.shared.isMonitoring ? "运行中" : "已停止")"
// 更新后台任务
let backgroundTaskStatus = BackgroundTaskManager.shared.backgroundTask != .invalid
metricsLabels[4].text = "后台任务: \(backgroundTaskStatus ? "运行中" : "空闲")"
// 根据电量状态更新颜色
updateMetricsColor(batteryLevel: batteryLevel)
}
private func updateMetricsColor(batteryLevel: Float) {
let color: UIColor
if batteryLevel < 0.2 {
color = .systemRed
} else if batteryLevel < 0.5 {
color = .systemOrange
} else {
color = .systemGreen
}
metricsLabels[0].textColor = color
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// 停止监控
updateTimer?.invalidate()
updateTimer = nil
}
deinit {
batteryMonitor.stopMonitoring()
cpuMonitor.stopMonitoring()
networkMonitor.stopMonitoring()
}
}
电量优化建议系统
swift
class PowerOptimizationAdvisor {
static let shared = PowerOptimizationAdvisor()
struct OptimizationSuggestion {
let title: String
let description: String
let priority: Priority
let action: (() -> Void)?
enum Priority {
case high
case medium
case low
}
}
private init() {}
// 分析并生成优化建议
func analyzePowerUsage() -> [OptimizationSuggestion] {
var suggestions: [OptimizationSuggestion] = []
// 1. 检查 CPU 使用率
let cpuUsage = CPUMonitor.shared.getCurrentCPUUsage()
if cpuUsage > 50 {
suggestions.append(OptimizationSuggestion(
title: "CPU 使用率过高",
description: "当前 CPU 使用率 \(String(format: "%.1f", cpuUsage))%,建议优化计算密集型任务",
priority: .high,
action: {
// 提供优化建议或自动优化
print("建议:将计算任务移到后台线程")
}
))
}
// 2. 检查网络使用
if let networkStats = NetworkMonitor.shared.getNetworkStats() {
if networkStats.uploadSpeed > 100 || networkStats.downloadSpeed > 100 {
suggestions.append(OptimizationSuggestion(
title: "网络流量较大",
description: "当前网络流量较大,建议在 WiFi 环境下使用",
priority: .medium,
action: nil
))
}
}
// 3. 检查定位服务
if OptimizedLocationManager.shared.isMonitoring {
let batteryLevel = UIDevice.current.batteryLevel
if batteryLevel < 0.3 {
suggestions.append(OptimizationSuggestion(
title: "定位服务消耗电量",
description: "当前电量较低,建议降低定位精度或暂停定位",
priority: .high,
action: {
// 自动降低定位精度
OptimizedLocationManager.shared.stopUpdatingLocation()
print("已自动停止定位服务")
}
))
}
}
// 4. 检查后台刷新
let backgroundRefreshStatus = UIApplication.shared.backgroundRefreshStatus
if backgroundRefreshStatus == .available {
suggestions.append(OptimizationSuggestion(
title: "后台刷新已启用",
description: "后台刷新会消耗额外电量,可在设置中关闭",
priority: .low,
action: nil
))
}
// 5. 检查屏幕亮度
let brightness = UIScreen.main.brightness
if brightness > 0.8 {
suggestions.append(OptimizationSuggestion(
title: "屏幕亮度较高",
description: "当前屏幕亮度 \(Int(brightness * 100))%,建议降低亮度以节省电量",
priority: .medium,
action: {
UIScreen.main.brightness = 0.5
print("已自动调整屏幕亮度")
}
))
}
return suggestions
}
// 自动优化
func autoOptimize() {
let suggestions = analyzePowerUsage()
// 执行高优先级的优化建议
let highPrioritySuggestions = suggestions.filter { $0.priority == .high }
for suggestion in highPrioritySuggestions {
print("🔧 执行优化: \(suggestion.title)")
suggestion.action?()
}
}
// 生成优化报告
func generateOptimizationReport() -> String {
let suggestions = analyzePowerUsage()
var report = """
========== 电量优化报告 ==========
生成时间: \(Date())
"""
if suggestions.isEmpty {
report += "✅ 当前电量使用良好,无需优化\n"
} else {
report += "发现 \(suggestions.count) 项优化建议:\n\n"
for (index, suggestion) in suggestions.enumerated() {
let priorityEmoji: String
switch suggestion.priority {
case .high: priorityEmoji = "🔴"
case .medium: priorityEmoji = "🟡"
case .low: priorityEmoji = "🟢"
}
report += "\(index + 1). \(priorityEmoji) \(suggestion.title)\n"
report += " \(suggestion.description)\n\n"
}
}
report += "================================\n"
return report
}
}
电量优化设置页面
swift
class PowerSettingsViewController: UITableViewController {
private let settings = [
SettingSection(
title: "定位服务",
items: [
SettingItem(title: "定位精度", value: "平衡", action: #selector(adjustLocationAccuracy)),
SettingItem(title: "后台定位", value: "关闭", action: #selector(toggleBackgroundLocation))
]
),
SettingSection(
title: "网络",
items: [
SettingItem(title: "仅 WiFi 下载", value: "开启", action: #selector(toggleWiFiOnly)),
SettingItem(title: "后台刷新", value: "关闭", action: #selector(toggleBackgroundRefresh))
]
),
SettingSection(
title: "性能",
items: [
SettingItem(title: "降低动画效果", value: "关闭", action: #selector(toggleReduceMotion)),
SettingItem(title: "自动优化", value: "开启", action: #selector(toggleAutoOptimization))
]
)
]
struct SettingSection {
let title: String
let items: [SettingItem]
}
struct SettingItem {
let title: String
var value: String
let action: Selector
}
override func viewDidLoad() {
super.viewDidLoad()
title = "电量优化设置"
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
// MARK: - Table View Data Source
override func numberOfSections(in tableView: UITableView) -> Int {
return settings.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return settings[section].items.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return settings[section].title
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let item = settings[indexPath.section].items[indexPath.row]
cell.textLabel?.text = item.title
cell.detailTextLabel?.text = item.value
cell.accessoryType = .disclosureIndicator
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let item = settings[indexPath.section].items[indexPath.row]
perform(item.action)
}
// MARK: - Actions
@objc private func adjustLocationAccuracy() {
let alert = UIAlertController(
title: "定位精度",
message: "选择定位精度级别",
preferredStyle: .actionSheet
)
alert.addAction(UIAlertAction(title: "高精度(耗电)", style: .default) { _ in
self.setLocationAccuracy(.best)
})
alert.addAction(UIAlertAction(title: "平衡", style: .default) { _ in
self.setLocationAccuracy(.hundredMeters)
})
alert.addAction(UIAlertAction(title: "省电", style: .default) { _ in
self.setLocationAccuracy(.kilometer)
})
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
present(alert, animated: true)
}
private func setLocationAccuracy(_ accuracy: CLLocationAccuracy) {
let locationManager = OptimizedLocationManager.shared
// 设置定位精度
print("设置定位精度: \(accuracy)")
}
@objc private func toggleBackgroundLocation() {
// 切换后台定位
print("切换后台定位")
}
@objc private func toggleWiFiOnly() {
// 切换仅 WiFi 下载
let current = UserDefaults.standard.bool(forKey: "WiFiOnly")
UserDefaults.standard.set(!current, forKey: "WiFiOnly")
print("仅 WiFi 下载: \(!current)")
}
@objc private func toggleBackgroundRefresh() {
// 切换后台刷新
print("切换后台刷新")
}
@objc private func toggleReduceMotion() {
// 切换降低动画效果
print("切换降低动画效果")
}
@objc private func toggleAutoOptimization() {
// 切换自动优化
let current = UserDefaults.standard.bool(forKey: "AutoOptimization")
UserDefaults.standard.set(!current, forKey: "AutoOptimization")
if !current {
PowerOptimizationAdvisor.shared.autoOptimize()
}
print("自动优化: \(!current)")
}
}
最佳实践
优化检查清单
markdown
## iOS 电量优化检查清单
### ✅ CPU 优化
- [ ] 避免主线程阻塞
- [ ] 使用后台线程处理耗时任务
- [ ] 优化算法和数据结构
- [ ] 减少定时器使用
- [ ] 使用 Instruments 分析 CPU 热点
- [ ] 实现计算结果缓存
- [ ] 降低动画帧率
### ✅ 网络优化
- [ ] 减少网络请求频率
- [ ] 实现请求合并和批处理
- [ ] 使用数据压缩
- [ ] 实现智能缓存策略
- [ ] WiFi 优先策略
- [ ] 后台任务延迟执行
- [ ] 使用 HTTP/2 或 HTTP/3
### ✅ 定位优化
- [ ] 使用合适的定位精度
- [ ] 设置距离过滤器
- [ ] 使用重要位置变化监控
- [ ] 实现定位超时机制
- [ ] 根据电量调整定位策略
- [ ] 不需要时及时停止定位
- [ ] 使用地理围栏替代持续定位
### ✅ 后台任务优化
- [ ] 降低后台刷新频率
- [ ] 使用后台 URLSession
- [ ] 实现任务延迟执行
- [ ] 及时结束后台任务
- [ ] 批量处理后台任务
- [ ] 监控后台任务时长
### ✅ 渲染优化
- [ ] 减少视图层级
- [ ] 使用异步绘制
- [ ] 优化图片加载
- [ ] 降低动画复杂度
- [ ] 使用 CADisplayLink 优化动画
- [ ] 暂停不可见视图的动画
- [ ] 根据场景调整刷新率
### ✅ 传感器优化
- [ ] 降低传感器采样频率
- [ ] 不使用时及时停止
- [ ] 使用 CMMotionActivityManager
- [ ] 批量处理传感器数据
- [ ] 根据电量调整采样策略
### ✅ 监控与分析
- [ ] 实现电量监控系统
- [ ] 收集电量消耗数据
- [ ] 定期分析电量报告
- [ ] 设置电量告警
- [ ] 提供优化建议
- [ ] 实现自动优化
电量优化效果对比
| 优化项 | 优化前 | 优化后 | 节省电量 |
|---|---|---|---|
| CPU 使用 | 持续 50% | 平均 20% | 40% |
| 网络请求 | 每秒 5 次 | 每 10 秒 1 次 | 60% |
| 定位服务 | GPS 持续定位 | 重要位置变化 | 80% |
| 后台刷新 | 每 15 分钟 | 每小时 | 75% |
| 动画渲染 | 60fps 持续 | 按需 30fps | 50% |
| 总体电量 | 15%/小时 | 6%/小时 | 60% |
常见问题解决
Q1: 如何检测应用的电量消耗?
A: 使用多种方法:
swift
class BatteryDiagnostics {
// 1. 使用 Xcode Energy Log
static func enableEnergyLogging() {
// 在 Xcode 中:Product → Profile → Energy Log
print("使用 Xcode Energy Log 分析电量消耗")
}
// 2. 使用 Instruments
static func useInstruments() {
// 使用 Energy Log 和 Time Profiler
print("使用 Instruments 分析")
}
// 3. 监控电量变化
static func monitorBatteryDrain() {
let monitor = BatteryMonitor.shared
monitor.startMonitoring()
// 记录一段时间的电量变化
DispatchQueue.main.asyncAfter(deadline: .now() + 3600) {
if let drainRate = monitor.calculateBatteryDrainRate() {
print("电量消耗速率: \(drainRate)%/小时")
}
}
}
// 4. 使用 MetricKit(iOS 13+)
static func useMetricKit() {
// 收集电量诊断数据
print("使用 MetricKit 收集电量数据")
}
}
Q2: 低电量模式如何适配?
A: 实现低电量模式检测和适配:
swift
class LowPowerModeManager {
static let shared = LowPowerModeManager()
private init() {
// 监听低电量模式变化
NotificationCenter.default.addObserver(
self,
selector: #selector(powerStateDidChange),
name: Notification.Name.NSProcessInfoPowerStateDidChange,
object: nil
)
}
// 检查是否处于低电量模式
func isLowPowerModeEnabled() -> Bool {
return ProcessInfo.processInfo.isLowPowerModeEnabled
}
@objc private func powerStateDidChange() {
let isLowPower = isLowPowerModeEnabled()
print("⚡️ 低电量模式: \(isLowPower ? "开启" : "关闭")")
if isLowPower {
enablePowerSavingMode()
} else {
disablePowerSavingMode()
}
}
// 启用省电模式
private func enablePowerSavingMode() {
print("🔋 启用省电模式")
// 1. 降低定位精度
OptimizedLocationManager.shared.stopUpdatingLocation()
// 2. 减少网络请求
NetworkOptimizer.shared.batchInterval = 2.0
// 3. 降低动画帧率
DisplayOptimizer.shared.adjustFrameRate(for: .lowPower)
// 4. 停止传感器监控
SensorManager.shared.stopMonitoring()
// 5. 暂停后台任务
BackgroundTaskManager.shared.endBackgroundTask()
// 6. 降低屏幕亮度
UIScreen.main.brightness = max(UIScreen.main.brightness - 0.2, 0.3)
}
// 禁用省电模式
private func disablePowerSavingMode() {
print("🔋 禁用省电模式")
// 恢复正常设置
NetworkOptimizer.shared.batchInterval = 0.5
DisplayOptimizer.shared.adjustFrameRate(for: .scrolling)
}
}
Q3: 如何优化推送通知的电量消耗?
A: 优化推送策略:
swift
class PushNotificationOptimizer {
static let shared = PushNotificationOptimizer()
private init() {}
// 智能推送策略
func shouldSendPushNotification(priority: Priority) -> Bool {
// 1. 检查电量
let batteryLevel = UIDevice.current.batteryLevel
if batteryLevel < 0.1 && priority != .critical {
print("⚡️ 电量过低,跳过非关键推送")
return false
}
// 2. 检查低电量模式
if ProcessInfo.processInfo.isLowPowerModeEnabled && priority == .low {
print("⚡️ 低电量模式,跳过低优先级推送")
return false
}
// 3. 检查时间段(夜间减少推送)
let hour = Calendar.current.component(.hour, from: Date())
if (22...6).contains(hour) && priority != .critical {
print("🌙 夜间时段,跳过非关键推送")
return false
}
return true
}
enum Priority {
case critical // 关键通知
case high // 高优先级
case normal // 普通
case low // 低优先级
}
// 批量推送
func batchPushNotifications(notifications: [UNNotificationRequest]) {
// 合并相似的通知
let grouped = Dictionary(grouping: notifications) { $0.content.categoryIdentifier }
for (category, requests) in grouped {
if requests.count > 1 {
// 创建合并通知
let content = UNMutableNotificationContent()
content.title = category
content.body = "您有 \(requests.count) 条新消息"
let request = UNNotificationRequest(
identifier: UUID().uuidString,
content: content,
trigger: nil
)
UNUserNotificationCenter.current().add(request)
print("📦 合并了 \(requests.count) 条通知")
} else {
// 单独发送
requests.forEach { UNUserNotificationCenter.current().add($0) }
}
}
}
}
Q4: 如何监控第三方 SDK 的电量消耗?
A: 实现 SDK 监控:
swift
class SDKPowerMonitor {
static let shared = SDKPowerMonitor()
private var sdkMetrics: [String: SDKMetric] = [:]
struct SDKMetric {
var cpuUsage: Double = 0
var networkBytes: Int64 = 0
var locationUpdates: Int = 0
var startTime: Date
}
private init() {}
// 开始监控 SDK
func startMonitoring(sdkName: String) {
sdkMetrics[sdkName] = SDKMetric(startTime: Date())
print("📊 开始监控 SDK: \(sdkName)")
}
// 停止监控并生成报告
func stopMonitoring(sdkName: String) -> String? {
guard let metric = sdkMetrics[sdkName] else {
return nil
}
let duration = Date().timeIntervalSince(metric.startTime)
let report = """
========== SDK 电量报告 ==========
SDK 名称: \(sdkName)
运行时长: \(String(format: "%.1f", duration)) 秒
CPU 使用: \(String(format: "%.1f", metric.cpuUsage))%
网络流量: \(metric.networkBytes / 1024) KB
定位次数: \(metric.locationUpdates)
================================
"""
sdkMetrics.removeValue(forKey: sdkName)
return report
}
// 记录 SDK 活动
func recordActivity(sdkName: String, type: ActivityType) {
guard var metric = sdkMetrics[sdkName] else { return }
switch type {
case .cpuUsage(let usage):
metric.cpuUsage = usage
case .networkBytes(let bytes):
metric.networkBytes += bytes
case .locationUpdate:
metric.locationUpdates += 1
}
sdkMetrics[sdkName] = metric
}
enum ActivityType {
case cpuUsage(Double)
case networkBytes(Int64)
case locationUpdate
}
}
性能优化工具
1. Xcode Instruments
swift
class InstrumentsHelper {
// 使用 Energy Log
static func analyzeWithEnergyLog() {
print("使用 Xcode Energy Log 分析:")
}
// 使用 Time Profiler
static func analyzeWithTimeProfiler() {
print("使用 Time Profiler 分析 CPU:")
}
// 使用 Network
static func analyzeWithNetwork() {
print("使用 Network Instrument 分析:")
}
}
2. 性能测试
swift
class PowerPerformanceTest {
// 电量消耗测试
static func testBatteryDrain(duration: TimeInterval = 3600) {
print("🧪 开始电量消耗测试(\(duration/60) 分钟)")
let monitor = BatteryMonitor.shared
monitor.startMonitoring()
let startLevel = monitor.getCurrentBatteryLevel()
let startTime = Date()
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
let endLevel = monitor.getCurrentBatteryLevel()
let endTime = Date()
let drain = (startLevel - endLevel) * 100
let actualDuration = endTime.timeIntervalSince(startTime) / 3600
let drainRate = drain / Float(actualDuration)
print("""
========== 电量测试结果 ==========
测试时长: \(String(format: "%.1f", actualDuration)) 小时
电量消耗: \(String(format: "%.1f", drain))%
消耗速率: \(String(format: "%.1f", drainRate))%/小时
================================
""")
}
}
// CPU 压力测试
static func testCPULoad() {
print("🧪 开始 CPU 压力测试")
let monitor = CPUMonitor.shared
monitor.startMonitoring(interval: 0.1)
// 模拟 CPU 密集任务
DispatchQueue.global(qos: .userInitiated).async {
var result = 0.0
for i in 0..