feat: 增加媒体格式校验,支持 JPEG、PNG、GIF、MP4、WebM、WebP 格式
This commit is contained in:
10
README.md
10
README.md
@@ -169,14 +169,20 @@ sdk.deleteFile(fileKey)
|
||||
### 文件传输
|
||||
|
||||
```kotlin
|
||||
// 传输媒体文件 (自动转换为 ANI 格式)
|
||||
// 支持: mp4, jpg, png, ani
|
||||
// 传输媒体文件 (格式校验 → ANI 转换 → prepare → transfer)
|
||||
sdk.transferMedia(fileUrl)
|
||||
|
||||
// 监听进度
|
||||
sdk.transferProgress.collect { percent -> /* 0-100 */ }
|
||||
```
|
||||
|
||||
**支持的媒体格式:** JPEG、PNG、GIF、MP4、WebM、WebP
|
||||
|
||||
格式校验规则:
|
||||
- 优先从 URL path 提取扩展名(自动忽略查询参数)
|
||||
- 无扩展名时通过 HEAD 请求检查 `Content-Type`
|
||||
- 不支持的格式抛出 `DuooomiBleError.UnsupportedFormat`
|
||||
|
||||
### 固件升级
|
||||
|
||||
```kotlin
|
||||
|
||||
@@ -10,6 +10,7 @@ import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import org.json.JSONObject
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URI
|
||||
import java.net.URL
|
||||
|
||||
class DuooomiBleSDK(context: Context, val config: DuooomiBleConfig) {
|
||||
@@ -303,6 +304,46 @@ class DuooomiBleSDK(context: Context, val config: DuooomiBleConfig) {
|
||||
|
||||
// MARK: - High-Level APIs
|
||||
|
||||
companion object {
|
||||
private val SUPPORTED_EXTENSIONS = setOf("jpeg", "jpg", "png", "gif", "mp4", "webm", "webp")
|
||||
private val SUPPORTED_MIME_TYPES = setOf(
|
||||
"image/jpeg", "image/png", "image/gif", "image/webp",
|
||||
"video/mp4", "video/webm"
|
||||
)
|
||||
}
|
||||
|
||||
private fun extractExtension(urlString: String): String? {
|
||||
return try {
|
||||
val path = URI(urlString).path ?: return null
|
||||
val dot = path.lastIndexOf('.')
|
||||
if (dot >= 0 && dot < path.length - 1) path.substring(dot + 1).lowercase() else null
|
||||
} catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
private suspend fun validateMediaFormat(url: String) {
|
||||
val ext = extractExtension(url)
|
||||
if (ext != null) {
|
||||
if (SUPPORTED_EXTENSIONS.contains(ext)) return
|
||||
throw DuooomiBleError.UnsupportedFormat(ext)
|
||||
}
|
||||
|
||||
val mime = withContext(Dispatchers.IO) {
|
||||
val conn = java.net.URL(url).openConnection() as HttpURLConnection
|
||||
try {
|
||||
conn.requestMethod = "HEAD"
|
||||
conn.connectTimeout = 10_000
|
||||
conn.readTimeout = 10_000
|
||||
conn.contentType?.split(";")?.firstOrNull()?.trim()?.lowercase()
|
||||
} finally {
|
||||
conn.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
if (mime == null || !SUPPORTED_MIME_TYPES.contains(mime)) {
|
||||
throw DuooomiBleError.UnsupportedFormat(mime ?: "unknown")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun transferMedia(fileUrl: String) {
|
||||
ensureConnected()
|
||||
val url = fileUrl.trim()
|
||||
@@ -315,6 +356,7 @@ class DuooomiBleSDK(context: Context, val config: DuooomiBleConfig) {
|
||||
aniUrl = url
|
||||
BleLog.i("Direct ANI transfer: $url", "Transfer")
|
||||
} else {
|
||||
validateMediaFormat(url)
|
||||
BleLog.i("Converting to ANI: $url", "Transfer")
|
||||
try {
|
||||
aniUrl = aniConverter.convert(url)
|
||||
|
||||
@@ -24,6 +24,7 @@ sealed class DuooomiBleError(message: String) : Exception(message) {
|
||||
class DeleteFileFailed(val status: Int) : DuooomiBleError("Delete failed: status=$status")
|
||||
class PrepareTransferFailed(val status: String) : DuooomiBleError("Prepare failed: $status")
|
||||
class TransferFailed(reason: String) : DuooomiBleError("Transfer failed: $reason")
|
||||
class UnsupportedFormat(val format: String) : DuooomiBleError("Unsupported file format: $format. Supported: jpeg, png, gif, mp4, webm, webp")
|
||||
object InvalidFrame : DuooomiBleError("Invalid protocol frame")
|
||||
object PermissionDenied : DuooomiBleError("Bluetooth permission denied")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user