---
id: native-battery-network-profiling
title: Battery / Network Profiling — 사용량 줄이기
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [native, battery, network, profiling, vibe-coding]
tech_stack: { language: "Swift / Kotlin", applicable_to: ["iOS", "Android"] }
applied_in: []
aliases: [battery drain, network usage, doze, background fetch, WorkManager]
---

# Battery / Network Profiling

> 모바일 앱 = 배터리 + 데이터 모두 한정. 하루 5% 이상 소모면 사용자 삭제. **wake lock / 백그라운드 polling / GPS / sync** 4종이 주범. 측정 → 줄이기.

## 📖 핵심 개념
- Doze (Android): screen off + 정지 → background 제한.
- Background app refresh (iOS): OS 가 사용 패턴 학습 → 자유로 결정.
- Wake lock: CPU 끄기 막음. 마지막 수단.
- Network bytes: cellular/wifi 별 측정.

## 💻 코드 패턴

### Android — Battery Historian
```bash
adb bugreport bugreport.zip
# https://bathist.ef.lc/ 에 업로드 또는 로컬 docker
docker run -p 9999:9999 bhaavan/battery-historian
```

### iOS — Energy Log
```
Xcode → Open Developer Tool → Instruments → Energy Log
# 또는 디바이스: Settings → Privacy → Analytics → Logs
```

### Network — 사용량 측정
```kotlin
// Android: TrafficStats / NetworkStatsManager
val rx = TrafficStats.getUidRxBytes(android.os.Process.myUid())
val tx = TrafficStats.getUidTxBytes(android.os.Process.myUid())
```

```swift
// iOS: URLSessionTaskMetrics 로 본인 트래픽 측정
class M: NSObject, URLSessionTaskDelegate {
    func urlSession(_ s: URLSession, task: URLSessionTask, didFinishCollecting m: URLSessionTaskMetrics) {
        for tx in m.transactionMetrics {
            print("\(tx.request.url!): \(tx.countOfRequestBodyBytesSent) tx, \(tx.countOfResponseBodyBytesReceived) rx")
        }
    }
}
```

### 백그라운드 작업 — WorkManager (Android)
```kotlin
val req = PeriodicWorkRequestBuilder<SyncWorker>(15, TimeUnit.MINUTES)
    .setConstraints(
        Constraints.Builder()
            .setRequiredNetworkType(NetworkType.UNMETERED) // wifi 만
            .setRequiresCharging(false)
            .setRequiresBatteryNotLow(true)
            .build()
    )
    .build()

WorkManager.getInstance(ctx).enqueueUniquePeriodicWork("sync", KEEP, req)
```

### iOS — BGTaskScheduler
```swift
BGTaskScheduler.shared.register(
    forTaskWithIdentifier: "com.app.refresh",
    using: nil
) { task in handleRefresh(task as! BGAppRefreshTask) }

let r = BGAppRefreshTaskRequest(identifier: "com.app.refresh")
r.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)
try? BGTaskScheduler.shared.submit(r)
```

### Network 압축 / batch
```kotlin
// OkHttp 자동 gzip
// 또는 brotli interceptor 추가

// Batch: 5초 마다 모아서 한 번 POST 보다 좋은 게 있나? 응 — 즉시 + jitter 분산
```

### 위치 (가장 비싼 자원)
```kotlin
val req = LocationRequest.Builder(BALANCED_POWER_ACCURACY, 60_000) // 1분 + 협력적
    .setMinUpdateDistanceMeters(50f) // 50m 변화만
    .build()
```

```swift
let m = CLLocationManager()
m.desiredAccuracy = kCLLocationAccuracyHundredMeters
m.distanceFilter = 100
// significant change service
m.startMonitoringSignificantLocationChanges()
```

## 🤔 의사결정 기준
| 작업 | 권장 |
|---|---|
| Background sync | WorkManager (Android) / BGTaskScheduler (iOS) |
| Push 보다 polling | 항상 push 가 우월 (FCM/APNs) |
| 위치 추적 | Significant change / geofence (지속 추적 X) |
| 큰 다운로드 | Background URLSession / WorkManager unmetered |
| Wake lock | 단기 + 명시적 release |

## ❌ 안티패턴
- **Background 5초 polling**: 배터리 폭발.
- **GPS continuous high accuracy**: 분당 5%.
- **Wake lock 잡고 release 안 함**: 영구 켜짐.
- **Cellular 에서 큰 동기화**: 데이터 폭발. unmetered 조건.
- **Image 원본 다운로드**: thumbnail / WebP / AVIF.
- **WebSocket 평생 유지**: foreground 만, background 는 push.
- **JSON 비압축**: gzip + minify.

## 🤖 LLM 활용 힌트
- WorkManager / BGTaskScheduler 항상 사용.
- 위치는 significant / geofence.
- 측정 → push, batch, 압축 3종.

## 🔗 관련 문서
- [[Native_Memory_Profiling]]
- [[Native_Perf_Tracing_Systrace]]
