うるおいらんど

【UIActivity】Twitter共有時にのみハッシュタグをつけたい!Instagramにも投稿したい!を実装してみた【Swift 3】

追記があります。

まだSwift3を使っています。Reoです。

UIActivityViewControllerを用いてシェアをするときに、

・Twitter共有では、ハッシュタグをつけたい!

・Instagramにも投稿したい!

と思い、これらを実装してみたので紹介しますー。

どちらも公式アプリが端末内にインストールされているのが前提となります。

 

画像とテキストをシェアする!

通常UIActivityViewControllerを用いてシェアするときは以下のようにします。

    //ボタンが押されたとき
    func btnTapped(sender:UIButton){
        let text = "シェアするテキスト"
        let image = UIImage(named:"test.jpg")
        let activityItem:[Any] = [text,image]
        let activityVC = UIActivityViewController(activityItems: activityItem, applicationActivities: nil)
        self.present(activityVC, animated: true, completion: nil)
    }

UIActivityViewControllerのactivityItemsにシェアしたいテキストや画像やURL等が含まれた配列を渡します。

こちらも何かの参考になれば(【Swift】UIActivityで画像を複数枚同時に共有するとき【メモ】)

 

Instagramにシェアしたい!

Instagramにシェアするときは「単一の画像」もしくは「動画URL」等でないと、選択できるリストに出てきません。

先ほどのコードでの実装だと、このActivitiesのリストに出てきてくれません。

手っ取り早く投稿できるようにするには「単一画像」または「動画URL」のみをActivityItemsに渡してやります

    //ボタンが押されたとき
    func btnTapped(sender:UIButton){
        let image = UIImage(named:"test.jpg")
        let activityItem:[Any] = [image]
        let activityVC = UIActivityViewController(activityItems: activityItem, applicationActivities: nil)
        self.present(activityVC, animated: true, completion: nil)
    }

これだとInstagramにも投稿できるようになります。 ちなみに動画は3秒以上でないとシェアできません。

 

でもこの場合、Twitterとかメールとか別のやつを選んだときにも「画像のみ」のシェアしかできません。 テキストも画像もシェアできるところでは、両方をシェアしたい。しかしこのUIActivityVC、開かれる前にアイテム渡しちゃうし、それに合わせてシェアできるものだけしか表示してくれない。(テキスト・画像を渡すとInstagramが表示されない。)

どうすればいいものか。色々試行錯誤して、ようやく実装できますた。ようやく本題です。

結局やりたいことは、 UIActivityVCが開かれたときには、「画像のみ」でシェアできるものを表示し、選択されたActivityがテキストも渡せるものなら、テキストと画像の両方を渡す といったことです。

 

UIActivityItemSourceを用いる!

まず渡したいアイテムそれぞれにUIActivityItemSourceプロトコルに適合したNSObjectのサブクラスでを作ります。

//渡したいテキスト
class TextActivityItem:NSObject,UIActivityItemSource{

}

//渡したい画像
class ImageActivityItem:NSObject,UIActivityItemSource{

}

 

まずは画像の方から。

初期化時にUIImageを渡すようにしておきます。

class ImageActivityItem:NSObject,UIActivityItemSource{
    
    var image:UIImage?
    override init(){
        super.init()
    }
    convenience init(_ image:UIImage?){
        self.init()
        self.image = image
    }
    
}

次にプレースホルダーの設定をします。

    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        return image ?? UIImage()
    }

これは仮のアイテムで、UIImageをシェアするつもりだよ!っていうのが伝わればおkなやつです。実際に渡すアイテムと型が違っても一応おk。

このactivityViewControllerPlaceholderItem(_:)が結構肝です。これによってどのActivityが表示されるかが決まります。

最後に実際に渡したい値をセット。

    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
        return image
    }

 

ImageActivityItemはこんな感じになりました。

class ImageActivityItem:NSObject,UIActivityItemSource{
    
    var image:UIImage?
    override init(){
        super.init()
    }
    convenience init(_ image:UIImage?){
        self.init()
        self.image = image
    }
    
    //実際に渡す
    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
        return image
    }
    
    //仮に渡す
    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        return image ?? UIImage()
    }
    
}

 

テキストを渡す

やりたいことは画像の時とほぼ同じです。UIImageかStringかの差です。

class TextActivityItem:NSObject,UIActivityItemSource{
    
    var shareText = ""
    override init(){
        super.init()
    }
    convenience init(_ text:String){
        self.init()
        self.shareText = text
    }
    
    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
        return shareText
    }
    
    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        //ここではNSObjectを返しておく
        return NSObject()
    }
}

 

この時の1番のキモがここ!

    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        //ここではNSObjectを返しておく
        return NSObject()
    }

ここではString型を返さずNSObjectを返しておく!というのが大事になります。

 

実際にこれらを使うときは、

    //ボタンが押されたとき
    func btnTapped(sender:UIButton){
        let text = "シェアするテキスト"
        let image = UIImage(named:"test.jpg")
        let activityItem:[Any] = [TextActivityItem(text),ImageActivityItem(image)]
        let activityVC = UIActivityViewController(activityItems: activityItem, applicationActivities: nil)
        self.present(activityVC, animated: true, completion: nil)
    }

のようにして配列に入れて渡してやります。

activityViewControllerPlaceholderItem(_:)を設定がここで活用されます。

最初の方法(text,imageをそのまま渡す方法)だと、「String型とUIImage型」をシェアするためのActivityアイコンが並びます。

しかしこの方法では、TextActivityItemのところでPlaceholderItemにNSObject()を渡しているので、「NSObject型とUIImage型」をシェアするためのアイコンが並びます。

このおかげでString型を含んでいると出てこないはずのInstagramのアイコンも出てくるようになります。∩(〃・ω・〃)∩ ばんじゃーい

 

そして実際にActivityアイコンを選択した後に、activityViewController(_:itemForActivityType:)が呼び出され、実際に必要なモノだけを自動的に選んでシェアします。(Instagramには画像のみが渡されます。テキストは渡されません。)

 

Twitterへのシェア時にのみハッシュタグをつけよう!

Twitterへのシェアの時にだけハッシュタグをつけたい!という場合には、先ほど作ったTextActivityItemのactivityViewController(_:itemForActivityType:)で分岐してやります。

    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
        //Twitter投稿時のみハッシュタグをつける
        if activityType == .postToTwitter {
            return shareText + "#ハッシュタグ"
        }
        return shareText
    }

 

TextActivityItemの全体はこんな感じになりました。

class TextActivityItem:NSObject,UIActivityItemSource{
    
    var shareText = ""
    override init(){
        super.init()
    }
    convenience init(_ text:String){
        self.init()
        self.shareText = text
    }
    
    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
        if activityType == .postToTwitter {
            return shareText + "#ハッシュタグ"
        }
        return shareText
    }
    
    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        //ここではNSObjectを返しておく
        return NSObject()
    }
}

 

 

おまけ。

Instagramのときだけ画像を加工したいとき

Twitterへの投稿にはactivityTypeに .postToTwitterというのが用意されていますが、Instagramでは用意されてません。ので以下のように分岐できます。

    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
        if activityType.rawValue == "com.burbn.instagram.shareextension"{
            //例えばここで真四角に切り取り処理をするとか。
            return cropImage(image: image!, contentSize: CGSize(width:600,height:600))
        }
        return image
    }

こんな感じでやってみても良いかも。

 

UIActivity関連これはうまくいったんですが、Facebookへの投稿だけ開いて少しすると勝手に閉じるし、謎エラーもあって結構困る・・・・。

それではでは。

 

参考リンク

Additional Notes追記

Gistにあげときました。

一応gistにあげました。

でも自分はもう使ってない手法。 TwitterKit等々を頑張って使ってます。

Comments

コメントはありません。

現在コメントフォームは工事中です。