[Flutter] Wakelock Plus 패키지

hyenni·2025년 7월 10일
0

Flutter

목록 보기
5/5
post-thumbnail

Wakelock Plus란?

Wakelock Plus는 Flutter 앱에서 디바이스의 화면이 자동으로 꺼지는 것을 방지하는 패키지입니다. 특히 동영상 재생, 프레젠테이션, 게임, 운동 앱 등에서 화면이 계속 켜져있어야 하는 상황에 필수적입니다.

패키지 정보

  • 공식 패키지: wakelock_plus
  • 플랫폼 지원: Android, iOS, macOS, Windows, Linux, Web
  • 기존 wakelock 패키지의 후속작 (더 안정적이고 많은 플랫폼 지원)

설치하기

pubspec.yaml에 의존성 추가

dependencies:
  flutter:
    sdk: flutter
  wakelock_plus: ^1.2.8

패키지 설치

flutter pub get

import 추가

import 'package:wakelock_plus/wakelock_plus.dart';

기본 사용법

1. Wakelock 활성화/비활성화

// 화면 꺼짐 방지 활성화
await WakelockPlus.enable();

// 화면 꺼짐 방지 비활성화
await WakelockPlus.disable();

2. 현재 상태 확인

// 현재 wakelock이 활성화되어 있는지 확인
bool isEnabled = await WakelockPlus.enabled;
print('Wakelock 상태: $isEnabled');

3. 토글 기능

// 현재 상태를 반전시키기
bool currentState = await WakelockPlus.enabled;
if (currentState) {
  await WakelockPlus.disable();
} else {
  await WakelockPlus.enable();
}

실제 활용 사례

1. 상태 기반 Wakelock 관리

enum AppState { idle, working, gaming, presenting }

class WakelockManager {
  static AppState _currentState = AppState.idle;
  
  static Future<void> updateState(AppState newState) async {
    _currentState = newState;
    
    switch (newState) {
      case AppState.idle:
        await WakelockPlus.disable();
        break;
      case AppState.working:
      case AppState.gaming:
      case AppState.presenting:
        await WakelockPlus.enable();
        break;
    }
  }
  
  static AppState get currentState => _currentState;
  static Future<bool> get isWakelockEnabled => WakelockPlus.enabled;
}

2. 자동 타이머 기반 Wakelock

class TimedWakelock {
  static Timer? _timer;
  
  static Future<void> enableForDuration(Duration duration) async {
    await WakelockPlus.enable();
    
    _timer?.cancel();
    _timer = Timer(duration, () async {
      await WakelockPlus.disable();
      print('Wakelock이 자동으로 해제되었습니다.');
    });
  }
  
  static Future<void> cancel() async {
    _timer?.cancel();
    await WakelockPlus.disable();
  }
}

// 사용 예시
TimedWakelock.enableForDuration(Duration(minutes: 30)); // 30분 후 자동 해제

3. 조건부 Wakelock

class ConditionalWakelock {
  static bool _userPreference = true;
  static bool _batteryOptimized = false;
  
  static Future<void> enableIfAllowed() async {
    if (_userPreference && !_batteryOptimized) {
      await WakelockPlus.enable();
    }
  }
  
  static void setUserPreference(bool enabled) {
    _userPreference = enabled;
    if (!enabled) {
      WakelockPlus.disable();
    }
  }
  
  static void setBatteryOptimization(bool optimized) {
    _batteryOptimized = optimized;
    if (optimized) {
      WakelockPlus.disable();
    }
  }
}

실용적인 UI 컴포넌트

Wakelock Toggle Widget

class WakelockToggleWidget extends StatefulWidget {
  final String title;
  final VoidCallback? onChanged;
  
  const WakelockToggleWidget({
    Key? key,
    this.title = 'Keep Screen On',
    this.onChanged,
  }) : super(key: key);

  
  _WakelockToggleWidgetState createState() => _WakelockToggleWidgetState();
}

class _WakelockToggleWidgetState extends State<WakelockToggleWidget> {
  bool _isEnabled = false;

  
  void initState() {
    super.initState();
    _checkWakelockStatus();
  }

  Future<void> _checkWakelockStatus() async {
    bool enabled = await WakelockPlus.enabled;
    setState(() => _isEnabled = enabled);
  }

  Future<void> _toggleWakelock() async {
    if (_isEnabled) {
      await WakelockPlus.disable();
    } else {
      await WakelockPlus.enable();
    }
    
    bool newState = await WakelockPlus.enabled;
    setState(() => _isEnabled = newState);
    
    widget.onChanged?.call();
  }

  
  Widget build(BuildContext context) {
    return Card(
      child: ListTile(
        leading: Icon(
          _isEnabled ? Icons.screen_lock_portrait : Icons.screen_lock_landscape,
          color: _isEnabled ? Colors.green : Colors.grey,
        ),
        title: Text(widget.title),
        subtitle: Text(_isEnabled ? '화면이 꺼지지 않습니다' : '화면이 자동으로 꺼집니다'),
        trailing: Switch(
          value: _isEnabled,
          onChanged: (_) => _toggleWakelock(),
          activeColor: Colors.green,
        ),
        onTap: _toggleWakelock,
      ),
    );
  }
}

주의사항

1. 배터리 소모 주의

// ❌ 잘못된 사용
class BadExample extends StatefulWidget {
  
  void initState() {
    super.initState();
    WakelockPlus.enable(); // 항상 켜둠 - 배터리 소모
  }
}

// ✅ 올바른 사용
class GoodExample extends StatefulWidget {
  
  void initState() {
    super.initState();
    // 필요할 때만 활성화
  }
  
  void startImportantTask() {
    WakelockPlus.enable(); // 작업 시작 시에만
  }
  
  void finishImportantTask() {
    WakelockPlus.disable(); // 작업 완료 시 해제
  }
}

2. 앱 생명주기 관리

class ProperLifecycleManagement extends StatefulWidget with WidgetsBindingObserver {
  
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.paused:
        // 앱이 백그라운드로 갈 때 해제
        WakelockPlus.disable();
        break;
      case AppLifecycleState.resumed:
        // 필요한 경우에만 다시 활성화
        if (shouldKeepScreenOn()) {
          WakelockPlus.enable();
        }
        break;
    }
  }

  
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    WakelockPlus.disable(); // 반드시 해제
    super.dispose();
  }
}

3. 사용자 설정 고려

class UserFriendlyWakelock {
  static const String _prefKey = 'wakelock_enabled';
  
  static Future<bool> getUserPreference() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    return prefs.getBool(_prefKey) ?? true;
  }
  
  static Future<void> setUserPreference(bool enabled) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setBool(_prefKey, enabled);
  }
  
  static Future<void> enableWithUserConsent() async {
    bool userAllowed = await getUserPreference();
    if (userAllowed) {
      await WakelockPlus.enable();
    }
  }
}

디버깅 및 테스팅

1. Wakelock 상태 모니터링

class WakelockDebugger {
  static void startMonitoring() {
    Timer.periodic(Duration(seconds: 5), (timer) async {
      bool isEnabled = await WakelockPlus.enabled;
      print('Wakelock 상태: ${isEnabled ? "활성화" : "비활성화"}');
    });
  }
  
  static Future<void> logStateChange(String action) async {
    bool stateBefore = await WakelockPlus.enabled;
    print('[$action] 이전 상태: $stateBefore');
    
    // 액션 수행 후
    await Future.delayed(Duration(milliseconds: 100));
    
    bool stateAfter = await WakelockPlus.enabled;
    print('[$action] 이후 상태: $stateAfter');
  }
}

2. 테스트 코드 예시

void main() {
  group('Wakelock Tests', () {
    test('should enable wakelock', () async {
      await WakelockPlus.enable();
      bool isEnabled = await WakelockPlus.enabled;
      expect(isEnabled, true);
    });

    test('should disable wakelock', () async {
      await WakelockPlus.disable();
      bool isEnabled = await WakelockPlus.enabled;
      expect(isEnabled, false);
    });

    test('should toggle wakelock', () async {
      bool initialState = await WakelockPlus.enabled;
      
      if (initialState) {
        await WakelockPlus.disable();
      } else {
        await WakelockPlus.enable();
      }
      
      bool finalState = await WakelockPlus.enabled;
      expect(finalState, !initialState);
    });
  });
}

플랫폼별 고려사항

Android

  • 권한 필요 없음: 별도의 권한 설정 불필요
  • 배터리 최적화: 일부 제조사에서 배터리 최적화로 인해 제한될 수 있음
  • 도즈 모드: Android 6.0+ 도즈 모드에서도 정상 작동

iOS

  • 백그라운드 제한: 앱이 백그라운드로 가면 자동으로 해제됨
  • 저전력 모드: 저전력 모드에서는 효과가 제한될 수 있음

마무리

Wakelock Plus는 사용자 경험을 크게 향상시킬 수 있는 강력한 도구입니다. 하지만 배터리 소모와 사용자 편의성 사이의 균형을 잘 맞춰야 합니다.

핵심 포인트

  1. 필요할 때만 사용: 동영상, 게임, 프레젠테이션 등 반드시 필요한 상황에서만
  2. 자동 해제: 작업 완료 시 또는 앱 종료 시 반드시 해제
  3. 사용자 선택권: 사용자가 on/off 할 수 있는 옵션 제공
  4. 생명주기 관리: 앱의 생명주기에 맞춰 적절히 관리

참고 자료

profile
안녕하세요

0개의 댓글