Search code examples
iosapp-storesubmissionapplication-loader

Set iOS Version for App Store submission (without Xcode!!!)


Dear stackoverflowers!

I am currently preparing an iPhone app for submission to the App store. It is a larger cross-platform C++ project, for which I had to ditch Xcode as IDE and move to a more "cross-platform type" build system. For now this is a simple Makefile. Everything worked just fine during the development process, just utilizing the XCode build chain, but not using XCode itself. However, now there is a last hurdle that I do not quite know how to pass:

After a lot of different other packaging related errors, that the Application Loader from Apple spit out about my .ipa file, there is this last one:

"The bundle is invalid. Apple is not currently accepting applications built with this version of the SDK or Xcode."

I have seen that I am clearly not the only one encountering this error, but most other articles, that describe how to solve this problem, are about solving it via Xcode settings, or are clearly outdated (2011 or earlier).

Facts about the app:

Two days ago, the app still was linked against the iOS 5.0 SDK. Given the error, I spent some time to link the app against the newest, fresh SDK, 6.1. So that is out the way, still the error (however, I did not expect that the server behind the apploader would try to 'parse' my executable to see which version I of the SDK link to... or does it, and there are some residual links to iOS 5.0?)

Next thing, my Info.plist. Well, here it is:

<?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>CFBundleDevelopmentRegion</key>
  <string>en</string>
  <key>CFBundleDisplayName</key>
  <string>Drone game</string>
  <key>CFBundleExecutable</key>
  <string>game</string>
  <key>CFBundleIconFiles</key>
  <array>
    <string>icon.png</string>
    <string>icon@2x.png</string>
    <string>icon-iPad.png</string>
  </array>
  <key>CFBundleIdentifier</key>
  <string>[The bundle identifier]</string>
  <key>CFBundleInfoDictionaryVersion</key>
  <string>6.0</string>
  <key>CFBundleIconFile</key>
  <string>icon.png</string>
  <key>CFBundleName</key>
  <string>Drone game</string>
  <key>CFBundlePackageType</key>
  <string>APPL</string>
  <key>CFBundleShortVersionString</key>
  <string>1.0</string>
  <key>CFBundleSignature</key>
  <string>????</string>
  <key>CFBundleVersion</key>
  <string>1.0</string>
  <key>LSRequiresIPhoneOS</key>
  <true/>
  <key>NSMainNibFile</key>
  <string>MainView</string>
  <key>CFBundleResourceSpecification</key>
  <string>ResourceRules.plist</string>
  <key>UIRequiredDeviceCapabilities</key>
  <array>
    <string>armv7</string>
  </array>
  <key>UISupportedInterfaceOrientations</key>
  <array>
    <string>UIInterfaceOrientationLandscapeRight</string>
  </array>
  <key>UIApplicationExitsOnSuspend</key>
  <true/>
  <key>UIStatusBarHidden</key>
  <true/>
  <key>LSApplicationCategoryType</key>
  <string></string>
  <key>UIInterfaceOrientation</key>
  <string>UIInterfaceOrientationLandscapeRight</string>
  <key>MinimumOSVersion</key>
  <string>6.1</string>
  <key>LSRequiredIPhoneOS</key>
  <true/>
  <key>UILaunchImageFile</key>
  <string>Default.png</string>
  <key>CFBundleGetInfoString</key>
  <string></string>
  <key>UIDeviceFamily</key>
  <array>
    <integer>1</integer>
    <integer>2</integer>
  </array>
</dict>
</plist>

I assume that there are still some options missing in the property list for the app, that are detected by the Application Loader or some values are filled in the wrong way. Part of the problem is that Apple's developer guide is not really helpful when not using Xcode. There are a lot of keys that are marked with "do not use, filled in by Xcode", with only little explanation (example: MinimumOSVersion).

The question essentially is: Does someone know where the application loader gets the used SDK version from? Or does the Application Loader care about the "Xcode Version" and it needs to be specified somewhere? Any advice would be great!


Solution

  • Okay, it took a while but I succeeded last week to submit my program using the Application Loader and without Xcode. The problem was a bunch of undocumented keys, that I reverse engineerd from XCode-built projects. For everyone, who wants to accomplish a similar thing, here the changed Info.plist that worked for me:

    <?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>
    

    New magic key with version string of the used OS. I do not know how to generate this string, this is the one Xcode wrote in another plist and I copied it.

        <key>BuildMachineOSBuild</key>
        <string>11G63b</string>
    

    .

        <key>CFBundleDevelopmentRegion</key>
        <string>en</string>
        <key>CFBundleDisplayName</key>
        <string>Drone game</string>
        <key>CFBundleExecutable</key>
        <string>game</string>
        <key>CFBundleIconFiles</key>
        <array>
            <string>icon.png</string>
            <string>icon@2x.png</string>
            <string>icon-iPad.png</string>
        </array>
        <key>CFBundleIdentifier</key>
        <string>[The bundle identifer]</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
        <key>NSHumanReadableCopyright</key>
        <string>[Copyright notice]</string>
        <key>CFBundleIconFile</key>
        <string>icon.png</string>
        <key>CFBundleName</key>
        <string>Drone game</string>
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleShortVersionString</key>
        <string>1.0</string>
    

    Here the real magic. Again some key that are documented nowhere, however, given the error message in the problem desciption, I suspect the keys DTSDKName and DTSDKBuild to be particulary important. Well yeah, but again version strings for Xcode (why does apple want to know that?) and the iphone; once again, I do not know how to generate these.

        <key>DTCompiler</key>
        <string></string>
        <key>DTPlatformBuild</key>
        <string>10B141</string>
        <key>DTPlatformName</key>
        <string>iphoneos</string>
        <key>DTPlatformVersion</key>
        <string>6.1</string>
        <key>DTSDKBuild</key>
        <string>10B141</string>
        <key>DTSDKName</key>
        <string>iphoneos6.1</string>
        <key>DTXcode</key>
        <string>0460</string>
        <key>DTXcodeBuild</key>
        <string>4H127</string>
    

    Also changed this one, I think this is a copy-paste artifact since I cannot remember changing it....

        <key>CFBundleSignature</key>
        <string>ASDR</string>
    

    .

        <key>CFBundleVersion</key>
        <string>1.0</string>
        <key>LSRequiresIPhoneOS</key>
        <true/>
        <key>NSMainNibFile</key>
        <string>MainView</string>
        <key>CFBundleResourceSpecification</key>
        <string>ResourceRules.plist</string>
        <key>UIRequiredDeviceCapabilities</key>
        <array>
            <string>armv7</string>
        </array>
        <key>UISupportedInterfaceOrientations</key>
        <array>
            <string>UIInterfaceOrientationLandscapeRight</string>
        </array>
        <key>UIApplicationExitsOnSuspend</key>
        <true/>
        <key>UIStatusBarHidden</key>
        <true/>
        <key>LSApplicationCategoryType</key>
        <string></string>
        <key>UIInterfaceOrientation</key>
        <string>UIInterfaceOrientationLandscapeRight</string>
    

    Changed to old version, seemingly not resposible for the rejection by the Application Loader and 5.0 is correct anyway

        <key>MinimumOSVersion</key>
        <string>5.0</string>  
    

    .

        <key>UILaunchImageFile</key>
        <string>Default.png</string>
        <key>CFBundleGetInfoString</key>
        <string></string>
        <key>UIDeviceFamily</key>
        <array>
            <integer>1</integer>
        </array>
    </dict>
    </plist>
    

    Bundling

    Finally, assuming you can compile a valid ".app"-directory, you need to generate a bundle from this (check by try to execute the ".app"-directory on the simulator using ios-sim or to deploy it on your phone using fruitstrap - great tools!). I chose an ipa-bundle. I used the following script to generate it from the .app-directory:

    #!/bin/bash
    cp embedded.mobileprovision [.app directory]
    codesign --force --sign "[Distribution Key Identifer]" --entitlements Entitlements.plist [.app directory]
    cd [.app directory]
    ln -s _CodeSignature/CodeResources CodeResources
    cd ..
    /usr/bin/xcrun -verbose -log -sdk iphoneos PackageApplication -v [.app directory] -o "$(pwd)/[bundle name].ipa" --sign "[Distribution Key Identifer]" --embed embedded.mobileprovision
    

    embedded.mobileprovision is the the distribution provisioning profile you download from Apple's Mobile Provisioning Centre. Just copy-paste it in your .app directory.

    [Distribution Key Identifer] is the identifier of your distribution signature from your keycahin.

    Note, that code signing is executed twice, once as part of "PackageApplication" and once invoked manually. Clearly, I do not know what is required to build a valid .ipa, but this worked. Feel free to improve on this by stripping unnecessary steps.

    Hope this will help someone who tries to achieve something similar, cheers!