Help us understand the problem. What is going on with this article?

Share Extensionのハマりポイント

はじめに

初の個人アプリを App Store に審査出したら 30 分足らずでリリースされてビビったからその全てをお伝えしますの記事を見てShare Extensionいいなぁと思い自分のアプリにもつけてみよう!と思ったのですが色々ハマりました...

対象

  • iOS13.0以上
  • macOS Catalina

Share Extensionの実装

ここを参考に実装をしました。

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

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

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

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

share_ios_screen

共有メニューに表示されない

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

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

上記のようにしてると共有メニューに表示されず参考記事のように SUBQUERY にすると表示されるようになりました:tada:

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
share_ios_screen share_mac_screen

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

こちらも参考記事に閉じる方法が書いてありました:heart_eyes:

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

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

共有メニューのローカライズ

iOS Mac
share_ios share_mac

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

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

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

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

共有した値が取得できない

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

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

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.firstNSExtensionItemAttachmentsKey に値が入っているのですが

 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 では下記のように値が入っていません...

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.firstNSExtensionItemAttributedContentTextKey からがんばれば取得できそうですがなんか違うと思いあきらめました。

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

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

Mac版で取得できた値(20200211追記)

コメントでURLは取れると聞いたので他の値が取れるかみてみました。

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

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

URL

 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

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

Movie

 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

 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 版はなにか特殊な設定がいるんでしょうか?調べた限り有力な情報は得られませんでした...

情報求ム!!

am10
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした