【Swift】CustomUIActivityでLINE/Twitterシェアを実装しよう

今回はCustomUIActivityを作成し、シェアボタンを押した時にテキスト、URL、画像などをシェアする機能を実装しました。URLSchemeを使うので、ライブラリなどを入れる必要がなく、カスタマイズも容易なので便利です。UIActivityは2つの[カテゴリ](https://developer.apple.com/documentation/uikit/uiactivity/category)があり、上段と下段に分かれているのですが下段にアプリを追加する方法があまり見当たらなかったので今回記事にしました。(LINEへのシェア機能をLINEActivityを使って実装しようと思っていたのですが、ライブラリ自体が少し古く、うまく動かない部分があったのでこちらの方法で実装すると良いかと思います)

##完成形
アクションボタンを押すと、下からアクティビティの候補が出てきて、その中から選択したアプリにシェアができるという仕組みになってます。今回はアイコンを下段に2つ追加しています。
![UIActivityImage.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271820/f3ebde82-967e-724e-7274-a2c7daf670e7.gif)
<img width="281" alt="スクリーンショット 2019-09-03 13.16.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271820/2d371420-9363-b16a-0360-c34ede25fdc0.png">

##実装方法
###1. アイコンの準備
アクティビティの候補として表示されるアプリのアイコンはモノクロになります。**白く表示させたい部分は透過させる必要があるので注意してください。**アイコンは`@2x`と`@3x`の2種類を用意し、プロジェクトファイルに追加してください。
###2. CustomUIActivityの作成
【New File】→【Swift File】を選択し、UIActivityを継承した2つのクラス(LINEActivity.swiftとTwitterActivity.swift)を作成し、以下のようにコーディングを行います。

```swift:LINEActivity.swift
import UIKit

class LINEActivity: UIActivity {
    let urlScheme: String = "line://msg/text"
    //シェアしたいメッセージ
    var message = "LINEにシェアするよ"
    let shareUrl = NSURL(string: "https://www.apple.com/jp/")!
    
    init(message: String) {
        self.message = message
    }
    
    override class var activityCategory: UIActivity.Category {
        //actionだと下の段, shareだと上の段に表示される
        return .action
    }
    
    override var activityTitle: String? {
        //表示の際のテキスト
        return "LINEでシェア"
    }
    
    override var activityImage: UIImage? {
        //UIActivityに表示されるアイコン
        return UIImage(named: "LINEActivityIcon")
    }
    
    override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
        return true
    }
  
    override func perform() {
        //urlSheme + / + message (+ image or url) のフォーマット
        let urlstring = "\(urlScheme)/\(message)\n\(shareUrl)"
        //日本語などをエンコード
        let encodedURL = urlstring.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
        let url = URL(string: encodedURL!)
        guard let openUrl = url else { return }
        UIApplication.shared.open(openUrl, options: .init(), completionHandler: nil)
        activityDidFinish(true)
    }
}
```

```swift:TwitterActivity.swift
import UIKit

class TwitterActivity: UIActivity {
    let urlScheme: String = "twitter://post?message="
    //シェアしたいメッセージ
    var message = "Twitterにシェアするよ"
    let shareUrl = NSURL(string: "https://www.apple.com/jp/")!
    
    init(message: String) {
        self.message = message
    }
    
    override class var activityCategory: UIActivity.Category {
        //actionだと下の段, shareだと上の段に表示される
        return .action
    }
    
    override var activityTitle: String? {
        //表示の際のテキスト
        return "Twitterでシェア"
    }
    
    override var activityImage: UIImage? {
        //UIActivityに表示されるアイコン
        return UIImage(named: "TwitterActivityIcon")
    }
    
    override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
        return true
    }
    
    override func perform() {
        //urlSheme + message (+ image or url) のフォーマット
        let urlstring = "\(urlScheme)\(message)\n\(shareUrl)"
        //日本語などをエンコード
        let encodedURL = urlstring.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
        let url = URL(string: encodedURL!)
        guard let openUrl = url else { return }
        UIApplication.shared.open(openUrl, options: .init(), completionHandler: nil)
        activityDidFinish(true)
    }
}
```

|    メソッド    |  内容  | 
|:-----------------|:------------------|
| URLSheme|特定のアプリに遷移させるためのリンク。LINEは**line://msg/text**、Twitterは**twitter://post?message=**でメッセージ送信画面へ遷移できる。 |
| activityCategory| **.share**だとUIActivityの上段にアプリが表示され、**.action**だと下段に表示される。|  
| activityTitle|UIActivityにアプリのアイコンと一緒に表示されるタイトル。|    
| activityImage|UIActivityに表示されるアプリのアイコン。1で作成したアイコンを指定する。|      
| perform()|アプリ遷移時に受け渡す情報をここで記述する。UrlShemeとメッセージやURLなどを連結し、エンコードしてからURLとして渡す。|  

###3. ViewControllerのコーディング
```swift:ViewController.swift
import UIKit

class ViewController: UIViewController {
    
    let shareText = "シェアするよ"
    let shareUrl = NSURL(string: "https://www.apple.com/jp/")!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func share() {
        //share(上の段)から遷移した際にシェアするアイテム
        let activityItems: [Any] = [shareText, shareUrl]
        let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: [LINEActivity(message: shareText), TwitterActivity(message: shareText)])
        self.present(activityViewController, animated: true, completion: nil)
    }
}
```
`share()`メソッドの中でシェアするアイテムを`[Any]`型の配列で定義し、UIActivityViewControllerの第一引数に渡します。**第一引数に渡したアイテムは下段ではなく、上段のシェアアクションの方に渡されるので注意してください。**第二引数には`LINEActivity()`と`TwitterActivity()`を配列にして渡します。

###4. StoryBoardの編集
以下のようにパーツをアクション接続したら完成です。
<img width="1121" alt="スクリーンショット 2019-09-03 14.03.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271820/aceec352-a41c-97b3-ced3-9f0eec40da6e.png">