feat: 增加媒体格式校验,支持 JPEG、PNG、GIF、MP4、WebM、WebP 格式

This commit is contained in:
km2023
2026-04-20 15:40:22 +08:00
parent 1a7bbdc625
commit f42944bb58
3 changed files with 75 additions and 7 deletions

View File

@@ -110,7 +110,7 @@ sdk.deleteFile(key: "file-key") { result in /* ... */ }
### 文件传输
```swift
// ANI prepare transfer
// ANI prepare transfer
sdk.transferMedia(fileUrl: "https://example.com/video.mp4") { result in
switch result {
case .success: print("Transfer complete")
@@ -120,6 +120,13 @@ sdk.transferMedia(fileUrl: "https://example.com/video.mp4") { result in
// delegate didUpdateProgress
```
**支持的媒体格式:** JPEG、PNG、GIF、MP4、WebM、WebP
格式校验规则:
- 优先从 URL path 提取扩展名(自动忽略查询参数)
- 无扩展名时通过 HEAD 请求检查 `Content-Type`
- 不支持的格式返回 `DuooomiBleError.unsupportedFormat`
### 固件升级
```swift

View File

@@ -35,6 +35,7 @@ public enum DuooomiBleError: LocalizedError {
case transferFailed(String)
case invalidFrame
case permissionDenied
case unsupportedFormat(String)
public var errorDescription: String? {
switch self {
@@ -64,6 +65,8 @@ public enum DuooomiBleError: LocalizedError {
return "Invalid protocol frame"
case .permissionDenied:
return "Bluetooth permission denied"
case .unsupportedFormat(let ext):
return "Unsupported file format: \(ext). Supported: jpeg, png, gif, mp4, webm, webp"
}
}
}

View File

@@ -419,6 +419,57 @@ public final class DuooomiBleSDK: NSObject {
// MARK: - High-Level APIs
private static let supportedMediaExtensions: Set<String> = [
"jpeg", "jpg", "png", "gif", "mp4", "webm", "webp"
]
private static let supportedMimeTypes: Set<String> = [
"image/jpeg", "image/png", "image/gif", "image/webp",
"video/mp4", "video/webm"
]
private func extractExtension(from urlString: String) -> String? {
guard let comps = URLComponents(string: urlString) else { return nil }
let path = comps.path
let ext = (path.lowercased() as NSString).pathExtension
guard !ext.isEmpty else { return nil }
return ext
}
private func validateMediaFormat(url: String, completion: @escaping (Result<Void, Error>) -> Void) {
if let ext = extractExtension(from: url) {
if DuooomiBleSDK.supportedMediaExtensions.contains(ext) {
completion(.success(()))
} else {
completion(.failure(DuooomiBleError.unsupportedFormat(ext)))
}
return
}
guard let requestUrl = URL(string: url) else {
completion(.failure(DuooomiBleError.transferFailed("Invalid URL: \(url)")))
return
}
var request = URLRequest(url: requestUrl)
request.httpMethod = "HEAD"
URLSession.shared.dataTask(with: request) { _, response, error in
if let error = error {
completion(.failure(DuooomiBleError.transferFailed("Format check failed: \(error.localizedDescription)")))
return
}
guard let mime = (response as? HTTPURLResponse)?.allHeaderFields["Content-Type"] as? String else {
completion(.failure(DuooomiBleError.unsupportedFormat("unknown")))
return
}
let baseMime = mime.components(separatedBy: ";").first?.trimmingCharacters(in: .whitespaces).lowercased() ?? ""
if DuooomiBleSDK.supportedMimeTypes.contains(baseMime) {
completion(.success(()))
} else {
completion(.failure(DuooomiBleError.unsupportedFormat(baseMime)))
}
}.resume()
}
///
public func transferMedia(fileUrl: String, completion: @escaping (Result<Void, Error>) -> Void) {
guard connectedDevice != nil else {
@@ -437,14 +488,21 @@ public final class DuooomiBleSDK: NSObject {
BleLog.i("Direct ANI transfer: \(url)", "Transfer")
transferMediaStep2(aniUrl: url, originalUrl: url, completion: completion)
} else {
BleLog.i("Converting to ANI: \(url)", "Transfer")
aniConverter.convert(fileUrl: url) { [weak self] result in
validateMediaFormat(url: url) { [weak self] result in
switch result {
case .failure(let error):
completion(.failure(DuooomiBleError.transferFailed("ANI conversion failed: \(error.localizedDescription)")))
case .success(let aniUrl):
BleLog.i("ANI ready: \(aniUrl)", "Transfer")
self?.transferMediaStep2(aniUrl: aniUrl, originalUrl: url, completion: completion)
completion(.failure(error))
case .success:
BleLog.i("Converting to ANI: \(url)", "Transfer")
self?.aniConverter.convert(fileUrl: url) { [weak self] result in
switch result {
case .failure(let error):
completion(.failure(DuooomiBleError.transferFailed("ANI conversion failed: \(error.localizedDescription)")))
case .success(let aniUrl):
BleLog.i("ANI ready: \(aniUrl)", "Transfer")
self?.transferMediaStep2(aniUrl: aniUrl, originalUrl: url, completion: completion)
}
}
}
}
}