UnityのiOSビルド時のplist設定の自動化

#はじめに
UnityもC#も知らないのにUnityプロジェクトのiOSビルドの設定の自動化やってと言われたときの備忘録。

Unity iOS ビルド設定　とかでググればいっぱい出てきたので楽勝やん！と思ったのですがわりと苦労したので同じ境遇の方の助けになれば...

#やりたいこと

* iOSのビルド後にCapabilitiesのBackground ModesをONにする
* Background Modesにaudioとbluetoothを設定する
* plistのRequired device capabilitiesにbluetooth-leを設定する

<img width="707" alt="u_capability" src="https://user-images.githubusercontent.com/34936885/45763210-feab6200-bc6a-11e8-9608-cb7820d63ec6.png">

<img width="609" alt="u_blue" src="https://user-images.githubusercontent.com/34936885/45763148-de7ba300-bc6a-11e8-9068-a78f2d8b6d9f.png">


#とりあえず試したこと(失敗)

下記のファイルをUnityのプロジェクトのAssets/Editor配下に入れてビルドする。
plistのキーとかは一度適当なXcodeプロジェクトで設定したものをコピペ。

```C#
using System.IO;
using UnityEngine;
using UnityEditor;
using UnityEditor.iOS.Xcode;
using UnityEditor.Callbacks;
using System.Collections;

public class XcodeSettingsPostProcesser
{
    [PostProcessBuildAttribute (0)]
    public static void OnPostprocessBuild(BuildTarget buildTarget, string pathToBuiltProject)
    {
        if (buildTarget != BuildTarget.iOS) return; 
   
        var projectPath = pathToBuiltProject + "/Unity-iPhone.xcodeproj/project.pbxproj";
        
        SetCapability(projectPath); 
        SetPlist(projectPath); 
    }
    
    public static void SetCapability(string path) 
    {
    	var proj = new PBXProject();
    	proj.ReadFromString(File.ReadAllText(path));
    	
    	string targetName = "Unity-iPhone";
    	string target = proj.TargetGuidByName(targetName);
    	proj.AddCapability(target, PBXCapabilityType.BackgroundModes);
    	
    	File.WriteAllText(projPath, proj.WriteToString());
    }
    
    public static void SetPlist(string path) 
    {
    	var plistPath = Path.Combine (path, "Info.plist");
    	var plist = new PlistDocument ();
    	plist.ReadFromFile (plistPath);
    	
    	var capabilities = plist.root.CreateArray("Required device capabilities");
    	capabilities.AddString("bluetooth-le");
    	
    	var backgroundModes = plist.root.CreateArray("Required background modes");
    	backgroundModes.AddString("App plays audio or streams audio/video using AirPlay");
    	backgroundModes.AddString("App communicates using CoreBluetooth");    	
    	plist.WriteToFile (plistPath);
    }
}
```

その結果がこれ

<img width="690" alt="u_capability_no" src="https://user-images.githubusercontent.com/34936885/45763122-ce63c380-bc6a-11e8-83f7-b42bd0033e6e.png">

<img width="686" alt="u_plist" src="https://user-images.githubusercontent.com/34936885/45763262-11be3200-bc6b-11e8-8e3f-896d75c932a0.png">

できてるようで何もできていない。
Required device capabilitiesもRequired background modesも2つあるしCapabilitiesタブのBackground Modesには何もチェックがついていない。

#ちょっと工夫(失敗)

2つできるのはplistのところでCreateArrayしてるからだと思う。[ここ](https://docs.unity3d.com/ja/current/ScriptReference/iOS.Xcode.PlistElementDict.html)をみると普通にthis[string]でDictionaryみたいにアクセスできるっぽい。
下記のように修正。

```C#
	public static void SetPlist(string path) 
    {
    	var plistPath = Path.Combine (path, "Info.plist");
    	var plist = new PlistDocument ();
    	plist.ReadFromFile (plistPath);
    	
    	var capabilities = plist.root["Required device capabilities"].toArray();
    	capabilities.AddString("bluetooth-le");
    	
    	var backgroundModes = plist.root["Required background modes"].toArray();
    	backgroundModes.AddString("App plays audio or streams audio/video using AirPlay");
    	backgroundModes.AddString("App communicates using CoreBluetooth");    	
    	plist.WriteToFile (plistPath);
    }
```

ビルドするとplistに何も追加されなかった...

plistに値が追加された１個目のやつをあらためて確認。コピペしたけど綴りが違う？と思い検索をかけてみた。すると下記のようにRequired device capabilitiesが一件しか引っかからない！！

<img width="269" alt="u_search" src="https://user-images.githubusercontent.com/34936885/45763317-28648900-bc6b-11e8-98db-8cdc2c96555c.png">

とりあえず下記のようにInfo.plistを開いてみた。

<img width="438" alt="u_plist_code" src="https://user-images.githubusercontent.com/34936885/45763364-416d3a00-bc6b-11e8-9094-445b3c5c1f08.png">

<img width="551" alt="u_plist_result" src="https://user-images.githubusercontent.com/34936885/45763377-49c57500-bc6b-11e8-80cc-9e24b6b46b25.png">

Required device capabilitiesとUIRequiredDeviceCapabilitiesがある？キーが違う！！

#修正
キーと値を下記のように修正し、keyがある場合とない場合の処理のチェックも入れた。

```C#
	public static void SetPlist(string path) 
    {
    	var plistPath = Path.Combine (path, "Info.plist");
    	var plist = new PlistDocument ();
    	plist.ReadFromFile (plistPath);
    	
    	PlistElementArray capabilities;
    	if (plist.root.values.ContainsKey("UIRequiredDeviceCapabilities")) {
    		capabilities = plist.root["UIRequiredDeviceCapabilities"].toArray();
    	} else {
    		capabilities = plist.root.CreateArray("UIRequiredDeviceCapabilities");
    	}
    	capabilities.AddString("bluetooth-le");
    	
    	PlistElementArray backgroundModes;
    	if (plist.root.values.ContainsKey("UIBackgroundModes")) {
    		backgroundModes = plist.root["UIBackgroundModes"].toArray();
    	} else {
    		backgroundModes = plist.root.CreateArray("UIBackgroundModes");
    	}
    	backgroundModes.AddString("audio");
    	backgroundModes.AddString("bluetooth-central");    	
    	plist.WriteToFile (plistPath);
    }
```

できた！！

下記に表示されているキーと実際のキーは違うっていうのは何となく知っていたけど今まで気にしたことがなかった。
ちなみに下記にRequired device capabilitiesと打つと勝手にUIRequiredDeviceCapabilitiesに変換してくれるらしい。

<img width="686" alt="u_plist" src="https://user-images.githubusercontent.com/34936885/45763262-11be3200-bc6b-11e8-8e3f-896d75c932a0.png">

よくみると参考サイトもCFBundleURLSchemesとか使ってた...

#さいごに

とりあえずはできましたがもっとスマートなやり方があれば教えてください。

Info.plistにそんな変換機能があるとは知らなかった新しいことをやるのは勉強になるな〜。

#参考

[UnityでXcodeの設定を自動化する方法まとめ](http://smartgames.hatenablog.com/entry/2016/06/19/164052)

[Unity iOSビルド時にURLスキームを追加するだけのPostProcessBuild](https://qiita.com/kabayaki/items/e6fe38e00d03ced0301a)

[Unity5のPostProcessBuildでXcode Capabilityの設定する方法](https://qiita.com/fullcorder/items/b82c48022acd0b4ff957)