ShareExtensionのNSExtensionActivationRuleに複雑な条件を指定する
はじめに
Flutterでブックマークアプリのようなアプリを開発した際に、SafariやChromeの共有メニューにはアプリアイコンが表示されるのに、GoogleやYahooといったアプリの共有メニューには表示されない、といったことがあったので、ShareExtensionの設定まわりを調査しました。
※ 後述の記事を参考に自分の理解をまとめたものなので、誤りがあるかもしれません。
結論
はじめに結論を書いておくと、NSExtensionActivationRule
に複雑な条件を指定するには、NSExtensionActivationRule
にSUBQUERY
を使って条件を指定します。指定したSUBQUERY
の条件に合う場合のみ、共有メニューにアプリアイコンが表示されるようになります。
<key>NSExtensionActivationRule</key>
<string>
SUBQUERY (
extensionItems,
$extensionItem,
SUBQUERY (
$extensionItem.attachments,
$attachment,
(
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url"
)
).@count == 1
).@count == 1
</string>
基本的な設定方法
受入を許可するデータタイプをNSExtensionActivationRule
に1つずつ設定します。
デフォルトでは、NSExtensionActivationRule
にTRUEPREDICATE
が設定されていて、すべてのデータタイプを受入可能になっています。しかし、この設定のままでは審査の際にリジェクトされてしまうそうなので、データタイプごとに1つ1つ許可する必要があります。
以下の例では、NSExtensionActivationSupportsText
とNSExtensionActivationSupportsWebURLWithMaxCount
が設定してあり、データタイプがテキストまたはURLの場合のみ、ShareExtensionが有効になります(アイコンが表示されるようになる)。
例えば、テキストを選択した際に表示される共有メニューではテキスト、Safariなどのブラウザの共有ボタンを押した時はURLを受け取ることが可能です。
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<!-- すべてのデータタイプを受け入れる設定。リジェクトされる -->
<!-- <string>TRUEPREDICATE</string> -->
<dict>
<!-- テキストデータを受け入れる -->
<key>NSExtensionActivationSupportsText</key>
<true/>
<!-- URLデータを1つまで受け入れる -->
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
その他に設定可能な項目は以下を参照してください。
App Extension Keys
複雑な条件が必要だった理由
自分が作成したブックマークアプリではURLを必要としていたため、NSExtensionActivationSupportsWebURLWithMaxCount
のみを設定しており、SafariやChromeなど、自分が普段使う数種類のアプリの共有メニューにはアイコンが正しく表示されていました。
しかし、ある時GoogleやYahooといったアプリではアイコンが表示されないということがわかり、調べてみたところYahoo,EdgeなどのアプリではURLとテキストを渡そうとしていたため、URLを1つだけ許可するという条件に合致せずにShareExtensionが有効になっていないということがわかりました。(GoogleアプリはURLしか渡していなさそうだったのに何故かダメでした)
そのため、NSExtensionActivationSupportsText
を設定したところ、GoogleやYahooのアプリの共有メニューからもShareExtensionが使えるようになりました。
しかし、この状態だと適当な文章を選択したときに表示される共有メニューからもShareExtensionが使えてしまい、URLを期待しているアプリからすると、URLなのかそうでない文字列が渡されてくるのかわからないといった問題があります。そのため、データタイプがURLの時だけアクティブになり、データタイプが複数渡されてもOK、というような条件にしたく、調査をしました。
複雑な条件を指定する
いろいろな方の記事を見て、最終的には以下のように設定しました。
②のSUBQUERYのANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url"
は、attachment
のデータタイプ(registeredTypeIdentifiers
)のいずれかがpublic.url
であるという条件で、②を実行すると、データタイプにpublic.url
を含むデータが得られます。残りの@count == 1
はデータが1つであることを意味していますが、URLが複数ある場合もあるかもしれないので、変える必要が出てくるかもしれません。
①のSUBQUERYは、extensionItems
の中で条件②を満たすものが1つである、という条件ですが、経験上extensionItems
が1以外だったことがないので、どんなときに複数になるのかはわかっていません。
ANY
とかUTI-CONFORMS-TO
などのキーワードの説明は以下に記載されています。
Predicate Format String Syntax
データタイプの一覧は下記を参照してください。
System-Declared Uniform Type Identifiers
<key>NSExtensionActivationRule</key>
<string>
SUBQUERY ( ・・・ ①
extensionItems,
$extensionItem,
SUBQUERY ( ・・・ ②
$extensionItem.attachments,
$attachment,
(
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url"
)
).@count == 1
).@count == 1
</string>
Discussion