Adding ITSAppUsesNonExemptEncryption to Info.plist for iOS builds (SOLVED)

One of the things I’d like to do is to add in the key ITSAppUsesNonExemptEncryption to my Info.plist for my iOS build. Defold game.project lets me specify a path to an Info.plist that I need to maintain, but I’d rather not do that since keeping it “in sync” with the Info.plist that the Defold build process generates “out of the box” is likely to result in an overlooked source of bugs.

Ideally, it would be nice if the Defold build would generate its Info.plist then let me specify a second Info.plist which gets “laid on top of” the generated one, letting me override values or add new key/values from the one I specify? Maybe with a boolean option “merge” which by default can be “false” (to preserve backwards-compatibility) but if set to “true” would merge the two.

Right now, what I’m doing is doing a build with no ios.infoplist set in game.project and taking a copy of the default Info.plist and stuffing it in assets/ios/base.plist. I have my customizations in assets/ios/custom.plist. I then use PlistBuddy to merge the two:

$ cd assets/ios
$ rm Info.plist
$ /usr/libexec/PlistBuddy -c "Merge base.plist" -c "Merge custom.plist" Info.plist

I can then set ios.infoplist to /assets/ios/Info.plist and build.

Alternatively, is there a way to specify a “custom build command” that could kick off an executable (shell script, or any other platform-compatible build script) during the build process for each platform target, where I could stuff those commands, to automate this?

Thanks, everyone! I’m really enjoying getting to know how to do stuff in Defold. This is a fun game in and of itself :wink:

Well, there’s Bob, the command line build tool, but there is no way to hook into the build process when building/bundling from the editor.

1 Like

Ooh! Bob sounds like a great option, although it’s throwing an error at me trying to resolve … I guess I’ll try reporting it?

Edited to ask: Where should Bob issues be reported?

What error is that? I’m guessing that it’s the lack of --auth and --email. These two options are currently required even though your dependencies might not be behind basic auth (yes, this will be fixed).

java -jar bob.jar --auth foobar --email bob@acme.com resolve

EDIT: Ah, I see now that this was the issue: Bob the builder fails when path contains spaces

1 Like

Did you figure out a more elegant way of doing this using bob?

I have everything for the continuous delivery working but this plist thing is still causing me issues :slight_smile:

I prefer not to override the plist with my own because I don’t want to potentially introduce problems by not keeping it in sync with the one that Defold would generate. Is there anywhere you can access a generated plist file from the engine before calling bob -bundle?

Bob.jar contains the info.plist so you can extract it from inside bob (jar files are zip files).

2 Likes

Awesome, thanks @britzl

If I were to use this plist template in the .project files ‘plist’ property - would bob bundle replace the tokens in it?

If you copy this file out to your project, and refer to it from game.project, then yes, the templated arguments will be replaced as usual.

3 Likes

When using Plistbuddy to set the key on the plist, its throwing up an error due to the placeholders that exist in the template plist file in bob. I’m wondering if anybody knows how to circumvent this at all without having to regexp it into the plist. I’m guessing in the bob build scripts you just do a simple find/replace on the tokens.

Here is the error:

[exec] Error Reading File: Info.plist
[exec] Encountered unknown tag {{ios.pre_renderered_icons}} on line 42

We use Mustache to do the string replacements, but you can ofc use whatever tool suits your need. E.g. Python + a sax-parser will let you insert your strings where ever you need it.

Also, if you want to go the regexp way, I personally use this regex site a lot to create various patterns. I don’t think I’ll ever really learn regex by heart, but I’m definitely using them a lot nowadays. They’re a good tool to learn if you are programming or writing various scripts etc.

1 Like

Tell me about it. Throughout my career regex has caused nothing but suffering! Thanks for the heads up on a couple of those tools though :slight_smile:

Might be useful for @dossy, I wrote a very primitive python script that extracts the plist from bob and appends the encryption exception tag:

import re
import os

from zipfile import ZipFile

def extract_without_folder(arc_name, full_item_name, folder):
    with ZipFile(arc_name) as zf:
        file_data = zf.read(full_item_name)
    with open(os.path.join(folder, os.path.basename(full_item_name)), "wb") as fout:
        fout.write(file_data)

extract_without_folder("bob.jar","com/dynamo/bob/bundle/resources/ios/Info.plist", "")

with open ('Info.plist', 'r+w' ) as f:
     content = f.read()

content_new = re.sub('<dict>', '<dict>\n\t<key>ITSAppUsesNonExemptEncryption</key>\n\t<false/>',         content, flags = re.M)

with open ('Info.plist', 'w' ) as f:
     f.write(content_new)

With the “Custom entitlements” introduced in Defold 1.2.144, is it possible to add the ITSAppUsesNonExemptEncryption more easily?

I haven’t been able to find an example of what this file should look like on the forum or otherwise.

If you set the ios.override_entitlements = true and then set your file to ios.entitlements then your file is used as-is.

I’m unfamiliar with how plist files work, so bear with me. I get this error:

With this “entitlements” file:

And this config:

Did you set the ios.override_entitlements? (edit: I now see that you do)
(edit)
When you do, you’ll pass in the full entitlements plist.

If you don’t, then it tries to merge the file with the entitlements in your mobileprovisioning profile.
And, if you don’t have that key there, you’l get that error message.

(edit)
My bad, it should say override_entitlements = 1

3 Likes

Fantastic, now it builds fine. Thanks!

1 Like

Back on this. Although the there are no build errors, I get this error when uploading:

ERROR ITMS-90045: "Invalid Code Signing Entitlements. Your application bundle's signature contains code signing entitlements that are not supported on iOS. Specifically, key 'ITSAppUsesNonExemptEncryption' in 'Payload/Game Name.app/GameName' is not supported."

ERROR ITMS-90075: "This bundle is invalid. The application-identifier entitlement is missing; it should contain your 10-character Apple Developer ID, followed by a dot, followed by your bundle identifier."

This is the ios_entitlement.plist I use:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    	<key>ITSAppUsesNonExemptEncryption</key>
    	<false/>
    </dict>
    </plist>

See above for my other settings.

Where am I going wrong?

Edit: Using a custom Info.plist with the key included works:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
            <key>BuildMachineOSBuild</key>
            <string>13A603</string>
            <key>CFBundleDevelopmentRegion</key>
            <string>en</string>
            <key>CFBundleDisplayName</key>
            <string>{{project.title}}</string>
            <key>CFBundleExecutable</key>
            <string>{{exe-name}}</string>
            <key>CFBundleIconFiles</key>
            <array>
                    <string>Icon-167.png</string>
                    <string>Icon-60@3x.png</string>
                    <string>Icon-60@2x.png</string>
                    <string>Icon-76@2x.png</string>
                    <string>Icon-76.png</string>
                    <string>Icon@2x.png</string>
                    <string>Icon.png</string>
                    <string>Icon-72@2x.png</string>
                    <string>Icon-72.png</string>
            </array>
            <key>CFBundleIcons</key>
            <dict>
                    <key>CFBundlePrimaryIcon</key>
                    <dict>
                            <key>CFBundleIconFiles</key>
                            <array>
                                    <string>Icon-167.png</string>
                                    <string>Icon-60@3x.png</string>
                                    <string>Icon-60@2x.png</string>
                                    <string>Icon-76@2x.png</string>
                                    <string>Icon-76.png</string>
                                    <string>Icon@2x.png</string>
                                    <string>Icon.png</string>
                                    <string>Icon-72@2x.png</string>
                                    <string>Icon-72.png</string>
                            </array>
                            <key>UIPrerenderedIcon</key>
                            <{{ios.pre_renderered_icons}}/>
                    </dict>
            </dict>
            <key>CFBundleIdentifier</key>
            <string>{{ios.bundle_identifier}}</string>
            <key>CFBundleInfoDictionaryVersion</key>
            <string>6.0</string>
            <key>CFBundleName</key>
            <string>dmengine</string>
            <key>CFBundlePackageType</key>
            <string>APPL</string>
            <key>CFBundleShortVersionString</key>
            <string>{{project.version}}</string>
            <key>CFBundleSignature</key>
            <string>????</string>
            <key>CFBundleSupportedPlatforms</key>
            <array>
                    <string>iPhoneOS</string>
            </array>
            <key>CFBundleVersion</key>
            <string>{{project.version}}</string>
            <key>DTCompiler</key>
            <string>com.apple.compilers.llvm.clang.1_0</string>
            <key>DTPlatformBuild</key>
            <string>16B91</string>
            <key>DTPlatformName</key>
            <string>iphoneos</string>
            <key>DTPlatformVersion</key>
            <string>8.0</string>
            <key>DTSDKBuild</key>
            <string>16B91</string>
            <key>DTSDKName</key>
            <string>iphoneos12.1</string>
            <key>DTXcode</key>
            <string>1010</string>
            <key>DTXcodeBuild</key>
            <string>10B61</string>
            <key>UIFileSharingEnabled</key>
            <{{project.write_log}}/>
            <key>LSRequiresIPhoneOS</key>
            <true/>
            <key>MinimumOSVersion</key>
            <string>8.0</string>
            <key>UIDeviceFamily</key>
            <array>
                    <integer>1</integer>
                    <integer>2</integer>
            </array>
            <key>UIStatusBarHidden</key>
            <true/>
            <key>UIViewControllerBasedStatusBarAppearance</key>
            <false/>
            <key>UIRequiredDeviceCapabilities</key>
            <array>
                    <string>armv7</string>
                    <string>opengles-2</string>
            </array>
            <key>UISupportedInterfaceOrientations</key>
            <array> {{#orientation-support}}
                    <string>UIInterfaceOrientation{{.}}</string>{{/orientation-support}}
            </array>
            <key>UISupportedInterfaceOrientations~ipad</key>
            <array> {{#orientation-support}}
                    <string>UIInterfaceOrientation{{.}}</string>{{/orientation-support}}
            </array>

            <key>CFBundleURLTypes</key>
            <array>
            </array>

            <key>LSApplicationQueriesSchemes</key>
            <array>
                    {{#application-queries-schemes}}<string>{{.}}</string>{{/application-queries-schemes}}
            </array>

            <key>UILaunchImages</key>
            <array>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Portrait</string>
                        <key>UILaunchImageSize</key>
                        <string>{320, 480}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Landscape</string>
                        <key>UILaunchImageSize</key>
                        <string>{320, 480}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-568h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Portrait</string>
                        <key>UILaunchImageSize</key>
                        <string>{320, 568}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-568h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Landscape</string>
                        <key>UILaunchImageSize</key>
                        <string>{320, 568}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Portrait-667h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Portrait</string>
                        <key>UILaunchImageSize</key>
                        <string>{375, 667}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Landscape-667h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Landscape</string>
                        <key>UILaunchImageSize</key>
                        <string>{375, 667}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Portrait-736h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Portrait</string>
                        <key>UILaunchImageSize</key>
                        <string>{414, 736}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Landscape-736h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Landscape</string>
                        <key>UILaunchImageSize</key>
                        <string>{414, 736}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Portrait-1024h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Portrait</string>
                        <key>UILaunchImageSize</key>
                        <string>{768, 1024}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Landscape-1024h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Landscape</string>
                        <key>UILaunchImageSize</key>
                        <string>{768, 1024}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Portrait-1112h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Portrait</string>
                        <key>UILaunchImageSize</key>
                        <string>{834,1112}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Landscape-1112h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Landscape</string>
                        <key>UILaunchImageSize</key>
                        <string>{834,1112}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Portrait-1366h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Portrait</string>
                        <key>UILaunchImageSize</key>
                        <string>{1024,1366}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Landscape-1366h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Landscape</string>
                        <key>UILaunchImageSize</key>
                        <string>{1024,1366}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Portrait-812h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Portrait</string>
                        <key>UILaunchImageSize</key>
                        <string>{375, 812}</string>
                    </dict>
                    <dict>
                        <key>UILaunchImageMinimumOSVersion</key>
                        <string>8.0</string>
                        <key>UILaunchImageName</key>
                        <string>Default-Landscape-812h</string>
                        <key>UILaunchImageOrientation</key>
                        <string>Landscape</string>
                        <key>UILaunchImageSize</key>
                        <string>{375, 812}</string>
                    </dict>
            </array>
    	<key>ITSAppUsesNonExemptEncryption</key>
    	<false/>
    </dict>
    </plist>

Is there a benefit of using override_entitlements=1 over the above solution?

It would be better if the key was merged with the built in .plist, to avoid maintaining the whole hard coded list.

I think there’s some confusion around entitlements, the *.mobileprovision file and the Info.plist file.

Entitlements
An entitlement is a right or privilege that grants an executable particular capabilities. For example, an app needs the HomeKit Entitlement — along with explicit user consent — to access a user’s home automation network. An app stores its entitlements as key-value pairs embedded in the code signature of its binary executable.

https://developer.apple.com/documentation/bundleresources/entitlements

Info.plist
An information property list file is a structured text file that contains essential configuration information for a bundled executable. The system uses these keys and values to obtain information about your app and how it is configured. As a result, all bundled executables (plug-ins, frameworks, and apps) are expected to have an information property list file.
https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html

The .mobileprovision file
This file together with a signing identity is used when bundling an iOS game. The file is generated in the Apple Developer portal. It defines which application it can be applied to and if the application is packaged for development or distribution. It also defines which capabilities (read entitlements) the application has.

How we bundle
When we bundle an iOS application we ask for the mobileprovision and a signing identity (from your keychain). We extract the entitlements from the mobileprovision file and use it when we create the application bundle. The entitlements are extracted like this:

security cms -D -i foobar.mobileprovision -o foobar.xml

You can try this yourself from the command line!

If you specify that you want to Override Entitlements we ignore the entitlements in your mobileprovision file and use the one you specify. Otherwise we merge them.

The problem
After this very long intro we need to look at the actual problem. You want to add the key ITSAppUsesNonExemptEncryption. Apple definition of the property:

“Set the value for this key to NO in your app’s Information Property List file to indicate that your app—including any third-party libraries you link against—either uses no encryption, or only uses encryption that’s exempt from export compliance requirements, as described in Determine your export compliance requirements. Set the value to YES to indicate that your app uses non-exempt encryption.”

Note that it says Information Property List. It is not an entitlement and should not be merged into the entitlements. It must be stored in the Info.plist. That is why it works when you specify it in a full Info.plist file.

Yes, I agree. What you can do is to fake an empty extension in your project and add your stub .plist file with the property and let the build server merge it for you.

3 Likes

Phew! Thanks for the thorough explanation. Happy Friday!

1 Like