【SwiftUI】iOS16.0 以降で使える ShareLinkでできることを調べてみた

iOS16 からSwiftUIで共有シートが実装できるようになった模様です。やった！
ちょうど共有機能をつけたいアプリがあり、その実装をしたのでできることを調べてみました。

https://developer.apple.com/documentation/SwiftUI/ShareLink

# 環境

- Xcode 14.2
- iPhone 13 mini（16.2）
- iPhone 14 Pro（16.2）

# できること

5パターン試してみたので、そのGIFを載せます。

<img width="300" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401966/88b511bf-7c27-9910-3785-e9ead76394a9.gif">

コード全体はこちらに置いています。

https://github.com/kamimi01/ShareLinkTest


## 1. リンクのみ

リンクのみの場合は、システム標準のUIになります。


```swift
VStack(alignment: .leading) {
    Text("1. システム標準の外観（リンクのみ）")
    ShareLink(item: URL(string: "https://developer.apple.com/xcode/swiftui/")!)
}
```

## 2. リンクのタイトルをカスタマイズ

```swift
VStack(alignment: .leading) {
    Text("2.リンクのタイトルだけをカスタマイズ")
    ShareLink("リンクのタイトル", item: URL(string: "https://developer.apple.com/xcode/swiftui/")!)
}
```

## 3. リンクの外観全体をカスタマイズ

```swift
VStack(alignment: .leading) {
    Text("3.リンクの外観全体をカスタマイズ")
    ShareLink(item: URL(string: "https://developer.apple.com/xcode/swiftui/")!) {
        HStack {
            Image(systemName: "personalhotspot")
            Text("共有ボタン")
        }
        .foregroundColor(.red)
    }
}
```

## 4. 独自の型を渡し、プレビューもカスタマイズ

`Transferable`型に準拠すれば、独自の型を渡すことができます。

```swift
// Transferableに準拠した型を定義
struct Photo: Transferable {
    static var transferRepresentation: some TransferRepresentation {
        ProxyRepresentation(exporting: \.image)
    }

    public var image: Image
    public var caption: String
}
```

またプレビューはリンクを共有する場合、デフォルトではプレースホルダーのリンクアイコン画像とネットワーク経由で取得したリンクのメタデータを表示するそうです。

このデフォルトを使わず、自分でプレビューを設定することができます。

```swift
VStack(alignment: .leading) {
    Text("4.Transferableに準拠した独自の型を渡し、プレビューもカスタマイズ")
    ShareLink(
        item: photo,
        preview: SharePreview(
                     photo.caption,
                     image: photo.image))
}
```


## 5. サブジェクトとメッセージを追加

共有するアプリによっては対応していないものもありますが、サブジェクトとメッセージのテキストを共有することもできます。

```swift
let photo = Photo(image: Image("people"), caption: "人々のアイコン")
・・・
VStack(alignment: .leading) {
    Text("5.サブジェクトとメッセージを追加")
    ShareLink(
        item: photo,
        subject: Text("Cool Photo"),
        message: Text("Check it out!"),
        preview: SharePreview(
                     photo.caption,
                     image: photo.image))
}
```

# アプリによって違う共有できるデータ

今回、独自の型を使った`Photo`で他のアプリにデータを共有しようとしたとき、何を共有できるのか調べてみました。アプリによって受け取る値に違いはありましたが、全部を受け取ってくれるアプリは調査した中ではありませんでした。

|共有したいデータ（↓）/アプリ（→）|コピーして標準メモアプリに貼り付け|標準メモアプリ|標準メールアプリ|Slack|Twitter|LINE|
|---|---|---|---|---|---|---|
||![IMG_1863.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401966/837f0f9b-0829-81e6-edc5-7b4163c67cb7.png)|![IMG_1862.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401966/84542a04-75ce-a5a0-5a5d-a874bca50ebb.png)|![IMG_1866 2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401966/2f18bc0f-4d69-564b-39c2-edf27c2646e5.png)|![IMG_1865.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401966/fe7d73a3-b256-7f9a-ea63-59011fd8982a.png)|![IMG_1867.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401966/83db6510-7828-aac7-1623-5bcb72ad838c.png)|![IMG_1861.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401966/d8c4191c-6939-7f2d-9952-9dee32edfd6b.png)|
|`Photo`構造体が持つ`caption`のテキスト<br>（「人々のアイコン」）|❌|❌|❌|❌|❌|❌|
|`Photo`構造体が持つ`image`の画像|✅|✅|✅|❌|✅|✅|
|サブジェクト<br>（「Cool Photo」）|❌|❌|✅|❌|❌|❌|
|メッセージ<br>（「Check it out!」）|✅|❌|✅|✅|✅|✅|

一番共有される可能性が高いのは、`image`の画像とメッセージでした。サブジェクトに対応しているのはこの中では標準メールアプリだけでしたね。あと独自の型で定義した`caption`もなかなか共有されませんね・・・なんでなんでしょうか・・・そこまで分かりませんでした。。

コピーしてメモアプリに貼った時と標準メモアプリに直で共有した時とで、どうして共有されるデータが違うの？と思ったりしました。。🙃


# 困ったこと（未解決）

未解決なのですが、実装中に不思議な事象が発生しました。

## プレビューに設定した画像が逆さまに表示されることがある

共有シートに表示されるプレビューに設定した画像が逆さまになることがありました。。今のところシミュレータとXcodeプレビューで発生しており、実機では発生していないですがたまたまかもしれません。。
理由はまだわかっていませんが、公式ドキュメントの通り実装しており何か特殊なことはしていないので、不具合なのでしょうか？ 🤔


<img width="300" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401966/c3fd85af-b916-4f04-950d-b1b5f213f615.png">

# おわりに

初めてShareLinkを触ってみました。実装したことがなかったのですが、SwiftUIがデフォルトで提供してくれていることにより簡単に実装できました。

ところで標準メモアプリの共有ボタンを押した時の共有シートのプレビューは結構複雑ですが、あれはSwiftUIのShareLinkだけでは無理そうですよね。相変わらず複雑なプレビューを実装したい場合は今回のこのShareLinkは向いていなそうだなという想像をしました。

UIKit側の実装もいつか触ってみたいです。


# 参考

改めて公式ドキュメント。
全部ではないですが、一部不完全なコードが載っていました。ブラケットが足りないレベルのミスですが。

https://developer.apple.com/documentation/SwiftUI/ShareLink

UIKit側のも少し読みました。

https://qiita.com/ezura/items/6036c6e100599b601482