はじめに
他のアプリから自分のアプリを立ち上げて何かの入力を促すという操作を行いたい場合
share extensionを利用することがあります。
今回はreceive_sharing_intentを利用したので、それの覚書です。
share_extentionというサンプルアプリを作成し、これを様々なアプリから開くようなサンプルを作りたいと思います。
実装
1.receive_sharing_intent 1.4.0+2
2.プロジェクトの作成
$ flutter create share_extensin
$ cd share_extension
3.install
dependencies:
flutter:
sdk: flutter
receive_sharing_intent: ^1.4.0+2
4.main.dartの修正
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
StreamSubscription _intentDataStreamSubscription;
List<SharedMediaFile> _sharedFiles;
String _sharedText;
@override
void initState() {
super.initState();
//アプリが起動されている状態で呼ばれた時、ここからURLが入ってくる
_intentDataStreamSubscription =
ReceiveSharingIntent.getTextStream().listen((String value) {
setState(() {
_sharedText = value;
});
}, onError: (err) {
print("getLinkStream error: $err");
});
// アプリが起動されていない状態で呼ばれた時、ここからURLが入ってくる
ReceiveSharingIntent.getInitialText().then((String value) {
setState(() {
_sharedText = value;
});
});
}
@override
void dispose() {
_intentDataStreamSubscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
const textStyleBold = const TextStyle(fontWeight: FontWeight.bold);
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
children: <Widget>[
Text("Shared urls/text:", style: textStyleBold),
Text(_sharedText ?? "")
],
),
),
),
);
}
}
5.XCodeでプロジェクトを開く
open ios/Runner.xcodeproj/
6.Xcodeで、ShareExtensionのディレクトリを作成する
ツールバーからFile > New > Targetを選択し、表示されたダイアログからShare Extensionを選択

ProductNameにはMyShareExtensionと入力する。(別に名前はなんでも良い。サービス名+ShareExtensionとかだとわかりやすくて良いかも)
-> サイドバーとTARGETSにMyShareExtensionという項目が出現する

6.5 RunnerとMyShareExtensionのBundleIdentifierを確認する
RunnerとExtensionのBundleIdentifierが同じPrefixになるように設定しておく
Runner:
jp.ne.test.share_xtension
MyShareExtension:
jp.ne.test.share_extension.MyShareExtension
(memo)
これはbuild時に
Embedded binary's bundle identifier is not prefixed with the parent app's bundle identifier.
と言われるため
https://qiita.com/koogawa/items/432b9c65035b6ba17c8b
7 Runner/Info.plistを編集する
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>ShareMedia</string>
</array>
</dict>
<dict/>
</array>
<key>NSPhotoLibraryUsageDescription</key>
<string>To upload photos, please allow permission to access your photo library.</string>
8.MyShareExtension/Info.plistを修正する
若干面倒くさいのが、ShareExtensionを利用したいアプリから、自分のアプリが見えるかどうかが
このinfo.plistの書き方によって、変わってくる。
例えば、primevideのアプリから、自分が作ったshare_extensionというアプリを開きたい場合、
下記のように自分のアプリが出てくることが期待されるが、ここに表示されないことがある。
この場合、info.plistのNSExtensionActivationRuleに記載が足りていないケースがある。
(期待されるRuleはアプリによって異なるため、自分が呼び出したアプリによって見直す必要がある)
debug.info.plistの事例のようにTRUEPREDICATEを指定すると、必ず出てくるようになるので、
最初の確認は、TRUEPREDICATEを指定すると良い。
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<string>TRUEPREDICATE</string>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsTextWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
間違えると..
App Store Connect Operation Error
ERROR ITMS-90362: "Invalid Info.plist value. The value for the key >'NSExtensionActivationRule' in bundle >Runner.app/PlugIns/OrquestShareExtension.appex is invalid.
と怒られます..
9.RunnerとMyShareExtensionを同じApp Groupに登録する
Signing & Capabilities -> +CapabilityボタンApp Groupsを選択。
App Groupsという項が表示されるので、Group名を入力する。(この画面の赤色になっている部分)
グループ名はgroup. + RunnerのBundlerIdentifier。
同じようにTARGETS/MyShareExtensionにもグループ名を設定する。
9.MyShareExtension/ShareViewController.swiftを修正する
今回はURLをシェアしたいだけなので最低限これだけでok。他にも使いたい場合は、
https://pub.dev/packages/receive_sharing_intent
を参考にdidSelectPost()に条件を増やしていく。
import UIKit
import Social
import MobileCoreServices
import Photos
class ShareViewController: SLComposeServiceViewController {
let hostAppBundleIdentifier = "jp.ne.sakura.oggata.share-extension"
let sharedKey = "ShareKey2"
var sharedText: [String] = []
let urlContentType = kUTTypeURL as String
override func isContentValid() -> Bool {
return true
}
override func viewDidLoad() {
}
override func didSelectPost() {
if let content = extensionContext!.inputItems[0] as? NSExtensionItem {
if let contents = content.attachments {
for (index, attachment) in (contents).enumerated() {
if attachment.hasItemConformingToTypeIdentifier(urlContentType) {
handleUrl(content: content, attachment: attachment, index: index)
}
}
}
}
}
private func handleUrl (content: NSExtensionItem, attachment: NSItemProvider, index: Int) {
attachment.loadItem(forTypeIdentifier: urlContentType, options: nil) { [weak self] data, error in
if error == nil, let item = data as? URL, let this = self {
this.sharedText.append(item.absoluteString)
if index == (content.attachments?.count)! - 1 {
let userDefaults = UserDefaults(suiteName: "group.\(this.hostAppBundleIdentifier)")
userDefaults?.set(this.sharedText, forKey: this.sharedKey)
userDefaults?.synchronize()
this.redirectToHostApp(type: .text)
}
}
}
}
private func redirectToHostApp(type: RedirectType) {
let url = URL(string: "ShareMedia://dataUrl=\(sharedKey)#\(type)")
var responder = self as UIResponder?
let selectorOpenURL = sel_registerName("openURL:")
while (responder != nil) {
if (responder?.responds(to: selectorOpenURL))! {
let _ = responder?.perform(selectorOpenURL, with: url)
}
responder = responder!.next
}
}
enum RedirectType {
case media
case text
case file
}
}
10 pod install
cd ./ios
pod install
10.Build Settings > Enable BitcodeをNO
実機にインストールするときに下記のようなエラーになる..
ld: 'ライブラリ名' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE)
https://qiita.com/imanishisatoshi/items/8b64af8262d7fe2eb2ba
11. provisioning profileにAppGroupを付け加える
Conclution
おしまい




