Share Extensionに渡されたファイルが読み取れなかった問題を解消した
Share Extensionとは
Share Extensionは、他のアプリで共有したいデータを自分のアプリで受け取るための機能です。例えば、写真アプリで写真を選択し、共有ボタンを押すと、Share Extensionが起動し、その写真を自分のアプリで受け取ることができます。
問題の発生
元の実装では、以下のコードを使用して画像ファイルを取得していました。
let extensionItem = extensionContext!.inputItems[0] as! NSExtensionItem
let attachment = extensionItem.attachments![0]
attachment.loadFileRepresentation(forTypeIdentifier: "public.image", completionHandler: { url, error in
let tempDirectory = try FileManager.default.url(
for: .itemReplacementDirectory,
in: .userDomainMask,
appropriateFor: url,
create: true
)
let destURL = tempDirectory.appending(path: url.lastPathComponent)
try FileManager.default.copyItem(at: url, to: destURL)
}
このコードでは、取得したURLを一時ディレクトリに移動し、そのURLを使用して画像を表示していました。しかし、ある日、Duolingoから共有された画像を受け取った際に、渡されたURLをもとにUIImageを生成しようとしたところ、nil
になってしまう問題が発生しました。
原因の調査
問題を調査した結果、Duolingoから渡されたファイルには拡張子がついていないことが判明しました。LLDBを使用してデータの先頭をダンプしてみたところ、以下のようなデータが表示されました。
po data.map { String(format: "%02x", $0) }.joined()
結果:
62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a90b0c2e2f3034383f4355246e756c6cdf
このデータを調べたところ、Binary Plist形式であることが分かりました。Binary Plistは、NSKeyedArchiver
でエンコードされたデータである可能性があります。
解決方法
以下のコードを使用して、Binary Plist形式のデータをアンアーカイブし、UIImageを取得することができました。
let extensionItem = extensionContext!.inputItems[0] as! NSExtensionItem
let attachment = extensionItem.attachments![0]
attachment.loadFileRepresentation(forTypeIdentifier: "public.image", completionHandler: { url, error in
let data = try! Data(contentsOf: url!)
let image = try! NSKeyedUnarchiver.unarchivedObject(ofClass: UIImage.self, from: data)
}
このコードでは、Data
を取得した後、NSKeyedUnarchiver
を使用してデータをアンアーカイブしています。これにより、拡張子がない場合でも正しく画像を取得することができました。
発展
次のようなextensionを生やすことで、ヘッダーを確認し、Binary Plist形式であるかどうかを判定することができます。
extension Data {
var isBinaryPlist: Bool {
let magic = "bplist00".data(using: .ascii)!
return self.prefix(8) == magic
}
}
まとめ
TypeIdentifierが"public.image"
に準拠していても、Binary Plist形式である可能性があるため、データの形式を確認することが重要です。一度データをアンアーカイブし、それに失敗する場合にファイルをコピーしたり、拡張子で判断するなどの処理を行うことが必要です。この問題を解決することで、Share Extensionを通じて受け取った画像を正しく表示できるようになりました。
Discussion