Token导航 LogoToken导航

Agent Skill · 运维和基础设施

axiom-energy-ref(公理能量参考)

axiom-energy-ref 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

axiom-energy-ref 是运维和基础设施类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证为 MIT,第三方扫描有未通过项,按安装量在运维和基础设施类的 2,449 个 Skill 里排第 452。

总安装 4,235周安装 173GitHub Stars 873下载 1,370核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:axiom-energy-ref(公理能量参考)
来源仓库:https://github.com/charleswiltgen/axiom
仓库路径:skills/axiom-energy-ref
安装命令:
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-energy-ref
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-energy-ref

这个 Skill 是做什么的

运维和基础设施类 Skill 处理部署、监控、日志和云资源,多数需要较高的执行权限。

用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。

提供 iOS 能源优化的完整 API 参考,包含 Instruments 中 Power Profiler 的使用流程和代码示例。通过 GitHub 仓库安装,使用 npx skills add 命令添加指定技能,需结合原始 README 进一步确认具体用法。

安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写操作。axiom-energy-ref 属于运维和基础设施类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/axiom-energy-ref

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/charleswiltgen/axiom --skill axiom-energy-ref;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

axiom-energy-ref 怎么安装?

在终端执行 npx skills add https://github.com/charleswiltgen/axiom --skill axiom-energy-ref。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

axiom-energy-ref 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

axiom-energy-ref 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

axiom-energy-ref 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

axiom-energy-ref 用的人多吗?

公开数据是累计安装 4,235 次,近一周安装 173 次,下载 1,370 次,GitHub 873 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

axiom-energy-ref 安全吗?

第三方扫描有未通过项,风险较高。除非你确认过源码,否则不建议直接安装到常用环境。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。

先想清楚的地方

  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理运维和基础设施类任务、又不想每次都手写提示词的人。

不太适合

  • 需要厂商级技术支持和 SLA 的生产系统。

运维和基础设施类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
brainstorming

头脑风暴 · Codex、Claude

3,148,776173,131操作浏览器MIT通过
copywriting

文案写作 · Codex、Claude

1,996,72425,583需要联网MIT通过
openclaw-secure-linux-cloud

OpenClaw secure linux cloud 命令行 · Codex、Claude

1,853,08840接触敏感数据未明确未通过
xget

xget 命令行 · Codex、Claude

1,799,28040执行命令未明确未通过
requesting-code-review

代码审查请求 · Codex、Claude

1,590,144173,103权限未标注MIT通过
axiom-energy-ref

公理能量参考 · 本页

4,235873需要联网MIT未通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Energy Optimization Reference

Complete API reference for iOS energy optimization, with code examples from WWDC sessions and Apple documentation.

Related skills: axiom-energy (decision trees, patterns), axiom-energy-diag (troubleshooting)


Part 1: Power Profiler Workflow

Recording a Trace with Instruments

Tethered Recording (Connected to Mac)
1. Connect iPhone wirelessly to Xcode
   - Xcode → Window → Devices and Simulators
   - Enable "Connect via network" for your device

2. Profile your app
   - Xcode → Product → Profile (Cmd+I)
   - Select Blank template
   - Click "+" → Add "Power Profiler"
   - Optionally add "CPU Profiler" for correlation

3. Record
   - Select your app from target dropdown
   - Click Record (red button)
   - Use app normally for 2-3 minutes
   - Click Stop

4. Analyze
   - Expand Power Profiler track
   - Examine per-app lanes: CPU, GPU, Display, Network

Important: Use wireless debugging. When device is charging via cable, system power usage shows 0.

On-Device Recording (Without Mac)

From WWDC25-226: Capture traces in real-world conditions.

1. Enable Developer Mode
   Settings → Privacy & Security → Developer Mode → Enable

2. Enable Performance Trace
   Settings → Developer → Performance Trace → Enable
   Set tracing mode to "Power Profiler"
   Toggle ON your app in the app list

3. Add Control Center shortcut
   Control Center → Tap "+" → Add a Control → Performance Trace

4. Record
   Swipe down → Tap Performance Trace icon → Start
   Use app (can record up to 10 hours)
   Tap Performance Trace icon → Stop

5. Share trace
   Settings → Developer → Performance Trace
   Tap Share button next to trace file
   AirDrop to Mac or email to developer

Interpreting Power Profiler Metrics

LaneMeaningWhat High Values Indicate
System PowerOverall battery drain rateGeneral energy consumption
CPU Power ImpactProcessor activity scoreComputation, timers, parsing
GPU Power ImpactGraphics rendering scoreAnimations, blur, Metal
Display Power ImpactScreen power usageBrightness, content type
Network Power ImpactRadio activity scoreRequests, downloads, polling

Key insight: Values are scores for comparison, not absolute measurements. Compare before/after traces on the same device.

Comparing Before/After (Example from WWDC25-226)

// Before optimization: CPU Power Impact = 21
VStack {
    ForEach(videos) { video in
        VideoCardView(video: video)
    }
}

// After optimization: CPU Power Impact = 4.3
LazyVStack {
    ForEach(videos) { video in
        VideoCardView(video: video)
    }
}

Part 2: Timer Efficiency APIs

NSTimer with Tolerance

// Basic timer with tolerance
let timer = Timer.scheduledTimer(
    withTimeInterval: 1.0,
    repeats: true
) { [weak self] _ in
    self?.updateUI()
}
timer.tolerance = 0.1  // 10% minimum recommended

// Add to run loop (if not using scheduledTimer)
RunLoop.current.add(timer, forMode: .common)

// Always invalidate when done
deinit {
    timer.invalidate()
}

Combine Timer Publisher

import Combine

class ViewModel: ObservableObject {
    private var cancellables = Set<AnyCancellable>()

    func startPolling() {
        Timer.publish(every: 1.0, tolerance: 0.1, on: .main, in: .default)
            .autoconnect()
            .sink { [weak self] _ in
                self?.refresh()
            }
            .store(in: &cancellables)
    }

    func stopPolling() {
        cancellables.removeAll()
    }
}

Dispatch Timer Source (Low-Level)

From Energy Efficiency Guide:

let queue = DispatchQueue(label: "com.app.timer")
let timer = DispatchSource.makeTimerSource(queue: queue)

// Set interval with leeway (tolerance)
timer.schedule(
    deadline: .now(),
    repeating: .seconds(1),
    leeway: .milliseconds(100)  // 10% tolerance
)

timer.setEventHandler { [weak self] in
    self?.performWork()
}

timer.resume()

// Cancel when done
timer.cancel()
For DispatchSourceTimer lifecycle safety and crash prevention, see axiom-timer-patterns.

Event-Driven Alternative to Timers

From Energy Efficiency Guide: Prefer dispatch sources over polling.

// Monitor file changes instead of polling
let fileDescriptor = open(filePath.path, O_EVTONLY)
let source = DispatchSource.makeFileSystemObjectSource(
    fileDescriptor: fileDescriptor,
    eventMask: [.write, .delete],
    queue: .main
)

source.setEventHandler { [weak self] in
    self?.handleFileChange()
}

source.setCancelHandler {
    close(fileDescriptor)
}

source.resume()

Part 3: Network Efficiency APIs

URLSession Configuration

// Standard configuration with energy-conscious settings
let config = URLSessionConfiguration.default
config.waitsForConnectivity = true  // Don't fail immediately
config.allowsExpensiveNetworkAccess = false  // Prefer WiFi
config.allowsConstrainedNetworkAccess = false  // Respect Low Data Mode

let session = URLSession(configuration: config)

Discretionary Background Downloads

From WWDC22-10083:

// Background session for non-urgent downloads
let config = URLSessionConfiguration.background(
    withIdentifier: "com.app.downloads"
)
config.isDiscretionary = true  // System chooses optimal time
config.sessionSendsLaunchEvents = true

// Set timeouts
config.timeoutIntervalForResource = 24 * 60 * 60  // 24 hours
config.timeoutIntervalForRequest = 60

let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)

// Create download task with scheduling hints
let task = session.downloadTask(with: url)
task.earliestBeginDate = Date(timeIntervalSinceNow: 2 * 60 * 60)  // 2 hours from now
task.countOfBytesClientExpectsToSend = 200  // Small request
task.countOfBytesClientExpectsToReceive = 500_000  // 500KB response

task.resume()

Background Session Delegate

class DownloadDelegate: NSObject, URLSessionDownloadDelegate {
    func urlSession(
        _ session: URLSession,
        downloadTask: URLSessionDownloadTask,
        didFinishDownloadingTo location: URL
    ) {
        // Move file from temp location
        let destination = FileManager.default.urls(
            for: .documentDirectory,
            in: .userDomainMask
        )[0].appendingPathComponent("downloaded.data")

        try? FileManager.default.moveItem(at: location, to: destination)
    }

    func urlSessionDidFinishEvents(
        forBackgroundURLSession session: URLSession
    ) {
        // Notify app delegate to call completion handler
        DispatchQueue.main.async {
            if let handler = AppDelegate.shared.backgroundCompletionHandler {
                handler()
                AppDelegate.shared.backgroundCompletionHandler = nil
            }
        }
    }
}

Part 4: Location Efficiency APIs

CLLocationManager Configuration

import CoreLocation

class LocationService: NSObject, CLLocationManagerDelegate {
    private let manager = CLLocationManager()

    func configure() {
        manager.delegate = self

        // Use appropriate accuracy
        manager.desiredAccuracy = kCLLocationAccuracyHundredMeters

        // Reduce update frequency
        manager.distanceFilter = 100  // Update every 100 meters

        // Allow indicator pause when stationary
        manager.pausesLocationUpdatesAutomatically = true

        // For background updates (if needed)
        manager.allowsBackgroundLocationUpdates = true
        manager.showsBackgroundLocationIndicator = true
    }

    func startTracking() {
        manager.requestWhenInUseAuthorization()
        manager.startUpdatingLocation()
    }

    func startSignificantChangeTracking() {
        // Much more energy efficient for background
        manager.startMonitoringSignificantLocationChanges()
    }

    func stopTracking() {
        manager.stopUpdatingLocation()
        manager.stopMonitoringSignificantLocationChanges()
    }
}

iOS 26+ CLLocationUpdate (Modern Async API)

import CoreLocation

func trackLocation() async throws {
    for try await update in CLLocationUpdate.liveUpdates() {
        // Check if device became stationary
        if update.stationary {
            // System pauses updates automatically
            // Consider switching to region monitoring
            break
        }

        if let location = update.location {
            handleLocation(location)
        }
    }
}

CLMonitor for Significant Changes

import CoreLocation

func setupRegionMonitoring() async {
    let monitor = CLMonitor("significant-changes")

    // Add condition to monitor
    let condition = CLMonitor.CircularGeographicCondition(
        center: currentLocation.coordinate,
        radius: 500  // 500 meter radius
    )
    await monitor.add(condition, identifier: "home-region")

    // React to events
    for try await event in monitor.events {
        switch event.state {
        case .satisfied:
            // Entered region
            handleRegionEntry()
        case .unsatisfied:
            // Exited region
            handleRegionExit()
        default:
            break
        }
    }
}

Location Accuracy Options

ConstantAccuracyBattery ImpactUse Case
kCLLocationAccuracyBestForNavigation~1mExtremeTurn-by-turn only
kCLLocationAccuracyBest~10mVery HighFitness tracking
kCLLocationAccuracyNearestTenMeters~10mHighPrecise positioning
kCLLocationAccuracyHundredMeters~100mMediumStore locators
kCLLocationAccuracyKilometer~1kmLowWeather, general
kCLLocationAccuracyThreeKilometers~3kmVery LowRegional content

Part 5: Background Execution APIs

beginBackgroundTask (Short Tasks)

class AppDelegate: UIResponder, UIApplicationDelegate {
    var backgroundTask: UIBackgroundTaskIdentifier = .invalid

    func applicationDidEnterBackground(_ application: UIApplication) {
        backgroundTask = application.beginBackgroundTask(withName: "Save State") {
            // Expiration handler - clean up
            self.endBackgroundTask()
        }

        // Perform quick work
        saveState()

        // End immediately when done
        endBackgroundTask()
    }

    private func endBackgroundTask() {
        guard backgroundTask != .invalid else { return }
        UIApplication.shared.endBackgroundTask(backgroundTask)
        backgroundTask = .invalid
    }
}

BGAppRefreshTask

import BackgroundTasks

// Register at app launch
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    BGTaskScheduler.shared.register(
        forTaskWithIdentifier: "com.app.refresh",
        using: nil
    ) { task in
        self.handleAppRefresh(task: task as! BGAppRefreshTask)
    }

    return true
}

// Schedule refresh
func scheduleAppRefresh() {
    let request = BGAppRefreshTaskRequest(identifier: "com.app.refresh")
    request.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)  // 15 min

    try? BGTaskScheduler.shared.submit(request)
}

// Handle refresh
func handleAppRefresh(task: BGAppRefreshTask) {
    scheduleAppRefresh()  // Schedule next refresh

    let fetchTask = Task {
        do {
            let hasNewData = try await fetchLatestData()
            task.setTaskCompleted(success: hasNewData)
        } catch {
            task.setTaskCompleted(success: false)
        }
    }

    task.expirationHandler = {
        fetchTask.cancel()
    }
}

BGProcessingTask

import BackgroundTasks

// Register
BGTaskScheduler.shared.register(
    forTaskWithIdentifier: "com.app.maintenance",
    using: nil
) { task in
    self.handleMaintenance(task: task as! BGProcessingTask)
}

// Schedule with requirements
func scheduleMaintenance() {
    let request = BGProcessingTaskRequest(identifier: "com.app.maintenance")
    request.requiresNetworkConnectivity = true
    request.requiresExternalPower = true  // Only when charging

    try? BGTaskScheduler.shared.submit(request)
}

// Handle
func handleMaintenance(task: BGProcessingTask) {
    let operation = MaintenanceOperation()

    task.expirationHandler = {
        operation.cancel()
    }

    operation.completionBlock = {
        task.setTaskCompleted(success: !operation.isCancelled)
    }

    OperationQueue.main.addOperation(operation)
}

iOS 26+ BGContinuedProcessingTask

From WWDC25-227: Continue user-initiated tasks with system UI.

import BackgroundTasks

// Info.plist: Add identifier to BGTaskSchedulerPermittedIdentifiers
// "com.app.export" or "com.app.exports.*" for wildcards

// Register handler (can be dynamic, not just at launch)
func setupExportHandler() {
    BGTaskScheduler.shared.register("com.app.export") { task in
        let continuedTask = task as! BGContinuedProcessingTask

        var shouldContinue = true
        continuedTask.expirationHandler = {
            shouldContinue = false
        }

        // Report progress
        continuedTask.progress.totalUnitCount = 100
        continuedTask.progress.completedUnitCount = 0

        // Perform work
        for i in 0..<100 {
            guard shouldContinue else { break }

            performExportStep(i)
            continuedTask.progress.completedUnitCount = Int64(i + 1)
        }

        continuedTask.setTaskCompleted(success: shouldContinue)
    }
}

// Submit request
func startExport() {
    let request = BGContinuedProcessingTaskRequest(
        identifier: "com.app.export",
        title: "Exporting Photos",
        subtitle: "0 of 100 photos"
    )

    // Submission strategy
    request.strategy = .fail  // Fail if can't start immediately
    // or default: queue if can't start

    do {
        try BGTaskScheduler.shared.submit(request)
    } catch {
        // Handle submission failure
        showExportNotAvailable()
    }
}

EMRCA Principles (from WWDC25-227)

Background tasks must be:

PrincipleMeaningImplementation
EfficientLightweight, purpose-drivenDo one thing well
MinimalKeep work to minimumDon't expand scope
ResilientSave progress, handle expirationCheckpoint frequently
CourteousHonor preferencesCheck Low Power Mode
AdaptiveWork with systemDon't fight constraints

Part 6: Display & GPU Efficiency APIs

Dark Mode Support

// Check current appearance
let isDarkMode = traitCollection.userInterfaceStyle == .dark

// React to appearance changes
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
        updateColorsForAppearance()
    }
}

// Use dynamic colors
let dynamicColor = UIColor { traitCollection in
    switch traitCollection.userInterfaceStyle {
    case .dark:
        return UIColor.black  // OLED: True black = pixels off = 0 power
    default:
        return UIColor.white
    }
}

Frame Rate Control with CADisplayLink

From WWDC22-10083:

class AnimationController {
    private var displayLink: CADisplayLink?

    func startAnimation() {
        displayLink = CADisplayLink(target: self, selector: #selector(update))

        // Control frame rate
        displayLink?.preferredFrameRateRange = CAFrameRateRange(
            minimum: 10,   // Minimum acceptable
            maximum: 30,   // Maximum needed
            preferred: 30  // Ideal rate
        )

        displayLink?.add(to: .current, forMode: .default)
    }

    @objc private func update(_ displayLink: CADisplayLink) {
        // Update animation
        updateAnimationFrame()
    }

    func stopAnimation() {
        displayLink?.invalidate()
        displayLink = nil
    }
}

Stop Animations When Not Visible

class AnimatedViewController: UIViewController {
    private var animator: UIViewPropertyAnimator?

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        startAnimations()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        stopAnimations()  // Critical for energy
    }

    private func stopAnimations() {
        animator?.stopAnimation(true)
        animator = nil
    }
}

Part 7: Disk I/O Efficiency APIs

Batch Writes

// BAD: Multiple small writes
for item in items {
    let data = try JSONEncoder().encode(item)
    try data.write(to: fileURL)  // Writes each item separately
}

// GOOD: Single batched write
let allData = try JSONEncoder().encode(items)
try allData.write(to: fileURL)  // One write operation

SQLite WAL Mode

import SQLite3

// Enable Write-Ahead Logging
var db: OpaquePointer?
sqlite3_open(dbPath, &db)

var statement: OpaquePointer?
sqlite3_prepare_v2(db, "PRAGMA journal_mode=WAL", -1, &statement, nil)
sqlite3_step(statement)
sqlite3_finalize(statement)

XCTStorageMetric for Testing

import XCTest

class DiskWriteTests: XCTestCase {
    func testDiskWritePerformance() {
        measure(metrics: [XCTStorageMetric()]) {
            // Code that writes to disk
            saveUserData()
        }
    }
}

Part 8: Low Power Mode & Thermal Response APIs

Low Power Mode Detection

import Foundation

class PowerStateManager {
    private var cancellables = Set<AnyCancellable>()

    init() {
        // Check initial state
        updateForPowerState()

        // Observe changes
        NotificationCenter.default.publisher(
            for: .NSProcessInfoPowerStateDidChange
        )
        .sink { [weak self] _ in
            self?.updateForPowerState()
        }
        .store(in: &cancellables)
    }

    private func updateForPowerState() {
        if ProcessInfo.processInfo.isLowPowerModeEnabled {
            reduceEnergyUsage()
        } else {
            restoreNormalOperation()
        }
    }

    private func reduceEnergyUsage() {
        // Increase timer intervals
        // Reduce animation frame rates
        // Defer network requests
        // Stop location updates if not critical
        // Reduce refresh frequency
    }
}

Thermal State Response

import Foundation

class ThermalManager {
    init() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(thermalStateChanged),
            name: ProcessInfo.thermalStateDidChangeNotification,
            object: nil
        )
    }

    @objc private func thermalStateChanged() {
        switch ProcessInfo.processInfo.thermalState {
        case .nominal:
            // Normal operation
            restoreFullFunctionality()

        case .fair:
            // Slightly elevated, minor reduction
            reduceNonEssentialWork()

        case .serious:
            // Significant reduction needed
            suspendBackgroundTasks()
            reduceAnimationQuality()

        case .critical:
            // Maximum reduction
            minimizeAllActivity()
            showThermalWarningIfAppropriate()

        @unknown default:
            break
        }
    }
}

Part 9: MetricKit Monitoring APIs

Basic Setup

import MetricKit

class MetricsManager: NSObject, MXMetricManagerSubscriber {
    static let shared = MetricsManager()

    func startMonitoring() {
        MXMetricManager.shared.add(self)
    }

    func didReceive(_ payloads: [MXMetricPayload]) {
        for payload in payloads {
            processPayload(payload)
        }
    }

    func didReceive(_ payloads: [MXDiagnosticPayload]) {
        for payload in payloads {
            processDiagnostic(payload)
        }
    }
}

Processing Energy Metrics

func processPayload(_ payload: MXMetricPayload) {
    // CPU metrics
    if let cpu = payload.cpuMetrics {
        let foregroundTime = cpu.cumulativeCPUTime
        let backgroundTime = cpu.cumulativeCPUInstructions
        logMetric("cpu_foreground", value: foregroundTime)
    }

    // Location metrics
    if let location = payload.locationActivityMetrics {
        let backgroundLocationTime = location.cumulativeBackgroundLocationTime
        logMetric("background_location_seconds", value: backgroundLocationTime)
    }

    // Network metrics
    if let network = payload.networkTransferMetrics {
        let cellularUpload = network.cumulativeCellularUpload
        let cellularDownload = network.cumulativeCellularDownload
        let wifiUpload = network.cumulativeWiFiUpload
        let wifiDownload = network.cumulativeWiFiDownload

        logMetric("cellular_upload", value: cellularUpload)
        logMetric("cellular_download", value: cellularDownload)
    }

    // Disk metrics
    if let disk = payload.diskIOMetrics {
        let writes = disk.cumulativeLogicalWrites
        logMetric("disk_writes", value: writes)
    }

    // GPU metrics
    if let gpu = payload.gpuMetrics {
        let gpuTime = gpu.cumulativeGPUTime
        logMetric("gpu_time", value: gpuTime)
    }
}

Xcode Organizer Integration

View field metrics in Xcode:

  1. Window → Organizer
  2. Select your app
  3. Click "Battery Usage" in sidebar
  4. Compare versions, filter by device/OS

Categories shown:

  • Audio
  • Networking
  • Processing (CPU + GPU)
  • Display
  • Bluetooth
  • Location
  • Camera
  • Torch
  • NFC
  • Other

Part 10: Push Notifications APIs

Alert Notifications Setup

From WWDC20-10095:

import UserNotifications

class NotificationManager: NSObject, UNUserNotificationCenterDelegate {

    func setup() {
        UNUserNotificationCenter.current().delegate = self
        UIApplication.shared.registerForRemoteNotifications()
    }

    func requestPermission() {
        UNUserNotificationCenter.current().requestAuthorization(
            options: [.alert, .sound, .badge]
        ) { granted, error in
            print("Permission granted: \(granted)")
        }
    }
}

// AppDelegate
func application(
    _ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
    let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
    sendTokenToServer(token)
}

func application(
    _ application: UIApplication,
    didFailToRegisterForRemoteNotificationsWithError error: Error
) {
    print("Failed to register: \(error)")
}

Background Push Notifications

// Handle background notification
func application(
    _ application: UIApplication,
    didReceiveRemoteNotification userInfo: [AnyHashable: Any],
    fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
    // Check for content-available flag
    guard let aps = userInfo["aps"] as? [String: Any],
          aps["content-available"] as? Int == 1 else {
        completionHandler(.noData)
        return
    }

    Task {
        do {
            let hasNewData = try await fetchLatestContent()
            completionHandler(hasNewData ? .newData : .noData)
        } catch {
            completionHandler(.failed)
        }
    }
}

Server Payload Examples

// Alert notification (user-visible)
{
    "aps": {
        "alert": {
            "title": "New Message",
            "body": "You have a new message from John"
        },
        "sound": "default",
        "badge": 1
    },
    "message_id": "12345"
}

// Background notification (silent)
{
    "aps": {
        "content-available": 1
    },
    "update_type": "new_content"
}

Push Priority Headers

PriorityHeaderUse Case
High (10)apns-priority: 10Time-sensitive alerts
Low (5)apns-priority: 5Deferrable updates

Energy tip: Use priority 5 for all non-urgent notifications. System batches low-priority pushes for energy efficiency.


Troubleshooting Checklist

Issue: App at Top of Battery Settings

  • Run Power Profiler to identify dominant subsystem
  • Check for timers without tolerance
  • Check for polling patterns
  • Check for continuous location
  • Check for background audio session
  • Verify BGTasks complete promptly

Issue: Device Gets Hot

  • Check GPU Power Impact for sustained high values
  • Look for continuous animations
  • Check for blur effects over dynamic content
  • Verify Metal frame limiting
  • Check CPU for tight loops

Issue: Background Battery Drain

  • Audit background modes in Info.plist
  • Verify audio session deactivated when not playing
  • Check location accuracy and stop calls
  • Verify beginBackgroundTask calls end promptly
  • Review BGTask scheduling

Issue: High Cellular Usage

  • Check allowsExpensiveNetworkAccess setting
  • Verify discretionary flag on background downloads
  • Look for polling patterns
  • Check for large automatic downloads

Expert Review Checklist

Timers (10 items)

  • Tolerance ≥10% on all timers
  • Timers invalidated in deinit
  • No timers running when app backgrounded
  • Using Combine Timer where possible
  • No sub-second intervals without justification
  • Event-driven alternatives considered
  • No synchronization via timer polling
  • Timer invalidated before creating new one
  • Repeating timers have clear stop condition
  • Background timer usage justified

Network (10 items)

  • waitsForConnectivity = true
  • allowsExpensiveNetworkAccess appropriate
  • allowsConstrainedNetworkAccess appropriate
  • Non-urgent downloads use discretionary
  • Push notifications instead of polling
  • Requests batched where possible
  • Payloads compressed
  • Background URLSession for large transfers
  • Retry logic has exponential backoff
  • Connection reuse via single URLSession

Location (10 items)

  • Accuracy appropriate for use case
  • distanceFilter set
  • Updates stopped when not needed
  • pausesLocationUpdatesAutomatically = true
  • Background location only if essential
  • Significant-change for background
  • CLMonitor for region monitoring
  • Location permission matches actual need
  • Stationary detection utilized
  • Location icon explained to users

Background Execution (10 items)

  • endBackgroundTask called promptly
  • Expiration handlers implemented
  • BGTasks use requiresExternalPower when possible
  • EMRCA principles followed
  • Background modes limited to needed
  • Audio session deactivated when idle
  • Progress saved incrementally
  • Tasks complete within time limits
  • Low Power Mode checked before heavy work
  • Thermal state monitored

Display/GPU (10 items)

  • Dark Mode supported
  • Animations stop when view hidden
  • Frame rates appropriate for content
  • Secondary animations lower priority
  • Blur effects minimized
  • Metal has frame limiting
  • Brightness-independent design
  • No hidden animations consuming power
  • GPU-intensive work has visibility checks
  • ProMotion considered in frame rate decisions

WWDC Session Reference

SessionYearTopic
2262025Power Profiler workflow, on-device tracing
2272025BGContinuedProcessingTask, EMRCA principles
100832022Dark Mode, frame rates, deferral
100952020Push notifications primer
7072019Background execution advances
4172019Battery life, MetricKit

Last Updated: 2025-12-26 Platforms: iOS 26+, iPadOS 26+

平台分布

Claude Code

27.72%
按下载量换算380

Codex

21.8%
按下载量换算299

OpenCode

16.44%
按下载量换算225

Antigravity

11.24%
按下载量换算154

Cursor

8.38%
按下载量换算115

windsurf

3.61%
按下载量换算49

安全审计

Gen Agent Trust Hub

未通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。

继续浏览同类 Skills