檔案、圖片與錄音
im.files 負責附件、頭像、群檔案的上傳和下載,以及錄音。檔案的 URL 是長期不變的標識,可以儲存;真正下載時,SDK 用它換取一個有時效的下載地址。用途和大小限制見服務端的媒體檔案。
| 要做什麼 | 看哪裡 |
|---|---|
| 從檔案、記憶體或系統選擇器得到要上傳的檔案 | 檔案來源 |
| 發圖片、檔案訊息 | 隨訊息上傳 |
| 上傳頭像、群檔案 | 頭像與群檔案 |
| 下載檔案、顯示圖片 | 下載與快取、Coil 圖片接入 |
| 調整圖片壓縮 | 圖片與影片預處理 |
| 按住說話 | 錄音 |
檔案來源
kotlin
import com.deeprespond.im.*
import java.io.File
val local = DRFile.fromFile(File(context.cacheDir, "report.pdf"), "report.pdf", "application/pdf")
val memory = DRFile.fromBytes("你好".toByteArray(), "note.txt", "text/plain")
val selected = DRFile.fromUri(context, uri)fromUri是 Android 專用的擴充套件函式,import com.deeprespond.im.*已包含它。- 檔案選擇器由你的 App 提供。需要在 App 重啟後繼續使用系統 URI 時,按 Android 的規則申請持久的訪問許可權。
- 訊息進入傳送佇列後,SDK 會把檔案儲存下來;在那之前,URI 必須一直能讀取。
- 還有一個
fromSource,用於適配其他平臺,一般的 App 用上面三種即可。
隨訊息上傳
kotlin
im.messages.send(SendTarget.User("bob"), OutgoingContent.Image(file))
im.messages.send(SendTarget.User("bob"), OutgoingContent.File(file, name = "报告.pdf"))SDK 負責上傳和傳送,進度在本地訊息的狀態中。不發訊息、只上傳檔案時,upload 返回一個上傳任務:
kotlin
import com.deeprespond.im.*
val task = im.files.upload(file, UploadPurpose.ATTACHMENT, FileKind.FILE, name = "报告.pdf")
val uploaded = task.await()
println(uploaded.url)UploadTask.progress是StateFlow,Progress.loaded/total以位元組計,大小未知時total為-1。task.cancel()之後,await以aborted失敗。- 取消等待的協程不會取消上傳:只是不再等結果,上傳仍在繼續。要真正取消,請呼叫
task.cancel()。
頭像與群檔案
頭像按用途上傳,再把得到的 url 寫進對應的資料:
| 用途 | 寫到哪裡 |
|---|---|
USER_AVATAR | users.updateMe |
GROUP_AVATAR | groups.update |
CHATROOM_AVATAR | 聊天室的 manage.update |
群檔案要帶 groupId:
kotlin
val task = im.files.upload(file, UploadPurpose.GROUP_FILE, FileKind.FILE, groupId = groupId)
val uploaded = task.await()
val page = im.files.groupFiles(groupId)
println(uploaded.fileId)
println(page.fileCount)groupFiles 返回 items、nextCursor、fileCount(檔案數)和 usedBytes(佔用的位元組數);deleteGroupFile 刪除群檔案(上傳者本人、群主或管理員)。上傳群檔案不會發出訊息。
下載與快取
kotlin
import com.deeprespond.im.*
val task = im.files.download(DownloadSource.File(fileUrl), conflict = Conflict.RENAME)
val saved = task.await()
println(saved.name)- 下載來源還可以是
DownloadSource.Thumbnail(url)(縮圖)和DownloadSource.Message(message)(訊息中的附件)。 saveTo指定儲存的目錄(File);同名檔案的處理Conflict可選RENAME、OVERWRITE、FAIL。DownloadTask.cancel()刪除沒下載完的臨時檔案,await以aborted失敗。resolveUrl換取下載地址,返回downloadUrl和到期時間expiresAt;resolveUrls批次換取,每項單獨帶error。下載地址會過期,不要把它當作圖片的長期標識儲存。localPath(url)返回 SDK 為當前使用者快取的圖片的本地路徑,clearImageCache()清空圖片快取。- 離開了群、或被內容安全遮蔽的檔案,可能無法再下載。
圖片與影片預處理
MediaOptions預設壓縮圖片:長邊最多 2048 畫素,JPEG 質量 85,圖片快取 300 MiB。compressImages = false只關閉壓縮,預設的去除後設資料(如拍攝地點)仍然執行。- 自定義的
preprocess在 IO 執行緒執行,需要自己清除不需要的後設資料。 files.prepare(file, kind, original)只做處理、不上傳,返回PreparedFile:處理後的檔案、kind、format、size、寬高、duration、thumbnail、downgraded、metadataKept。不能按原來的媒體型別處理時,kind可能變為FILE,請按返回值顯示。PreparedFile最後沒有拿去上傳或傳送時,請刪除用不到的臨時檔案。DRFile.withKeepMetadata()明確保留後設資料,只在業務確實需要時使用。
Coil 圖片接入
加入 im-coil,使用 Coil 3 並註冊 SDK 元件:
kotlin
import coil3.ImageLoader
import com.deeprespond.im.coil.*
val loader = ImageLoader.Builder(context)
.components { addDRImage(im) }
.build()
val model = DRImage(fileUrl)把 model 交給你的 Coil ImageView 或 Compose 元件即可。DRImage.of(message, thumbnail = true) 從訊息中取縮圖,訊息沒有圖片時為 null。圖片快取按當前使用者區分;不要把有時效的下載地址當作 Coil 的模型。
錄音
App 在清單宣告 RECORD_AUDIO,並在使用前取得麥克風許可權:
kotlin
import com.deeprespond.im.*
import kotlin.time.Duration.Companion.seconds
val recording = VoiceRecorder.start(context, maxDuration = 60.seconds)
// 用户点击停止时;不是开始后立即停止。
val voice = recording.stop()
im.messages.send(SendTarget.User("bob"), voice.toContent())Recording.level是音量的Flow,可以畫音量條。ended表示錄音已經結束,reason為MAX_DURATION(到了最長時長)或INTERRUPTED(被中斷)。切到後臺或失去音訊焦點都可能中斷錄音,請監聽ended更新介面。cancel()放棄並刪除這段錄音。- 已經在錄音、正在通話、沒有麥克風許可權或裝置出錯時,不能開始錄音。
- 輸出為 AAC(m4a),不需要額外的 FFmpeg。
完整檔案介面見FilesModule,錄音介面見Recording。
