Unity+iOSでカメラロールにスクショを保存するまで

# はじめに
初qiitaです。
Unityで作成するARKitアプリに「カメラで撮影する」機能を入れようと思ったら、思いの外情報が少なかったので、いろいろ調べて実装しました。
iOSネイティブを書くことはほとんど無かったのでミス等あったらすいません。
今回Androidは省いています。ARCore触り出したらまた作るかもしれません...

ぜひARKitやVuforia等を用いたアプリと組み合わせてみてください。

UnityProject(ソースコード)はこちら
https://github.com/Ryopon/iOSScreenCapture

**追記(18/02/01)**
手動で設定していた部分の自動化等を行いました。
それに伴い記事を少し修正しています。

# 環境
Unity2017.1.f1
iOS11

# カメラと写真の利用許可を求める
ネイティブ側のコードは[こちら](https://github.com/Ryopon/iOSScreenCapture/blob/master/Assets/iOSScreenCapture/Plugins/UnityIosPlugin.mm)を見てください。
Unity側(C#)では下の様なコードで呼び出しを行います。

```c#:UnityiOS.cs
public class UnityiOS {
...
	public static void RequestPermissions() {
		AVAuthorizationStatus avstatus = HasCameraPermission();
		PHAuthorizationStatus phstatus = HasCameraRollPermission();

		//アクセス許可のリクエストを出していない場合はリクエストを送る
		if (avstatus == AVAuthorizationStatus.NotDetermined) {
			_RequestCameraPermission();
		}

		if(phstatus == PHAuthorizationStatus.NotDetermined) {
			_RequestCameraRollPermission();
		}
	}
...
}
```

RequestPermissions関数を呼び出すことでネイティブコードが実行され、カメラと写真へのアクセス許可を求めるポップアップが表示されます。
また、AuthorizationがNotDeterminedの場合にリクエストを求める事で初回起動時のみリクエストが表示されます。

# 利用許可がもらえなかった場合の処理
ユーザーによってアクセスを拒否された場合はこんな感じの画面を出したいですよね。
<img width="664" alt="スクリーンショット 2017-09-26 19.11.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/193550/ddcd839c-9f7f-4bdf-c72b-afec8795c333.png">

アクセス許可を持っているかどうかはHasCamera(Roll)Permissionで調べる事が出来ますので

```c#:Example
if(UnityiOS.HasCameraPermission()) {
  //処理
}
```
こんな感じで調べて画面の表示を行ってください。

ついでに「はい」押したら設定画面に飛んで欲しいですよね！

```c#:UnityiOS.cs
...
	public static void GoToSettings() {
#if !UNITY_EDITOR
        _GoToSettings();
#endif
	}

	public void GoToSettings_forUGUI() {
#if !UNITY_EDITOR
        _GoToSettings();
#endif
	}
...
```
こんな関数を用意していますので
<img width="299" alt="スクリーンショット 2017-09-28 11.02.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/193550/1810f62f-dd6c-9939-2fec-d2bb772df708.png">

uGUIボタンのOnClickに入れておくと、ボタン押下時にアプリの設定が開くようになります。
**ボタンから静的関数を呼び出すことは出来ない**(GoToSettings関数等)ので注意してください(missingが表示されます)。

# 写真を撮ってカメラロールに保存する
撮影を実行するにはUnityiOSScreenCapture.Executeを実行します。こちらもGoToSettings_forUGUIと同様にuGUIボタンのOnClickに入れておくと、撮影ボタンを作れます。

```c#:UnityiOSScreenCapture.cs
public class UnityiOSScreenCapture : MonoBehaviour {

	public UnityEvent OnCompleteCapture;
	public UnityEvent OnFailCapture;

	public void Execute() {
#if !UNITY_EDITOR
		PHAuthorizationStatus phstatus = (PHAuthorizationStatus)Enum.ToObject(
			typeof(PHAuthorizationStatus), UnityiOS.HasCameraRollPermission());
		UnityiOS.PlaySystemShutterSound();
		if(phstatus == PHAuthorizationStatus.Authorized) {
			Handheld.SetActivityIndicatorStyle(UnityEngine.iOS.ActivityIndicatorStyle.Gray);
			Handheld.StartActivityIndicator();
		} else {
			OnFailCapture.Invoke();
		}
#endif
	}
...
}
```

撮影成功時に**OnCompleteCapture**、写真へのアクセスが非許可設定になってる場合に**OnFailCapture**が実行されるようになっていますので、こちらもインスペクタ上で設定してあげてください。

また、ネイティブからのコールバックを受ける関係でヒエラルキーに指定した名前のゲームオブジェクトを作成する必要があります。（この辺りもっと上手く作れるはずなのでプルリクお待ちしてます！！）
<img width="371" alt="スクリーンショット 2017-09-28 12.04.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/193550/983800d5-c93c-7c57-4649-62bfed449168.png">

今回は"UnityiOSScreenCapture"というゲームオブジェクトにコールバックを返すので、このオブジェクトにUnityiOSScreenCaptureをAddComponentして使います。
コールバックを返す対象はCaptureCallback.mmに記述していますので、変更したい場合はこれをイジって下さい。

```objc:
    UnitySendMessage("UnityiOSScreenCapture", "DidImageWriteToAlbum", "");
```

# XCodeの設定(不要になりました)
XCodeで追加していた設定をビルド時に自動で追加してくれるエディタ拡張を追加しました。
→[IOSSCBuildPostProcessor.cs](https://github.com/Ryopon/iOSScreenCapture/blob/master/Assets/iOSScreenCapture/Editor/IOSSCBuildPostProcessor.cs)
カメラロールへのアクセスを求める際に表示する説明文は

```c#:IOSSCBuildPostProcessor.cs
public class IOSSCBuildPostProcessor
{
...
    public static void OnPostProcessBuildIOS(string pathToBuiltProject)
    {
#if UNITY_IOS
...
        const string description = "Camera roll access permission is necessary for saving an image.";
...
#endif //UNITY_IOS
    }
}
```
OnPostProcessBuildIOS関数内の**description**の中身を書き換えて下さい。

~~Unityだけでは行えない設定があるので、XCode側で少し設定を加える必要があります。
まずは**General > Linked Frameworks And Libraries**で**Photos.framework**を追加します。~~
<img width="396" alt="スクリーンショット 2017-09-28 12.39.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/193550/715a6d4b-2a94-d81b-bd1d-f29549dd2027.png">

~~次に**Info > Custom iOS Target Properties**で以下の２つを追加します。~~

 - Privacy - Photo Library Usage Description
 - Privacy - Camera Usage Description

~~カメラについてはUnityでも指定出来ますが、写真についてはXCode側で設定する必要があるので今回はまとめてこちらで設定しています。~~
<img width="485" alt="スクリーンショット 2017-09-28 15.30.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/193550/4fdd57b9-55eb-3adb-5716-0e8e345241e7.png">


以上でカメラロールにスクショを保存するまでのアレコレは終了です。