프로그래밍 언어/Flutter

[Flutter] iOS 파일 다운로드(파일 앱 저장, 공유하기 팝업창 생성)

이로률 2025. 3. 1. 19:23

1. 기존 코드

안드로이드는 추가해놓고 iOS는 파일 다운로드 기능을 추가하지 않았다..

Future<void> _startFileDownload(
    String url, String fileName, String accessToken) async {
  try {
    final directory = await getApplicationDocumentsDirectory();
    String saveDirPath = directory.path;

    if (Platform.isAndroid == true) {
      saveDirPath = await ExternalPath.getExternalStoragePublicDirectory(
          ExternalPath.DIRECTORY_DOWNLOADS);
    }

    print('다운로드 URL: $url, 파일 저장 경로: ${saveDirPath}');

    // 이슈 안드로이드 9버전에서 동일한 이름의 파일을 다운받으려하면 파일 다운로드에 실패함

    await FlutterDownloader.enqueue(
      url: url,
      fileName: fileName,
      headers: {
        'User-Agent': 'MOBI',
        'Authorization': 'bearer $accessToken',
      }, 
      savedDir: saveDirPath,
      showNotification: true, 
      openFileFromNotification: true,
      saveInPublicStorage: true,
    );
  } on CmimException catch (e, s) {
    print('CmimException fileDownload Stack trace: $s');
  } catch (e, s) {
    print('Exception fileDownload Stack trace: $s');

    alert(title: '오류', msg: '파일 다운로드 중 오류가 발생하였습니다.');
  }
}

2. 변경코드

2-1) 다운로드 시 디바이스 내의 "파일" 앱에 파일이 저장되도록 구현

Future<void> _startFileDownload(
    String url, String fileName, String accessToken) async {
  try {
    final directory = await getApplicationDocumentsDirectory();
    String saveDirPath = directory.path;

    if (Platform.isAndroid == true) {
      saveDirPath = await ExternalPath.getExternalStoragePublicDirectory(
          ExternalPath.DIRECTORY_DOWNLOADS);
    } 
    //여기에 iOS일 경우의 조건문을 추가해준다
    else if (Platform.isIOS == true) { 
      saveDirPath = "${directory.path}/";
    }

    print('다운로드 URL: $url, 파일 저장 경로: ${saveDirPath}');

    await FlutterDownloader.enqueue(
      url: url,
      fileName: fileName,
      headers: {
        'User-Agent': 'MOBI',
        'Authorization': 'bearer $accessToken',
      }, 
      savedDir: saveDirPath,
      showNotification: true, 
      openFileFromNotification: true, 
      saveInPublicStorage: true,
    );
  } on CmimException catch (e, s) {
    print('CmimException fileDownload Stack trace: $s');
  } catch (e, s) {
    print('Exception fileDownload Stack trace: $s');
    alert(title: '오류', msg: '파일 다운로드 중 오류가 발생하였습니다.');
  }
}

2-2) iOS는 파일 공유하기 팝업창 표출되도록 구현

  • 안드로이드는 그대로 "파일" 앱에 저장
  • iOS만 공유하기 팝업창 표출되도록 구현한 방법이다.

기존 코드와 다르게 조건문 안에서 코드를 구현하였다.

Future<void> _startFileDownload(
    String url, String fileName, String accessToken) async {
  try {
    Directory directory = await getApplicationDocumentsDirectory();
    // String saveDirPath = directory.path;

    //1. 안드로이드 
    if (Platform.isAndroid == true) {
      String saveDirPath = await ExternalPath.getExternalStoragePublicDirectory(
          ExternalPath.DIRECTORY_DOWNLOADS);

      //이 부분부터 다름
      //안드로이드는 파일 앱에 다운로드
      String newFileName = await getUniqueFileName(saveDirPath, fileName);
      await FlutterDownloader.enqueue(
        url: url,
        fileName: newFileName,
        headers: {
          'User-Agent': 'MOBI',
          'Authorization': 'bearer $accessToken',
        },
        savedDir: saveDirPath,
        showNotification: true, 
        openFileFromNotification: true, 
        saveInPublicStorage: true,
      );
      util_dialog.toast(msg: '파일 다운로드가 완료되었습니다.');
    } 
    //2. iOS
    else if (Platform.isIOS == true) {

      final response = await http.get(
        Uri.parse(url),
        headers: {
          'User-Agent': 'MOBI',
          'Authorization': 'bearer $accessToken',
        }
      );

      //파일 다운로드가 완료되면 임시로 파일을 저장한 후, 공유하기를 통해 작업이 이루어지면 임시파일 삭제하는 방식임
      if(response.statusCode == 200) {
        final tempDir = await getTemporaryDirectory();
        final filePath = path.join(tempDir.path, fileName);
        final file = File(filePath);
        await file.writeAsBytes(response.bodyBytes);

        await Share.shareXFiles([XFile(filePath)]); //파일 공유하기 팝업창 생성

        await file.delete();

      } else {
        util_dialog.toast(msg: '파일 다운로드 중 오류가 발생하였습니다.');
      }
    }


  } on CmimException catch (e, s) {
    print('CmimException fileDownload Stack trace: $s');
  } catch (e) {
    print('$e');
    util_dialog.toast(msg: '파일 다운로드 중 오류가 발생하였습니다.');
  }
}