Flutter violation when deploy iOS (WidgetsBindingObserver, life-cycle)

강정우·2023년 10월 31일
0

Flutter&Dart

목록 보기
78/82

Guideline 5.1.2 - Legal - Privacy - Data Use and Sharing

  • 대충 보면 iOS 14.5 이상 버전에서는 AppTrackingTransparency 프레임웤을 추가하라고 나와있다.

  • 요즘 어플깔면 항상 보는 그거다. 여러 코드 중 첫번째 코드만 사용해도 좋고
await AppTrackingTransparency.requestTrackingAuthorization();
  • andoird 환경에서 사용자에게 더 자세한 요구사항을 보여주려면 두번째 코드블럭도 추가하는 것이 좋다.
String _authStatus = 'Unknown';

  @override
  void initState() {
    super.initState();

    // It is safer to call native code using addPostFrameCallback after the widget has been fully built and initialized.
    // Directly calling native code from initState may result in errors due to the widget tree not being fully built at that point.    
    WidgetsFlutterBinding.ensureInitialized().addPostFrameCallback((_) => initPlugin());

  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlugin() async {
    final TrackingStatus status =
        await AppTrackingTransparency.trackingAuthorizationStatus;
    setState(() => _authStatus = '$status');
    // If the system can show an authorization request dialog
    if (status == TrackingStatus.notDetermined) {
      // Show a custom explainer dialog before the system dialog
      await showCustomTrackingDialog(context);
      // Wait for dialog popping animation
      await Future.delayed(const Duration(milliseconds: 200));
      // Request system's tracking authorization dialog
      final TrackingStatus status =
          await AppTrackingTransparency.requestTrackingAuthorization();
      setState(() => _authStatus = '$status');
    }

    final uuid = await AppTrackingTransparency.getAdvertisingIdentifier();
    print("UUID: $uuid");
  }
  • 그리고 광고 식별자를 추가하기위해 uuid를 추가해도 된다.
final uuid = await AppTrackingTransparency.getAdvertisingIdentifier();
  • 위 코드로 request permission을 하면 된다. 그리고 아래 2줄을 추가하여 <string>부분을 한글로 바꿔도 된다.
<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>

Guideline 5.1.5 - Legal - Privacy - Location Services

  • 위치 정보 동의에 not allow를 눌러도 app fully funtional 하도록 하라고 나와있는데 물론 없이도 사용가능하지만 나는 뭔가 navigation 처럼 동작시키고자 설정으로 바로 보내주고 설정에서 ok를 누르면 앱을 다시 실행시키는 코드를 작성하고 싶었다.

  • 처음에는 state를 이용하려 했으나 저거 하나 하자고 라이브러리를 설치하는 것이 아까워 조금 찾아보니 옵저버 패턴과
    flutter life cycle을 이용하여 해결 할 수 있었다.

  • 우선의 기존에 있었던 checkPermission이라는 코드를 최대한 살려보고자 했다.
Future checkPermission() async {
  final isLocationEnabled = await Geolocator.isLocationServiceEnabled();
  if (!isLocationEnabled) {
    return '위치 서비스를 활성화 해주세요.';
  }
  LocationPermission checkPermission = await Geolocator.checkPermission();
  if (checkPermission == LocationPermission.denied) {
    checkPermission = await Geolocator.requestPermission();
    if (checkPermission == LocationPermission.denied) {
      return '위치 권한을 허가해주세요.';
    }
  }
  if (checkPermission == LocationPermission.deniedForever) {
    return '앱의 위치 권한을 세팅에서 허가해주세요.';
  }
  return '위치 권한이 허가되었습니다.';
}

WidgetsBindingObserver

  • 우선 옵저버 패턴에 대해서 알아봐야하는데 옵저버 패턴(Observer Pattern)이란?
    옵저버 패턴은 객체의 상태가 변하면 이를 관찰하는 다른 객체에게 이를 알리는 설계 패턴이다.
    이를 통해 한 객체의 상태가 변하면 이를 의존하는 다른 객체들이 이 변화를 자동으로 감지하여 반응할 수 있다.

  • 예를 들어, Flutter에서 WidgetsBindingObserver는 앱의 생명주기 상태 변화를 감지하는 역할을 한다. WidgetsBindingObserver를 클래스에 추가하면 didChangeAppLifecycleState와 같은 메소드를 오버라이드하여 앱의 생명주기 상태 변화를 감지하고 이에 따른 동작을 정의할 수 있다.

class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
  late WebViewController webViewController;
  String? _token;

  // initState 메소드에 WidgetsBinding.instance.addObserver 추가
  @override
  void initState() {
    super.initState();
    _token = widget.token;
    WidgetsBinding.instance!.addObserver(this);
    ...
  }
    
  // dispose 메소드에 WidgetsBinding.instance.removeObserver 추가
  @override
  void dispose() {
    WidgetsBinding.instance!.removeObserver(this);
    super.dispose();
  }

  // 앱 생명주기 상태 변화 감지
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      setState(() {});
    }
  }
  • 즉, 위 코드를 해석하자면 앱 설정 변경 후 다시 앱으로 돌아올 때 위치 권한 체크를 다시 수행하도록 설정한 것이다.
    Flutter의 WidgetsBindingObserver를 사용하여 앱의 생명주기 상태 변화를 감지하고, 앱이 활성 상태로 전환될 때마다 위치 권한 체크를 수행하도록 하였다.

life-cycle

  • 생명주기(Lifecycle)란?
    생명주기는 앱이나 앱의 각 화면이 생성되고 소멸될 때까지의 과정을 의미한다. 대부분의 UI 프레임워크나 라이브러리는 컴포넌트의 생성, 업데이트, 소멸 등의 단계를 가지고 있으며, 이런 단계를 생명주기 메소드라고 부른다.
    이 메소드들은 프레임워크나 라이브러리에서 자동으로 호출되며, 우리는 이 메소드를 오버라이드하여 각 단계에서 수행할 작업을 정의할 수 있다.
    Flutter에서는 StatefulWidget의 생명주기 메소드로 createState, initState, didChangeDependencies, build, didUpdateWidget, deactivate, dispose 등이 있다.
    이 중에서 initState는 위젯이 생성될 때 한 번만 호출되며, dispose는 위젯이 소멸될 때 한 번만 호출된다. didChangeAppLifecycleState는 앱의 상태가 변화했을 때 호출되는 메소드로, WidgetsBindingObserver를 통해 사용할 수 있습니다.

  • 따라서 위 코드는 WidgetsBindingObserver를 통해 앱의 생명주기 상태를 감지하고, 앱이 활성 상태로 전환될 때마다 화면을 갱신하도록 하였다.
    이를 통해 사용자가 앱 설정을 변경한 후 앱으로 돌아왔을 때 변경된 설정에 따라 화면이 갱신될 수 있다.

결과

profile
智(지)! 德(덕)! 體(체)!

0개의 댓글