Edited at

iOSで自分のアプリから写真をInstagramでシェアする時にハマった

More than 1 year has passed since last update.

Instagramの公式ページにも書いてるし、ググれば出てくるのですが、いろいろハマったのでまとめておきます。

動作環境、Xcode 9.3 + Swift 4.1 + iOS 11


URLスキームを使ってシェアする方法

公式ページには書かれていません。しかし、レイアウトというアプリでは、アプリ内で加工した写真を選択状態にして、Instagramの投稿画面を開くことができるので、隠しであるのかも?


APIを使って直接投稿する方法

投稿APIはありません・・・


UIActivityViewControllerを使ってシェアする方法

簡単でよいのですが、Instagramアプリは起動せず、直接自分のアプリから投稿する形になります。つまり、ユーザーからするとInstagramアプリの写真加工が使えないので不便に感じるかも。

@IBAction private func didTapShare() {

do {
// UIImageをactivityItemsにわたす
let activityViewController = UIActivityViewController(activityItems: [self.image], applicationActivities: nil)
present(activityViewController, animated: true)
} catch let error {
print(error)
}
}

表示されるシェアシート

02-1.png

Instagramを選択すると自分のアプリ内で投稿画面が表示される。

03.png


UIDocumentInteractionControllerを使ってシェアする方法

公式ドキュメントにも書かれているこの方法。説明にはInstagramアプリのみが選択対象になると書かれているのですが、実際はそうはなりません・・・過去はそうだったのかも知れませんが、iOS 11ではそうなりませんでした。あといくつかハマりポイントがありました。

@IBAction private func didTapShare() {

do {
// UIImageをDataに変換
guard let imageData = UIImageJPEGRepresentation(image, 1.0) else {
return
}

// テンポラリファイルとして保存。拡張子はigoにする
let imageURL = URL(fileURLWithPath: (NSTemporaryDirectory() as NSString).appendingPathComponent("image.igo"))
try imageData.write(to: imageURL, options: .atomicWrite)

// 必ずメンバ変数として保持すること。ローカル変数だと意図しないタイミングで破棄される
// 保存した画像ファイルのURLを渡す
self.documentInteractionController = UIDocumentInteractionController(url: imageURL)
self.documentInteractionController!.uti = "com.instagram.exclusivegram"
// shareButtonは押したボタン(UIBarButtonItem)
self.documentInteractionController!.presentOpenInMenu(from: shareButton, animated: true)
// よくこの方法が見られるけど、たいていはBarButtonItemから起動するのでは?iPadでは、ここきちんとやらないと変なとこからポップアップするので注意
// self.documentInteractionController!.presentOpenInMenu(from: self.view.bounds, in: self.view, animated: true)
} catch let error {
print(error)
}
}

UIDocumentInteractionControllerオブジェクトをメンバ変数として保持しないと、意図せず破棄されてしまいます。一瞬シェアシートが出たと思ったら、すぐに閉じてしまう。エラーログにInvalid Operationとか出ます。

そして実際に開かれるシェアシート。

01-1.png

一覧に表示されるのはInstagramだけじゃないんですよね・・・他のアプリもigo拡張子に対応したからでしょうか?

ただ先程のUIActivityControllerの時と違って、「Instagram」ではなく「Instagramにコピー」になっていて、選択すると、Instagramが起動し写真が選択された状態で投稿画面が開きます。これはこれで便利な気もしますが、シェアシートで選択できるアプリが限られてしまうのが、ユーザーからすると不便かもしれません。Twitterがないのはさすがに・・・Slackやクラシルは出てくるのですがw

そこでファイル拡張子やUTIの指定を以下のように変えてみます。

// 拡張子をjpg

let imageURL = URL(fileURLWithPath: (NSTemporaryDirectory() as NSString).appendingPathComponent("image.jpg"))
// utiをpublic.jpeg
documentInteractionController!.uti = "public.jpeg"

この場合、表示されるシェアシートはこのようになります。

04-1.png

Twitterもあります。そしてInstagramとInstagramへコピーの両方が表示されます。ユーザーからしたら何が違うんだと混乱の元になりそうですが・・・でも個人的には、これが一番いいかなと思いました。

Instagramの公式ドキュメントには、以下のようにするように書かれているのですが、上記のケースとシェアシートに表示されるアプリ、およびInstagramへコピーを選択した時の挙動に違いはなさそうでした。ドキュメント用意した時と変わってしまったのかなあ。

// 拡張子をig

let imageURL = URL(fileURLWithPath: (NSTemporaryDirectory() as NSString).appendingPathComponent("image.ig"))
// utiをcom.instagram.photo
documentInteractionController!.uti = "com.instagram.photo"