【正社員】還元率83%【フリーランス】マージン一律5万円で案件をご紹介させていただきます。 詳細はこちら

【Android】<Kotlin>OkHttpを使用して、ファイルをダウンロードし端末のフォルダに保存する実装方法を徹底解説!

【Android】<Kotlin>OkHttpを使用して、ファイルをダウンロードし端末のフォルダに保存する実装方法を徹底解説!
すだ

みなさまこんにちは〜!
メモリアインクのすだです。

本日は、
KotlinのOkHttpを使用して
非同期でファイルをダウンロードし、端末のダウンロードフォルダに保存する方法について
実際のコードを用いてわかりやすく解説していきます!

この記事を読んでわかること…
・OkHttpとは?
・ファイルダウンロードの実装方法
・ファイルダウンロード時のエラーハンドリング

目次

環境

  • Kotlin (ver 1.9.0)
  • Android Studio (Giraffe | 2022.3.1 Patch 3)

OkHttpとは?

OkHttpは、Androidでネットワークを行うためのシンプルで高機能なHTTPクライアントライブラリです。
GoogleやSquareなどで広く利用されており、HTTPリクエストを簡単に扱えるため、ファイルダウンロードにも非常に適しています。

【公式】https://square.github.io/okhttp/

OkHttpでファイルをダウンロードするメリット

Androidアプリの機能の中で、KotlinのOkHttpでファイルダウンロードを実装することは 以下のメリットがあります。

  • 効率的な接続:接続の再利用が自動で行われ、通が高速化される
  • 非同期処理が簡単:シンプルなコードで非同期ダウンロードが可能
  • リクエストの柔軟性:カスタムヘッダーやリトライ処理が簡単に追加できる
  • 安定性:信頼性が高く、大規模なアプリケーションでも利用されている

その他にも、以下のような ファイルや画像をダウンロード機能を実現できるものは存在しますが、
以下の理由で OkHttpを使用するのが一般的です。

HttpURLConnection
・標準APIだが古い:公式でサポートされていますが、コード量が多くなりがちで使いにくい。
・メンテナンスが必要:接続管理やリソース解放(disconnect()など)が煩雑。
・同期的な処理が中心:非同期処理が難しく、手間がかかる。

権限の設定

インターネットからファイルをダウンロードするために、AndroidManifest.xmlに以下の権限を追加します。

<uses-permission android:name="android. permission. INTERNET />
<uses-permission android:name="android. permission.WRITE_EXTERNAL_STORAGE />
  • INTERNET:インターネットへのアクセスを許可します。
  •   WRITE_EXTERNAL_STORAGE:外部ストレージへの書き込みを許可します。

【サンプルコード】0kHttpを使ったファイルダウンロードの実装

それでは早速実装していきましょう!

まずはOkHttpの依存関係を追加します。▼

implementation ("com. squareup.okhttp3:0khttp:4.9.3")

次に、ボタン押下でファイルがダウンロードされるよう実装します。▼

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val downloadButton = findViewById<Button>(R.id.download_button)
        downloadButton.setOnClickListener() {
            val fileUrl = "https://drive.google.com/file/d/1_HESoWRVFMIIadNEF6Eu52JsYlnzBuh2/view?usp=sharing"
            val fileName = "sample.pdf"
            downloadFile(fileUrl, fileName)
        }
    }
}

そして、非同期でファイルダウンロードを行う処理を実装します。▼

private fun downloadFile(fileUrl: String, fileName: String) {
        CoroutineScope (Dispatchers. IO). launch {
            try {
                val client = OkHttpClient()
                val request = Request.Builder().url(fileUrl).build()
                // ダウンロード実行
                val response = client.newCall(request).execute()

                if (response.isSuccessful) {
                    // ダウンロードデータの取得
                    val inputStream: InputStream? = response.body?.byteStream()
                    val resolver = contentResolver
                    val contentValues = ContentValues().apply {
                        put(MediaStore.Downloads.DISPLAY_NAME, fileName)
                        put(MediaStore.Downloads.MIME_TYPE, "application/pdf")
                        put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
                    }

                    val uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
                    uri?.let { fileUri ->
                        resolver.openOutputStream(fileUri).use { outputStream ->
                            inputStream?.copyTo(outputStream!!)
                        }
                    }

                    withContext(Dispatchers.Main) {
                        Toast.makeText(applicationContext, "ダウンロード完了", Toast.LENGTH_LONG).show()
                    }
                } else {
                    withContext(Dispatchers.Main) {
                        Toast.makeText(applicationContext, "ダウンロード失敗", Toast.LENGTH_SHORT).show()
                    }
                }
            } catch(e: Exception) {
                withContext(Dispatchers.Main) {
                    Toast.makeText(applicationContext, "エラー", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

サンプルコードの解説

4〜7行目:OkHttpでダウンロードリクエストを送信

OkHttpclient はHTTPリクエストを行うクライアントです。
Request.Builder ().url(fileUrl).build()で、ダウンロードするファイルのURLを指定して、リクエストを作成、
そしてnewcall(request).execute()でリクエストを実行し、サーバーからのレスポンスを受け取ります

同期処理として行うため、リクエストが完了するまで待機します。

9行目:レスポンスの成功判定

isSuccessfulは、HTTPステータスコードが200~299の範囲であればtrueを返します。
失敗した場合はエラーとして処理されます。

11行目:ダウンロードデータの取得

response. body?.bytestream()で、ダウンロードしたデータをストリーム形式で取得します。

(ストリームはデータを少しずつ読み込みながら処理するため、大容量のファイルでもメモリ効率が良いです。)

12〜17行目:MediaStoreを使ってファイル情報を設定

contentResolverは、Androidシステムを通じてストレージにアクセスするためのオブジェクトです。
そしてContentValues保存するファイルの情報(名前やパス、MIMEタイプなど)を設定します。

・DISPLAY_NAME:保存するファイル名です。例:sample.pdf
・MIME_TYPE:ファイルの種類を示します。application/pdf はPDFファイルを意味します。
・RELATIVE_PATH :保存先フォルダを指定します。この例では「ダウンロードフォルダ」に保存します。

19行目:ファイルの保存先をMediaStoreに挿入

Mediastore, Down loads.EXTERNAL_CONTENT_URIは、ダウンロードフォルダのURIです。
insertでファイルを挿入し、保存先のURIが返されます。

ファイルの保存先が正しく作成されると、そのURIが取得できます。

20〜24行目:ダウンロードデータをファイルに書き込み

openOutputstreamで、指定したURIにファイルを書き込むためのストリームを取得します。
inputstream?.copyTo (outputstream!!)ダウンロードしたデータを出カストリームにコピーしてファイルとして保存、
そしてuseでストリームの自動クローズを保証し、リソースリークを防ぎます。

それでは、ビルドしてみましょう!

【Android】<Kotlin>OkHttpを使用して、ファイルをダウンロードし端末のフォルダに保存する実装方法を徹底解説!

ダウンロード先のフォルダを確認すると、

【Android】<Kotlin>OkHttpを使用して、ファイルをダウンロードし端末のフォルダに保存する実装方法を徹底解説!

ファイルが保存されているのを確認できます。

まとめ

おつかれさまでした。いかがでしたでしょうか!

ダウンロード機能は、一見難しいように感じますが
きちんと手順を踏むことでわかりやすく実装を行うことができます。

すだ

技術者としてのキャリアパスを次のレベルへと進めたい皆様、
未経験からIT・Webエンジニアを目指すなら【ユニゾンキャリア】
を通じて、
自分の市場価値をさらに向上させてみませんか?

それではまた次の記事でお会いしましょう!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

弊社テックブログをご愛読いただきありがとうございます。
当テックブログを運用している株式会社メモリアインクは、
【正社員】還元率83%
【フリーランス】マージン一律5万円で案件のご紹介
と、エンジニアの皆様に分かりやすい形で稼げる仕組みを構築し提供させていただいております。詳しくは弊社お問い合わせページ、プロフィールのQRコードを読み取り、LINEメッセージでお問い合わせいただけますと幸いです。

コメント

コメントする

目次