Search code examples
iosxcodeunity-game-engineprime31

Unity Prime31 prompt for photo is crashing on iOS 10 and XCode 8


Calling EtceteraBinding.promptForPhoto resulting in immediate crash on iOS 10.

public void TakePhotoTapped() {

    #if UNITY_IOS
    EtceteraBinding.promptForPhoto(0.2f, PhotoPromptType.Camera, 0.8f, true);
    #endif

}

Xcode spits out this log. It does look like some sort of permission issue? Please help.

2016-10-11 11:46:35.758167 xxx[1643:458841] invalid mode 'kCFRunLoopCommonModes' provided to CFRunLoopRunSpecific - break on _CFRunLoopError_RunCalledWithInvalidMode to debug. This message will only appear once per execution.
2016-10-11 11:46:49.760643 xxx[1643:458841] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2016-10-11 11:46:49.768609 xxx[1643:458841] [MC] Reading from public effective user settings.
2016-10-11 11:47:02.450381 xxx[1643:459135] [access] This app has crashed because it attempted to access privacy-sensitive data without a usage description.  The app's Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.

Solution

  • This is related to new iOS 10 Privacy Settings requirement. You must declare ahead of time any access to private data or your App will crash.

    You can add a usage key to your app’s Info.plist together with a purpose string or add a script that will do it for you in Unity for all your builds.

    Xcode Info.plist tab: Info.plist

    SO for each framework you have to declare it's use and enter a string message that is shown to the user.

    You can also add a post processing script in your Assets/Editor folder, where you declare all features used - this will automatically add them to Info.plist:

    using UnityEngine;
    using UnityEditor;
    using System.Collections;
    using UnityEditor.Callbacks;
    using System.Collections;
    using System.IO;
    using UnityEditor.iOS.Xcode;
    
    
    public class ChangeIOSplistFile : MonoBehaviour {
    
        [PostProcessBuild]
        public static void ChangeXcodePlist(BuildTarget buildTarget, string pathToBuiltProject) {
    
            if (buildTarget == BuildTarget.iOS) {
    
                // Get plist
                string plistPath = pathToBuiltProject + "/Info.plist";
                PlistDocument plist = new PlistDocument();
                plist.ReadFromString(File.ReadAllText(plistPath));
    
                // Get root
                PlistElementDict rootDict = plist.root;
                var cameraKey = "NSCameraUsageDescription";
                rootDict.CreateDict (cameraKey);
                rootDict.SetString (cameraKey, "Enter your description here.");
    
                var galleryKey = "NSPhotoLibraryUsageDescription";
                rootDict.CreateDict (galleryKey);
    
                rootDict.SetString (galleryKey, "Enter your description here.");
    
                // Write to file
                File.WriteAllText(plistPath, plist.WriteToString());
            }
        }
    }