질문 정리

PDF 파일 다운로드를 사용자에게 알리기

five2week 2024. 5. 29. 20:09

문제 상황

파일 스트림을 통해서 pdf를 다운로드하는 과정에서 사용자에게 다운로드 상태나 메세지가 보이지 않습니다. 따라서 사용자는 다운로드의 진행 상태를 알 수 없어 해당 기능을 사용하는데 불편함을 느낄 수 있습니다.

따라서 pdf를 다운로드 하면 다운로드에 대한 정보가 사용자에게 제공되도록 개발을 하려고합니다.

생각한 방법

  1. downloadManager 사용
    1. 적합한 상황
      • 주로 웹에서 직접 파일을 다운로드할 때 사용됩니다. 다운로드할 리소스는 웹상의 URI 형태로 제공되어야 하며, 이 URI는 HTTP 또는 HTTPS 프로토콜을 사용해 접근 가능한 파일이어야 합니다.
      • 대용량 파일 다운로드: 대용량 파일이나 긴 다운로드 시간이 필요한 파일을 다운로드할 때 유용합니다.
      • 앱 사용 중이 아닐 때도 다운로드 필요: 앱이 백그라운드에서 실행되거나 사용자가 다른 앱을 사용 중일 때도 다운로드가 계속 진행되어야 하는 경우.
    2. 장점
      • 사용 편의성: API 사용이 간단하며 다운로드 관리가 용이합니다.
      • 안정성과 효율성: 시스템에 의해 관리되므로 네트워크 상태 변화에 따른 자동 재개 등의 기능이 내장되어 있습니다.
    3. 단점
      • 제한된 커스터마이제이션: UI나 알림 스타일 변경이 제한적입니다.
      • 권한 요구: 사용자에게 파일과 네트워크 접근 권한을 요구해야 합니다.
  2. NotificationManager 사용
    1. 적합한 상황
      • 로컬 파일, 네트워크 상의 URI, 또는 앱 내부에서 생성된 데이터 등 다운로드할 대상의 형태에 구애받지 않습니다. 단, 개발자가 구현해야합니다.
      • 다양한 알림의 필요성: 다운로드뿐만 아니라 다른 종류의 작업 진행 상태도 사용자에게 알리고 싶을 때 적합합니다.
      • 고도의 사용자 경험 제공: 알림의 모양, 소리, 진동 등을 사용자의 기대에 맞춰 상세하게 조정해야 할 때.
    2. 장점
      • 높은 커스터마이징: 사용자의 요구에 따라 다양하게 알림을 구성할 수 있습니다.
      • 직접적인 사용자 인터랙션: 알림을 통해 사용자가 다운로드를 제어할 수 있습니다.
    3. 단점
      • 개발 복잡성: 알림 관리, 상태 업데이트 등 모든 부분을 개발자가 직접 처리해야 합니다.
      • 배터리와 자원 사용: 자주 업데이트되는 알림은 배터리와 자원 소모가 클 수 있습니다.

1. DownloadManager 사용

DownloadManager는 안드로이드 시스템이 제공하는 API로, 네트워크를 통한 파일 다운로드를 관리하고 사용자에게 상태 바 알림을 통해 다운로드 진행 상태를 보여줍니다. 이 방법을 사용하면 다운로드 중, 완료, 실패 등의 상태를 자동으로 사용자에게 알릴 수 있습니다.

fun downloadFile(context: Context, url: String, title: String, description: String) {
    val request = DownloadManager.Request(Uri.parse(url))
        .setTitle(title)
        .setDescription(description)
        .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
        .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "filename.pdf")

    val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    val downloadId = downloadManager.enqueue(request)

    val query = DownloadManager.Query().setFilterById(downloadId)
    val cursor = downloadManager.query(query)
    if (cursor != null && cursor.moveToFirst()) {
        val columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
        if (columnIndex != -1) {
            val status = cursor.getInt(columnIndex)
            when (status) {
                DownloadManager.STATUS_RUNNING -> {
                    // 다운로드 중 처리
                }
                DownloadManager.STATUS_SUCCESSFUL -> {
                    // 다운로드 완료 처리
                }
                DownloadManager.STATUS_FAILED -> {
                    // 다운로드 실패 처리
                }
            }
        } else {
            LogUtils.e("DownloadManager", "COLUMN_STATUS not found in cursor")
        }
    } else {
        LogUtils.e("DownloadManager", "Cursor is null or empty")
    }
    cursor?.close()
}

2. 사용자 정의 알림 사용

파일 다운로드를 직접 관리하는 경우, NotificationManager를 사용하여 직접 사용자에게 다운로드 진행 상태를 알릴 수 있습니다. 이를 통해 다운로드 진행률 표시 막대를 포함하는 사용자 정의 알림을 만들 수 있습니다.

private fun showDownloadNotification(
    context: Context,
    file: File,
    progress: Int,
) {
    val channelId = "download_channel"
    val notificationManager =
        context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    val importance = NotificationManager.IMPORTANCE_DEFAULT
    val channel = NotificationChannel(channelId, "Downloads", importance)
    notificationManager.createNotificationChannel(channel)

    val contentUri =
        FileProvider.getUriForFile(context, "${context.packageName}.provider", file)

    val intent =
        Intent(Intent.ACTION_VIEW).apply {
            setDataAndType(contentUri, "application/pdf")
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
        }

    val pendingIntent =
        PendingIntent.getActivity(
            context,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
        )

    val notificationBuilder =
        NotificationCompat.Builder(context, channelId).setContentTitle("Analysis PDF Download")
            .setSmallIcon(android.R.drawable.stat_sys_download)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT).setOngoing(progress < 100)
            .setProgress(100, progress, false).setAutoCancel(true)
            .setContentIntent(pendingIntent)

    if (progress == 0 || progress == 50) {
        notificationBuilder.setContentText("Download in progress: $progress%")
        notificationManager.notify(1, notificationBuilder.build())
    } else if (progress == 100) {
        notificationBuilder.setContentText("Download complete").setProgress(0, 0, false)
            .setOngoing(false)
            .setSmallIcon(android.R.drawable.stat_sys_download_done)
        notificationManager.notify(1, notificationBuilder.build())
    }
}

저는 서버에서 제공해주는 데이터의 형태가 uri가 아닌 file의 형태였기 때문에 2번째 방법을 사용해서 처리했습니다.

 

결론적으로, 다루는 리소스의 형태는 각 방법의 사용 및 구현에 큰 영향을 미치며, 개발 과정에서 이를 고려해 선택해야 합니다. DownloadManager는 웹 기반의 파일 다운로드에 최적화된 서비스를 제공하며, NotificationManager는 더 넓은 범위의 사용자 정의 기능과 함께 다양한 형태의 데이터 처리가 가능합니다.