Swift Playgrounds のアプリに plist ファイルを適応して機能を追加する 

# 初めに

まず最初に **Xcode の Playground とは違います** のでmm
今回は **Swift Playgrounds** でアプリを開発する場合のお話です。



## Swift Playgrounds とは

2016年に登場した iPad 上で Swift を学習できるアプリです。

https://www.apple.com/jp/swift/playgrounds/


当初はテンプレートの教材を Swift で学習するだけでした。

現在はバージョンが`4.1`までリリースされており、iPad のみならず Mac 上でも動作し、**実際にリリースできるアプリが作成できる**までになりました。

## どんなことができるの？

iOSDC Japan 2022 で LT をしました！
資料をあげたので、見ていただけると少しは理解が深まるかと思いますmm

https://speakerdeck.com/hcrane/iosdc2022-ipadosdc-japan-2022


# plist ファイルによる機能の拡張

## 0. 前提

Swift Playgrounds のアプリでは `info.plist` は存在しません。
`Package.swift` で多くのことが管理されます。

通常、機能の追加をする場合は GUI 上から行います。


![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/c0e8a2b6-a8a9-c5cc-c77f-1594dad5f2c0.png)


機能を追加すると `Package.swift` に追加されます。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/8695f2bc-c228-eeb3-baad-92be43e8631f.png)

## 1. 問題

GUI で追加できる機能は以下になります。
（内部コードより。 v4.0なので少しだけ古いです。）

```.swift
public enum Capability : Swift.Equatable, Swift.Encodable {
      case appTransportSecurity(configuration: PackageDescription.ProductSetting.IOSAppInfo.AppTransportSecurityConfiguration, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case bluetoothAlways(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case calendars(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case camera(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case contacts(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case faceID(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case localNetwork(purposeString: Swift.String, bonjourServiceTypes: [Swift.String]? = nil, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case locationAlwaysAndWhenInUse(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case locationWhenInUse(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case mediaLibrary(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case microphone(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case motion(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case nearbyInteractionAllowOnce(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case photoLibrary(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case photoLibraryAdd(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case reminders(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case speechRecognition(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      case userTracking(purposeString: Swift.String, _: PackageDescription.ProductSetting.IOSAppInfo.DeviceFamilyCondition? = nil)
      public static func == (a: PackageDescription.ProductSetting.IOSAppInfo.Capability, b: PackageDescription.ProductSetting.IOSAppInfo.Capability) -> Swift.Bool
}
```

名前からなんとなく予想できるかと思います。

問題として**ここにないものは追加しようがありません**。実際、追加できない機能がいくつか存在します。また、それ以外にも今までの Xcode プロジェクトにあった `info.plist` の設定などは追加のしようがありません。

## 2. 独自 plist の追加

そこで便利なのが、`additionalInfoPlistContentFilePath` の引数を使うことです。
![Screen Shot 2022-09-08 at 4.46.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/66f5da99-222b-ffa5-d7cc-bb746c4709fe.png)

詳しく見たい方は以下のパスから

```
/Applications/Xcode.app/Contents/PlugIns/IDESwiftPackageCore.framework/Versions/A/Frameworks/SwiftPM.framework/
```

自信で追加したい機能や設定を、独自の `plist` として作成し、それを読み込ませます。
![Screen Shot 2022-09-08 at 4.46.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/09d68275-3859-5df6-8b03-d287fb32f457.png)

こうすることで、最終的な成果物は、`Package.swift` と `plist` が**合成されたもの**になります。

（同じ設定を追加した場合はどちらが優先されるかはわかりません。どなたかテストした人がいれば情報お願いしますmm）

## 例外

`iCloud` の機能のみ、現状追加しようがないようです。
（他の機能もあれば情報お願いしますmm）

おそらく、Swift Playgrounds が `iCloud` で管理することを想定しているツールのため、問題が起きないように、自信からはアクセスできないようになっているのだと思います。

# 終わりに

時間が経てば、GUI に機能が増えてくると思うので、いったん足りない機能は拡張して補っていくと言う形になると思います。

なんだかんだで代わりの手段を用意してくれている Apple さん、ありがたや🙏


## リポジトリ


以下に導入したアプリがあるので、参考程度に見ていただけますと🙏

https://github.com/crane-hiromu/PadOSDC_Japan_App


## その他

関連記事はこちら

https://qiita.com/hcrane/items/4b287e9b9cddd0106572

https://qiita.com/hcrane/items/10d5d579ea7f9bc935e9

https://qiita.com/hcrane/items/7a422bdf76091befc8c4


## 参考文献

https://skyaaron.com/posts/swiftpm-app-projects/

https://gist.github.com/treastrain/2f21d42c360dc9b9876ddde125abe247