LASSIC Media らしくメディア
アプリに共有機能(Share Extension)を実装、外注
LASSIC IT事業部|元請(プライムベンダー)としてシステム保守・運用を受託
この記事のポイント
- アプリの共有機能には、他アプリのコンテンツを受け取る方向と、自社アプリから外へ送る方向の2種類があります。
- iOSはApple公式のShare Extension・UIActivityViewController、AndroidはGoogle公式のintent-filter・ACTION_SENDでそれぞれ実現します。
- OSごとに仕組み・審査要件・データ共有方法が異なるため、対応範囲の見極めが外注判断の材料になります。
目次
- 共有機能(Share Extension)実装とは、受信と送信の2方向を指す
- 業務アプリで共有機能が求められる場面――写真・URL・ファイルの受け渡し
- iOSで受け取る仕組み――Share Extension(App Extension)の内部構造
- iOSで送る仕組み――UIActivityViewController(共有シート)の実装
- Androidの受信と送信――intent-filterとACTION_SEND・Sharesheet
- 拡張機能と本体アプリのデータ橋渡し――App Groupsと共有ストレージ
- 実装で見落としやすい落とし穴――権限・審査・型不一致のリスク
- 内製と外注の分かれ目――対応OS・想定用途で工数が変わる
- まとめ:アプリの共有機能実装で押さえる3つの判断軸
- よくある質問
共有機能(Share Extension)実装とは、受信と送信の2方向を指す
アプリの共有機能(Share Extension)実装とは、他アプリのコンテンツを自社アプリに取り込む仕組みと、自社アプリのコンテンツを他アプリへ送る仕組みの両方を指します。iOSではApp Extension(アプリの機能をシステムの他の場所に拡張する仕組み)の一種であるShare Extensionと、共有シートを呼び出すUIActivityViewControllerでそれぞれ実現します*1*2。Androidではintent-filterによるACTION_SEND受信と、Android Sharesheet(システム標準の共有UI)への送信で実現します*4*5。
両方向は実装するAPIも審査で見られる観点も異なります。受信側はコンテンツを受け取った後の処理設計、送信側は渡すデータの種類と権限設計が要点です。次章以降、業務アプリでの使われ方からOSごとの実装、外注判断の材料まで順に整理します。
業務アプリで共有機能が求められる場面――写真・URL・ファイルの受け渡し
業務アプリで共有機能が求められる場面は、社内ツール間や外部サービスとの情報の受け渡しです。現場で撮影した写真をメールアプリやチャットツールから直接自社の業務アプリへ取り込みたい、あるいは業務アプリ内のレポートをSNSや社外の共有ツールへ送りたいという要望が典型です。
受信側の例では、ブラウザで見ているWebページのURLを共有シートから業務アプリに送り、案件メモとして保存する使い方があります。ファイル管理アプリからPDFやCSVを受け取り、承認フローに乗せる設計も同じ仕組みによるものです。送信側の例では、業務アプリで作成した画像や資料を、社内で使っているチャットアプリやメールへワンタップで渡す用途が挙げられます。
いずれの場面も、OSが用意する共有の仕組みに乗ることが前提です。独自の共有UIを一から作ると、ユーザーが慣れた操作感から外れ、対応できるアプリの数も限られます。次章からはiOS・Androidそれぞれの実装方式を、公式情報に基づいて確認します。
iOSで受け取る仕組み――Share Extension(App Extension)の内部構造
App Extensionとしての位置づけとInfo.plist設定
Share Extensionは、ユーザーがコンテンツを他サービスへ共有するための標準的な手段を提供するApp Extensionです*1。Xcodeが提供するShareテンプレートでは、Info.plistのNSExtensionPointIdentifierに「com.apple.share-services」を指定し、システムに対して自分がShare Extensionであることを示します*1。ユーザーが他アプリで共有ボタンをタップすると、システムのアクティビティビュー内にこの拡張機能が表示される仕組みです*1。
NSExtensionContextとNSExtensionActivationRule
拡張機能本体は、標準UIを使う場合はSLComposeServiceViewControllerを、独自UIを使う場合はUIViewControllerを継承したクラスを実装します*1。ホストアプリから渡された共有元のテキストや添付データは、extensionContext.inputItemsを通じて取得します*1。取得できるのはNSExtensionItemの配列で、添付ファイルはNSItemProvider(受け渡すデータの型と読み込み処理をまとめたオブジェクト)として保持されます*1。
どの種類のコンテンツに対して自分の拡張機能を表示するかは、NSExtensionAttributes内のNSExtensionActivationRuleという条件式で制御します。この設定を絞り込まないと、対応できない形式のコンテンツに対しても拡張機能が表示され、ユーザー体験を損ねかねません。画像何枚まで・URL1件のみ、といった条件を明示することが実務上重要です。
コンテンツの検証と処理完了の通知
ユーザーが投稿操作を行うと、isContentValidメソッドで入力内容の妥当性を判定し、投稿ボタンの有効・無効を切り替えます*1。処理が完了したら、completeRequestReturningItems(withExtensionItems:completionHandler:)を呼び出してホストアプリに処理完了を通知します*1。この呼び出しを忘れると、拡張機能が終了せずユーザーが操作に詰まる原因になります。
iOSで送る仕組み――UIActivityViewController(共有シート)の実装
自社アプリから外部へコンテンツを渡す側は、UIActivityViewControllerを使います。これはiOS標準の共有・アクション画面を表示するビューコントローラーで、メール・メッセージ・SNS投稿・ファイル保存など、システムに登録された共有先の一覧をユーザーに提示します*2。
初期化時に渡すactivityItemsには、文字列・URL・UIImage・Data・NSItemProviderなど、共有したいコンテンツの配列を指定します*2。文字列とURLを両方渡すことで、テキストと画像を組み合わせた共有も実現できます。applicationActivitiesを指定すれば、自社アプリ独自のアクションを共有シートの選択肢に追加することも可能です*2。
excludedActivityTypesを設定すると、業務用途に不要な項目(印刷やAirDropなど)を共有シートから除外できます。iPadでは、モーダル表示ではなくポップオーバーとして表示するための表示元(sourceView)の指定が別途必要になる点も、実装時に確認すべき差分です。
Androidの受信と送信――intent-filterとACTION_SEND・Sharesheet
受信側――マニフェストのintent-filterで対応形式を宣言する
Androidで他アプリからコンテンツを受け取るには、AndroidManifest.xmlのActivityにintent-filterを追加し、ACTION_SENDまたはACTION_SEND_MULTIPLEアクションと、対応するMIMEタイプ(データの種類を示す識別子。例:image/*、text/plain)を宣言します*5。category DEFAULTの指定も必須です*5。
受け取ったIntentの処理では、intent.actionとintent.typeを見て分岐します。テキストならEXTRA_TEXT、画像やファイルならEXTRA_STREAM(URI形式)から値を取得します*5。複数枚の画像を受け取る場合はACTION_SEND_MULTIPLEで、EXTRA_STREAMがURIの配列になる点が単数受信との違いです*5。
送信側――ACTION_SENDとcreateChooserでSharesheetを呼び出す
自社アプリから他アプリへコンテンツを渡す場合は、ACTION_SENDのIntentを組み立て、Intent.createChooserに渡してAndroid Sharesheetを表示します*4。Android開発者ガイドは、独自の一覧UIを作るよりもSharesheetを使う方法を推奨しています。理由は、システム全体で一貫した操作感が保たれ、利用頻度に応じたアプリの並び替えも自動で行われるためです*4。
テキストはEXTRA_TEXTとtype「text/plain」で渡せます*4。画像やファイルを渡す場合はEXTRA_STREAMにcontent://形式のURIを指定しますが、file://形式のパスをそのまま渡すことはできません*4。自社ファイルを他アプリに読み取り可能にするには、FileProvider(アプリ内ファイルを一時的に他アプリへ公開する仕組み)経由でcontent URIを発行し、FLAG_GRANT_READ_URI_PERMISSIONで読み取り権限を付与する必要があります*4。
拡張機能と本体アプリのデータ橋渡し――App Groupsと共有ストレージ
iOSのShare Extensionは、ホストアプリ本体とは別のプロセスとして動作し、処理が終わると同時にメモリ上のデータも失われます。受け取ったコンテンツをアプリ本体側で後から使いたい場合、App Groups(複数のアプリ・拡張機能で共有できる領域を割り当てるXcodeの機能)の設定が必要です*3。
App Groupsを有効にすると、共有識別子(group.com.example.appのような文字列)を使って、FileManagerのcontainerURL(forSecurityApplicationGroupIdentifier:)で共有コンテナのURLを取得できます*3。UserDefaults(suiteName:)を使えば、簡単な設定値も本体と拡張機能の間で共有できます*3。Xcodeの「Signing & Capabilities」でApp Groupsを追加し、本体アプリと拡張機能の両方に同じ識別子を設定することが前提になります*3。
Androidの場合、受信処理は拡張機能ではなく自社アプリ内のActivityが直接担うため、iOSのApp Groupsに相当する別プロセス間の共有機構は基本的に不要です。むしろ論点になるのは、送信時にFileProviderで発行するURIの権限範囲と有効期限の管理です*4。OSごとにデータ共有の課題そのものが異なる点は、設計初期に押さえておくべきポイントです。
実装で見落としやすい落とし穴――権限・審査・型不一致のリスク
共有機能の実装で失敗すると、単なる表示崩れでは済まないリスクがあります。iOSでNSExtensionActivationRuleの条件設定を誤ると、想定外のコンテンツ種別で拡張機能が共有シートに表示されなかったり、逆に対応できない形式でも表示されて処理が失敗する場合があるため、注意が必要です。App Storeの審査で、動作しない拡張機能が指摘され、リジェクトにつながる可能性もあります。
Androidでは、FileProviderの権限設定を誤ると、受け取り側のアプリでURIへのアクセスが拒否され、共有そのものが失敗します。EXTRA_STREAMに渡すURIのMIMEタイプと実際のファイル形式が一致していないと、受け取り側で意図しないアプリが起動したり、正しく処理されなかったりする場合もあります。
この作業を内製で担うには、複数領域の知識が要ります。iOS側はApp Extensionのターゲット構成・NSExtensionActivationRuleの条件記述・App Groupsのエンタイトルメント設定です。Android側はintent-filterの宣言・FileProviderの権限設計・URIパーミッションの扱いです*1*3*4*5。両OSでの実機検証を行える体制も欠かせません。
内製と外注の分かれ目――対応OS・想定用途で工数が変わる
共有機能そのものの実装手順はApple・Googleの両社が公式ドキュメントとして公開しているため、対応するコンテンツ種別が限られる場合は自社での実装を検討できる場合もあります*1*4。判断が分かれるのは、iOS・Android双方への対応が必要な場合や、受信・送信の両方向を業務フローに組み込む場合です。
専門パートナーに委託する場合は、対応OS・対応するコンテンツ種別(テキスト・画像・複数ファイルなど)・App Groupsによるデータ連携の要否まで、依頼範囲を具体的に洗い出せるかどうかが選定の分かれ目になります。内製では既存のモバイル開発担当者が通常業務と並行して対応することになり、iOS・Android両方の実機検証に割ける時間が限られる場合があります。
。対応OSの範囲や受信・送信のどちらを優先するかによって、必要な工数は変わってきます。現状の要件を整理したうえで、内製・外注の切り分けを検討することが実務的です。
まとめ:アプリの共有機能実装で押さえる3つの判断軸
本稿ではアプリの共有機能(Share Extension)実装について、公式情報をもとに整理しました。要点は3つに集約できます。第一に、共有機能には他アプリのコンテンツを受け取る方向と、自社アプリから外へ送る方向の2種類があり、iOSはShare ExtensionとUIActivityViewController、Androidはintent-filterとACTION_SENDでそれぞれ実現します*1*2*4*5。第二に、拡張機能とアプリ本体でデータを橋渡しする場合、iOSではApp Groupsの設定が必要になる一方、AndroidではFileProviderの権限設計が要点になります*3*4。第三に、対応OSの範囲や受信・送信のどちらを優先するかによって実装工数は変わり、内製と外注の判断材料になります。
よくある質問
Share ExtensionとUIActivityViewControllerはどう違いますか。
Share Extensionは他アプリのコンテンツを自社アプリで受け取るための仕組みで、App Extensionの一種として動作します*1。UIActivityViewControllerは反対に、自社アプリのコンテンツを他アプリへ送るために使う共有シートの呼び出しAPIです*2。役割が受信と送信で異なる点が主な違いです。
Androidで画像やファイルを共有するとき、URIをそのまま渡せますか。
file://形式のパスをそのままEXTRA_STREAMに渡すことはできません*4。FileProviderを使ってcontent://形式のURIを発行し、FLAG_GRANT_READ_URI_PERMISSIONで一時的な読み取り権限を付与する必要があります*4。この権限設計を誤ると、受け取り側のアプリでアクセスが拒否されます。
iOSの拡張機能で受け取ったデータを、アプリ本体側でも使えますか。
拡張機能はホストアプリ本体とは別プロセスで動作するため、処理終了後にメモリ上のデータは失われます*3。本体側で後から使いたい場合は、App Groupsで共有コンテナを設定し、FileManagerやUserDefaultsを介してデータを橋渡しする実装が必要です*3。
複数の画像やファイルをまとめて共有する場合、実装は変わりますか。
はい、Androidでは単数受信のACTION_SENDに対し、複数受信・送信にはACTION_SEND_MULTIPLEを使い、EXTRA_STREAMがURIの配列になります*5。iOSではNSExtensionActivationRuleで対応する枚数の上限などの条件を指定して制御します*1。単数と複数で扱うAPIとデータ構造が異なる点に注意が必要です。
共有機能の実装を外部に委託する場合、何を確認すればよいですか。
対応するOS(iOS・Androidの両方か一方か)、受信・送信のどちらを優先するか、対応するコンテンツ種別(テキスト・画像・複数ファイルなど)をまず確認します。加えてApp GroupsやFileProviderによるデータ連携の要否を委託先とすり合わせることが大切です。契約前に実機での検証範囲を明確にしておくと、リリース後のトラブルを抑えやすくなります。
著者:テレリモ総研編集部 鈴木 亮佑
ご不明な点はお問い合わせフォームからもご連絡いただけます。
- *1 出典:Apple「App Extension Programming Guide – Share and Action Extensions」(https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/Share.html)
- *2 出典:Apple Developer Documentation「UIActivityViewController」(https://developer.apple.com/documentation/uikit/uiactivityviewcontroller)
- *3 出典:Apple Developer Documentation「Configuring app groups」(https://developer.apple.com/documentation/xcode/configuring-app-groups)
- *4 出典:Android Developers「Send simple data to other apps」(https://developer.android.com/training/sharing/send)
- *5 出典:Android Developers「Receive simple data from other apps」(https://developer.android.com/training/sharing/receive)