Share Extensionのハマりポイント

# はじめに
[初の個人アプリを App Store に審査出したら 30 分足らずでリリースされてビビったからその全てをお伝えします](https://qiita.com/lovee/items/67906ec593ebd91d608d)の記事を見てShare Extensionいいなぁと思い[自分のアプリ](https://qiita.com/am10/items/3ecac20451c82133e900)にもつけてみよう！と思ったのですが色々ハマりました...

# 対象
* iOS13.0以上
* macOS Catalina

# Share Extensionの実装
[ここ](https://qiita.com/lovee/items/67906ec593ebd91d608d#share-extension-%E5%AF%BE%E5%BF%9C)を参考に実装をしました。

Share Extension の追加自体は簡単でした。

`ShareViewController` の POST 機能とかいらなかったので参考記事に書いてあったように下記のように修正して画面を作成しました。

```swift:ShareViewController.swift
- class ShareViewController: SLComposeServiceViewController {
+ class ShareViewController: UIViewController {
```

画面は下記のようなものでテキストのみ共有するようにしました。(上下に `TextView` を置いています。上が共有文字列で下はまだ実装中)

<img width="300" alt="share_ios_screen" src="https://user-images.githubusercontent.com/34936885/74103996-f4597300-4b93-11ea-8143-97759b71c0a2.png">

# 共有メニューに表示されない
なぜか共有メニューにアプリが表示されない時がありました:scream:

```xml:info.plist
<key>NSExtensionAttributes</key>
<dict>
 <key>NSExtensionActivationRule</key>
 <dict>
  <key>NSExtensionActivationSupportsText</key>
  <true/>
 </dict>
</dict>
```

上記のようにしてると共有メニューに表示されず[参考記事](https://qiita.com/lovee/items/67906ec593ebd91d608d#share-extension-%E5%AF%BE%E5%BF%9C)のように SUBQUERY にすると表示されるようになりました:tada:

```xml:info.plist
<key>NSExtensionActivationRule</key>
 <string>SUBQUERY (extensionItems,$extensionItem,
  SUBQUERY ($extensionItem.attachments,$attachment,
    (ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.text" 
    || ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.plain-text")
  ).@count == $extensionItem.attachments.@count).@count == 1
 </string>
```

# 画面が閉じれない
| iOS | Mac |
| --- | --- |
|<img width="300" alt="share_ios_screen" src="https://user-images.githubusercontent.com/34936885/74103996-f4597300-4b93-11ea-8143-97759b71c0a2.png">|<img width="300" alt="share_mac_screen" src="https://user-images.githubusercontent.com/34936885/74104061-79dd2300-4b94-11ea-8e78-f81042b7e960.png">|

上記のように iOS 版は半モーダルなので下にスワイプすれば閉じれますが Mac 版の場合は閉じることができません:scream:

こちらも[参考記事](https://qiita.com/lovee/items/67906ec593ebd91d608d#share-extension-%E5%AF%BE%E5%BF%9C)に閉じる方法が書いてありました:heart_eyes:

閉じるボタンを用意して下記のようにすれば閉じることができました:tada:

```swift
@IBAction private func cancel(_ sender: Any) {
  extensionContext!.completeRequest(returningItems: nil, completionHandler: nil)
}
```

# 共有メニューのローカライズ
| iOS | Mac |
| --- | --- |
|<img width="300" alt="share_ios" src="https://user-images.githubusercontent.com/34936885/74103987-e99ede00-4b93-11ea-8106-f5e884cb9b0b.png">|<img width="300" alt="share_mac" src="https://user-images.githubusercontent.com/34936885/74104015-0fc47e00-4b94-11ea-8d79-61ca53666dd7.png">|

上記のように iOS 版は共有メニューにもアプリのターゲットで設定した Display Name が表示されます（ローカライズも対応）が Mac 版は Share Extension のターゲットで設定した Display Name が表示されています:scream:

Share Extension のターゲットに InfoPlist.strings を下記のように追加しました。

```swift:InfoPlist.strings
CFBundleDisplayName = "DNA Converter"; // (Japaneseの方は "DNA変換" と設定)
```

これで Mac版 でもアプリ同様共有メニューにも日本語表示なら「DNA変換」英語表記なら「DNA Converter」と表示されるようになりました:tada:（どっかに変数を設定してアプリのターゲットと共通化すべきなのかも?）

# 共有した値が取得できない
致命的なのですが Mac 版で共有した値が取得できませんでした:scream:

共有したテキストの取得処理は下記のように実装しました。

```swift
let extensionItem: NSExtensionItem = extensionContext?.inputItems.first as! NSExtensionItem
guard let itemProvider = extensionItem.attachments?.first else {
  // ここでなんかエラー処理
  return
}

let publicText = String(kUTTypeText)  // "public.text"
if itemProvider.hasItemConformingToTypeIdentifier(publicText) {
  itemProvider.loadItem(forTypeIdentifier: publicText, options: nil, completionHandler: { (data, error) in
    guard let text = data as? String else {
      // ここでなんかエラー処理
      return
    }
    // ここでなんか処理
  })
  return
}

let publicPlainText = String(kUTTypePlainText)  // "public.plain-text"
if itemProvider.hasItemConformingToTypeIdentifier(publicPlainText) {
  itemProvider.loadItem(forTypeIdentifier: publicPlainText, options: nil, completionHandler: { (data, error) in
    guard let text = data as? String else {
      // ここでなんかエラー処理
      return
    }
    // ここでなんか処理
  })
  return
}

// ここでなんかエラー処理
```

iOS では下記のように `extensionContext?.inputItems.first` の `NSExtensionItemAttachmentsKey` に値が入っているのですが

```swift
 po extensionContext?.inputItems
▿ Optional<Array<Any>>
  ▿ some : 1 element
    - 0 : <NSExtensionItem: 0x6000007e4260> - userInfo: {
    NSExtensionItemAttachmentsKey =     (
        "<NSItemProvider: 0x600002edc690> {types = (\n    \"public.plain-text\"\n)}"
    );
    NSExtensionItemAttributedContentTextKey = {length = 317, bytes = 0x7b5c7274 66315c61 6e73695c 616e7369 ... 20417070 6c65207d };
    "com.apple.UIKit.NSExtensionItemUserInfoIsContentManagedKey" = 0;
}
```

Mac では下記のように値が入っていません...

```swift
po extensionContext?.inputItems
▿ Optional<Array<Any>>
  ▿ some : 1 element
    - 0 : <NSExtensionItem: 0x6000018d45c0> - userInfo: {
    NSExtensionItemAttachmentsKey =     (
    );
    NSExtensionItemAttributedContentTextKey = {length = 315, bytes = 0x7b5c7274 66315c61 6e73695c 616e7369 ... 30204170 706c657d };
}
```

色々試してみましたが Mac 版では値が取得できませんでした。`extensionContext?.inputItems.first` の `NSExtensionItemAttributedContentTextKey` からがんばれば取得できそうですがなんか違うと思いあきらめました。

ここにきて思ったのが Mac 版だけ動作がおかしいのでそもそも Share Extension が Mac に対応してないんじゃね？という疑惑です。（なんか知ってる人いたら教えて下さい）

ということで私は Mac 版の Share Extension はあきらめました:confused:

# Mac版で取得できた値(20200211追記)
コメントでURLは取れると聞いたので他の値が取れるかみてみました。

info.plist を下記に設定して `extensionContext?.inputItems` をログで出してみました。

```xml:info.plist
<key>NSExtensionAttributes</key>
<dict>
  <key>NSExtensionActivationRule</key>
  <string>TRUEPREDICATE</string>
</dict>
```

## URL

```swift
▿ Optional<Array<Any>>
  ▿ some : 1 element
    - 0 : <NSExtensionItem: 0x6000013e8660> - userInfo: {
    NSExtensionItemAttachmentsKey =     (
        "<NSItemProvider: 0x600003aeddc0> {types = (\n    \"public.url\"\n)}",
        "<NSItemProvider: 0x600003aedea0> {types = (\n    \"public.image\"\n)}"
    );
}
```

## Image

```swift
▿ Optional<Array<Any>>
  ▿ some : 1 element
    - 0 : <NSExtensionItem: 0x600002034630> - userInfo: {
    NSExtensionItemAttachmentsKey =     (
        "<NSItemProvider: 0x60000092f3a0> {types = (\n    \"public.image\"\n)}"
    );
}
```

## Movie

```swift
▿ Optional<Array<Any>>
  ▿ some : 1 element
    - 0 : <NSExtensionItem: 0x6000013d1ef0> - userInfo: {
    NSExtensionItemAttachmentsKey =     (
        "<NSItemProvider: 0x600003ae0230> {types = (\n    \"com.apple.quicktime-movie\",\n    \"public.file-url\",\n    \"public.url\"\n)}"
    );
}
```

## PDF

```swift
▿ Optional<Array<Any>>
  ▿ some : 1 element
    - 0 : <NSExtensionItem: 0x6000013c54f0> - userInfo: {
    NSExtensionItemAttachmentsKey =     (
        "<NSItemProvider: 0x600003ae43f0> {types = (\n    \"public.url\"\n)}",
        "<NSItemProvider: 0x600003ae5ff0> {types = (\n    \"com.adobe.pdf\"\n)}"
    );
}
```

## まとめ
| Type | 結果 |
| --- | --- |
| text | :x: |
| url | :o: |
| image | :o: |
| movie | :o: |
| pdf | :o: |

テキストだけ取れない:poop:

# さいごに
Mac 版はなにか特殊な設定がいるんでしょうか？調べた限り有力な情報は得られませんでした...

情報求ム!!