如何让iOS应用在各类「打开方式…」及分享菜单中正常显示?
iOS应用全局分享菜单适配问题
问题背景
我开发的iOS应用支持相册选图和相机拍照,现在需要实现:用户能从Mail、Safari、Photos等所有支持长按图片调出「分享…」菜单的应用中,通过分享直接导入图片到我的应用。
目前仅在Photos应用分享单张图片时能看到我的应用,多选图片、Safari或Mail中的图片分享时均不显示。已知Instagram、OmniFocus等第三方应用可以实现该功能,且它们并非使用分享扩展,而是直接打开目标应用。
已尝试的操作
- 严格按照Apple技术笔记QA1587配置新Xcode项目,结果与实际应用一致,仅Photos单图场景有效
- 尝试过
LSHandlerRank、CFBundleTypeRole的各种组合 - 测试过有无
CFBundleTypeIconFiles、LSSupportsOpeningDocumentsInPlace的情况 - 覆盖了从
public.data这类通用UTI到public.image、public.jpeg这类特定UTI的所有配置 - 已提交Apple开发者技术支持工单,暂未收到回复
- 曾偶然出现应用图标在分享菜单中,但无法复现,推测是系统缓存
CFBundleDocumentTypes导致刷新不稳定
现有配置步骤
- 创建新Xcode项目
- Info.plist配置:
<key>CFBundleDocumentTypes</key> <array> <dict> <key>CFBundleTypeName</key> <string>Image</string> <key>LSHandlerRank</key> <string>Owner</string> <key>CFBundleTypeRole</key> <string>Editor</string> <key>LSItemContentTypes</key> <array> <string>public.data</string> <string>public.content</string> <string>public.item</string> </array> </dict> </array> <key>LSSupportsOpeningDocumentsInPlace</key> <true/>
- SceneDelegate中添加代码:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { for context in URLContexts { let url = context.url if let data = try? Data(contentsOf: url), let image = UIImage(data: data) { let alert = UIAlertController() alert.title = "Loaded an image" alert.message = "Size is \(image.size)" window?.rootViewController?.present(alert, animated: true, completion: nil) } } }
注:有无LSSupportsOpeningDocumentsInPlace对结果无影响
可行配置方案
1. 修正Info.plist的UTI配置
需要明确指定图片类UTI,同时添加LSFileQuarantineEnabled并设置为false,确保系统不会因为安全隔离过滤掉应用。更新后的CFBundleDocumentTypes配置如下:
<key>CFBundleDocumentTypes</key> <array> <dict> <key>CFBundleTypeName</key> <string>Image Files</string> <key>CFBundleTypeRole</key> <string>Viewer</string> <key>LSHandlerRank</key> <string>Alternate</string> <key>LSItemContentTypes</key> <array> <string>public.image</string> <string>public.jpeg</string> <string>public.png</string> <string>public.gif</string> <string>com.apple.heic</string> <string>com.apple.heif</string> </array> <key>LSFileQuarantineEnabled</key> <false/> </dict> </array> <key>LSSupportsOpeningDocumentsInPlace</key> <true/>
2. 添加UTI导出声明(关键)
在Info.plist中添加UTExportedTypeDeclarations,明确声明支持的图片类型,帮助系统识别应用的处理能力:
<key>UTExportedTypeDeclarations</key> <array> <dict> <key>UTTypeIdentifier</key> <string>public.image</string> <key>UTTypeDescription</key> <string>Image File</string> <key>UTTypeConformsTo</key> <array> <string>public.item</string> </array> </dict> </array>
3. 处理多图场景的代码适配
原代码仅处理单图,需要适配多选场景,同时注意文件权限问题(不要直接用Data(contentsOf:),改用安全作用域访问):
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { for context in URLContexts { let url = context.url // 处理安全作用域文件 guard url.startAccessingSecurityScopedResource() else { print("无法访问文件") return } defer { url.stopAccessingSecurityScopedResource() } do { let data = try Data(contentsOf: url) if let image = UIImage(data: data) { let alert = UIAlertController(title: "导入图片成功", message: "尺寸:\(image.size)", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) window?.rootViewController?.present(alert, animated: true) } } catch { print("读取图片失败:\(error.localizedDescription)") } } }
4. 清除系统缓存的方法
配置修改后,为确保系统立即刷新,可执行以下操作:
- 删除设备上的应用,重新安装
- 重启设备(彻底清除Launch Services缓存)
- 使用Xcode的
Product > Clean Build Folder,再重新运行
关键说明
CFBundleTypeRole设为Viewer比Editor更符合分享场景的定位,系统优先级更高LSHandlerRank设为Alternate,避免和系统默认应用冲突,同时保证在分享菜单中显示- 明确指定具体图片UTI,比通用UTI更易被系统识别,覆盖所有常见图片格式
LSFileQuarantineEnabled设为false,防止系统将从其他应用分享的文件视为隔离文件,导致应用无法被选中- 必须处理安全作用域文件,尤其是iOS 13+,否则会无法读取来自其他应用的文件
内容的提问来源于stack exchange,提问作者Bill
相关产品推荐
相关产品推荐

