アプリの動作環境ごとに「ファイル」からのディレクトリ内閲覧許諾を切り替える

この記事は株式会社シンプルウェイ 2020 アドベントカレンダーの参加記事です。
https://qiita.com/advent-calendar/2020/simpleway

## 概要

Xcodeプロジェクトにおいてinfo.plistに

* LSSupportsOpeningDocumentsInPlace
* UIFileSharingEnabled

をそれぞれtrueに設定することで、アプリ内ディレクトリの中を「ファイル」アプリで閲覧することができる。
検証環境でアプリを動かした際に、データが正しく保存されているか等確認するのに役に立つ。
一方で、本番でユーザーに閲覧されてしまうと、アプリ内ディレクトリのファイルの削除等も出来てしまうため、
アプリの意図しない動作を引き起こす可能性がある。
そのため、ビルド環境ごとに権限を切り替えるようにしたい。

--- 

## 前置き

ここでは、アプリの環境を

* 開発：Debug
* 検証：Staging
* 本番：Release

の3つが存在するとして進めます。

## 方法

普通、info.plistの値を環境毎に切り替えるには、
Build Settings内でUser-Definedパラメータを追加して、その値をinfo.plistの値に紐付ければよい。
だが、User-DefinedパラメータにBool値を持たせることができないため、この方法が使えない。

そのため、アプリのビルド時にスクリプトでinfo.plistを書き換える必要がある。

### 手順① PreProcess info.plistを有効にする

Build SettingsのPackages項目の「Preprocess info.plist File」パラメータをYESにする

![preprocess.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911364/a78fe1f8-78c2-1ea1-bd1a-1a7e2aef0b78.png)

これをYESにすることで、

* info.plistがBuild Phasesの他の何よりも先に作成される。
* 通常のInfo.plistと別に`${TEMP_DIR}/Preprocessed-Info.plist`という名前で別のInfo.plistが作成されるようになる。

あとは、Run ScriptでそのPreprocessed-Info.plistのほうを編集すると、それがアプリに即反映される。


### 手順② Run Scriptにてスクリプトを記述する

Build Phasesにおいて左上の+からRun Scriptを新規作成する
作成したらスクリプト記述欄に以下のように書く

```
# plist編集の準備
plutil="/usr/bin/plutil"

# 先述したPreprocessed-Info.plistを編集する
infoPlistFileDestination="${TEMP_DIR}/Preprocessed-Info.plist"

# ビルド環境によってファイル閲覧許諾を切り替える
# こうすることで検証時のディレクトリ内確認ができ、かつ本番ではOFFにできる
$plutil -remove 'LSSupportsOpeningDocumentsInPlace' $infoPlistFileDestination
$plutil -remove 'UIFileSharingEnabled' $infoPlistFileDestination

echo ${CONFIGURATION}
if [ ${CONFIGURATION} == "Debug" ] || [ ${CONFIGURATION} == "Staging" ]; then
$plutil -insert 'LSSupportsOpeningDocumentsInPlace' -xml '<true/>' $infoPlistFileDestination
$plutil -insert 'UIFileSharingEnabled' -xml '<true/>' $infoPlistFileDestination
else
$plutil -insert 'LSSupportsOpeningDocumentsInPlace' -xml '<false/>' $infoPlistFileDestination
$plutil -insert 'UIFileSharingEnabled' -xml '<false/>' $infoPlistFileDestination 
fi
```

こうすることで、ビルド直前にinfo.plistの値を書き換えて環境毎にパラメータを変えられる。

※CONFIGURATIONの値はプロジェクトのConfiguration設定によって変わるので確認する。echoの値でも確認できる。
このRun Scriptで出力したechoの値はXcode左メニューのReport Navigatorで確認できる。
![echo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911364/9702c2b0-a8ab-9ed1-1a89-edf360afa419.png)

### 手順③ Run ScriptのInput FilesにPreprocessing-Info.plistを追加する

②で作ったRun ScriptのInput FilesにPreprocessing-Info.plistを追加する。
理由は[こちらの記事](https://qiita.com/y_hakutaku/items/3d67582d2f14d50a4ab7)が詳しく解説していただいています。

![inputFiles.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911364/73dd9f04-21cd-9ba5-0e78-f8ff4c998c73.png)


### 手順④ Run ScriptをCopy Bundle Resourcesより前に配置する

Run ScriptをCopy Bundle Resourcesより前にドラッグ・アンド・ドロップで配置する。

![seq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911364/cc5b88f0-eaa1-34e9-5421-c02512085540.png)


ここまで行ったら、それぞれの環境ごとにビルドして、

* 開発・検証 → 「ファイル」アプリの「このiPhone内」にビルドしたアプリが表示される
* 本番 → 「ファイル」アプリの「このiPhone内」にビルドしたアプリが表示されない

となるか確認して完了。

## 参考にさせていただいた記事

[Xcode10以降でBuild PhasesのRun ScriptでInfo.plistが加工できない](https://qiita.com/y_hakutaku/items/3d67582d2f14d50a4ab7)
[コマンドラインでplistを操作（データ追加・編集・削除）](https://qiita.com/trakwkbys/items/a94c4d43342e96352bde)
[Configurationによってinfo.plistを書き換えてATSの有効/無効を切り替える](https://qiita.com/jumperson/items/1b670bcedb497318263e)
[これがXcodeでのバージョニングの決定版になるかも](https://www.tokoro.me/posts/xcode-versioning/)