4.B QQ 链接分享补 previewimageUrl:用 app icon 当缩略图

QQ 会话里链接分享的缩略图位空白,因为 News 类型缺 previewimageUrl 字段。
对齐 msext QQShareManager.m:517-522 + 1271-1278 的写法:

1. app icon JPEG 0.7 写到 NSTemporaryDirectory()/qq_share_<UUID>.jpg
2. 拼 file://<path> 字符串
3. base64 后再 URL-encode
4. append &previewimageUrl=<那串>

writeAppIconToTemp() 与 appIconImage() 直接抄 WechatShare 同源策略(读
Info.plist CFBundleIcons → CFBundlePrimaryIcon → CFBundleIconFiles 最后
一个)。两处复制可接受 —— Share 模块统一缩略图工具可后续抽到
ImageProvider,本次保持改动范围最小。
This commit is contained in:
joywayer
2026-06-24 18:03:58 +08:00
parent 34a336d859
commit 2f3a35892b
+39
View File
@@ -114,6 +114,13 @@ public final class QQShare: SharePlatform {
parts.append("url=\(Self.encode(Self.base64(content.webpageUrl)))")
}
// 3. app icon tmp previewimageUrl = urlenc(base64("file://<path>"))
// msext QQShareManager.m:517-522 saveImageToTempDirectory + base64
if let thumbPath = Self.writeAppIconToTemp() {
let fileURL = "file://\(thumbPath)"
parts.append("previewimageUrl=\(Self.encode(Self.base64(fileURL)))")
}
let urlString = "mqqapi://\(host)?\(parts.joined(separator: "&"))"
Self.log.debug("QQShare URL → \(urlString, privacy: .public)")
@@ -184,6 +191,38 @@ public final class QQShare: SharePlatform {
return top
}
// MARK: - app icon tmp file
/// app icon JPEG NSTemporaryDirectory
/// msext QQShareManager.m:1271-1278 saveImageToTempDirectory:
/// qq_share_<UUID>.jpgJPEG 0.7 nil
private static func writeAppIconToTemp() -> String? {
guard let data = appIconImage().jpegData(compressionQuality: 0.7) else { return nil }
let path = NSTemporaryDirectory() + "qq_share_\(UUID().uuidString).jpg"
do {
try data.write(to: URL(fileURLWithPath: path), options: .atomic)
return path
} catch {
log.error("QQShare 写缩略图临时文件失败 \(error.localizedDescription, privacy: .public)")
return nil
}
}
/// app icon UIImage WechatShare.appIconImage()
/// Info.plist CFBundleIcons CFBundlePrimaryIcon CFBundleIconFiles
private static func appIconImage() -> UIImage {
if let icons = Bundle.main.object(forInfoDictionaryKey: "CFBundleIcons") as? [String: Any],
let primary = icons["CFBundlePrimaryIcon"] as? [String: Any],
let files = primary["CFBundleIconFiles"] as? [String],
let last = files.last,
let icon = UIImage(named: last) {
return icon
}
if let icon = UIImage(named: "AppIcon") { return icon }
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 1, height: 1))
return renderer.image { _ in }
}
// MARK: - URL / Base64
/// RFC 3986 unreserved + URL-encode msext line 1262-1268