fastlane: [gym] Export Developer ID macOS app fails (.app)

New Issue Checklist

Issue Description

Note: I’m a little new to fastlane so please bare with me!

Using gym to build my macOS app, the command fails right after the export phase:

INFO [2020-02-02 18:34:26.67]: ▸ Exported MyApp to: /var/folders/sr/4s52t1q16yzgnn17nfwy_fv40000gn/T/gym_output20200202-85761-10rcbbx
INFO [2020-02-02 18:34:26.67]: ▸ ** EXPORT SUCCEEDED **
ERROR [2020-02-02 18:34:26.69]: The generated archive is invalid, this can have various reasons:
ERROR [2020-02-02 18:34:26.69]: Usually it's caused by the `Skip Install` option in Xcode, set it to `NO`
ERROR [2020-02-02 18:34:26.69]: For more information visit https://developer.apple.com/library/ios/technotes/tn2215/_index.html
ERROR [2020-02-02 18:34:26.69]: Also, make sure to have a valid code signing identity and provisioning profile installed
...

The export itself succeeds (a valid, correctly signed binary is produced) but fastlane appears unable to find the binary and assumes the export has failed.

This appears to be a bug in gym/lib/gym/generators/package_command_generator_xcode7.rb in pkg_path. The function assumes the export output has a suffix of .pkg. However, I am trying to export a Developer ID app, so the export produces a .app.

If I ‘hack’ the pkg_path function and replace .pkg with .app, everything works perfectly.

Command executed

bundle exec fastlane myappbeta

Complete output when running fastlane, including the stack trace and command used
 [18:41:29]: Successfully exported and compressed dSYM file
[18:41:29]: Successfully exported the .app file:
[18:41:29]: ../MyApp Releases/MyApp/MyApp 4.1.10/MyApp 4.app
[18:41:29]: Generated plist file with the following values:
[18:41:29]: ▸ -----------------------------------------
[18:41:29]: ▸ {
[18:41:29]: ▸   "provisioningProfiles": {
[18:41:29]: ▸     "com.xxx.myapp": "match Direct com.xxx.myapp macos"
[18:41:29]: ▸   },
[18:41:29]: ▸   "method": "developer-id",
[18:41:29]: ▸   "signingStyle": "manual"
[18:41:29]: ▸ }
[18:41:29]: ▸ -----------------------------------------
[18:41:29]: $ /usr/bin/xcrun /Users/blah/Work/Xcode\ Projects/MyApp/vendor/bundle/ruby/2.6.0/gems/fastlane-2.141.0/gym/lib/assets/wrap_xcodebuild/xcbuild-safe.sh -exportArchive -exportOptionsPlist '/var/folders/sr/4s52t1q16yzgnn17nfwy_fv40000gn/T/gym_config20200202-95104-14e0ysk.plist' -archivePath /Users/blah/Library/Developer/Xcode/Archives/2020-02-02/MyApp\ 4\ 2020-02-02\ 18.41.09.xcarchive -exportPath '/var/folders/sr/4s52t1q16yzgnn17nfwy_fv40000gn/T/gym_output20200202-95104-1vwto0x'
[18:41:36]: The generated archive is invalid, this can have various reasons:
[18:41:36]: Usually it's caused by the `Skip Install` option in Xcode, set it to `NO`
[18:41:36]: For more information visit https://developer.apple.com/library/ios/technotes/tn2215/_index.html
[18:41:36]: Also, make sure to have a valid code signing identity and provisioning profile installed
[18:41:36]: Follow this guide to setup code signing https://docs.fastlane.tools/codesigning/GettingStarted/
[18:41:36]: If your intention was only to export an ipa be sure to provide a valid archive at the archive path.
[18:41:36]: This error might also happen if your workspace/project file is not in the root directory of your project.
[18:41:36]: To workaround that issue, you can wrap your calls to gym with
[18:41:36]: `Dir.chdir('../path/to/dir/containing/proj') do`
[18:41:36]: For an example you can check out
[18:41:36]: https://github.com/artsy/emission-nebula/commit/44fe51a7fea8f7d52f0f77d6c3084827fe5dd59e 

Environment

 
✅ fastlane environment ✅

Stack

Key Value
OS 10.15.3
Ruby 2.6.3
Bundler? true
Git git version 2.21.1 (Apple Git-122.3)
Installation Source ~/Work/Xcode Projects/MyApp/vendor/bundle/ruby/2.6.0/bin/fastlane
Host Mac OS X 10.15.3 (19D76)
Ruby Lib Dir /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib
OpenSSL Version LibreSSL 2.8.3
Is contained false
Is homebrew false
Is installed via Fabric.app false
Xcode Path /Applications/Xcode.app/Contents/Developer/
Xcode Version 11.3.1

System Locale

Variable Value
LANG en_US.UTF-8
LC_ALL
LANGUAGE

fastlane files:

`./fastlane/Fastfile`
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
#     https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
#     https://docs.fastlane.tools/plugins/available-plugins
#

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane

# load variables from .env file in the root if it exists
if File.exist?('../.env')
  open('../.env', 'r').readlines.each do |l|
    kv = l.split('=')
    ENV[kv[0]] = kv[1].chomp
  end
end

default_platform(:mac)

platform :mac do
  desc "MyApp"

  # Configuration
  projectFilename = "MyApp.xcodeproj"

  # Before Integration Tests (Xcode Server Bot)
  lane :before_integration do
    sigh(platform: "macos",
         output_path: '/Library/Developer/XcodeServer/ProvisioningProfiles', 
         skip_install: true)
  end

  # Generate Beta and export it to Latest folder
  lane :myappbeta do
    buildNumber = get_info_plist_value(path: "./Info.plist", key: "CFBundleVersion")
    version = get_version_number(xcodeproj: projectFilename,
                                  target: "MyAppPaddle"
    )
    versionedPath = "MyApp " + version
    versionedFullPath = "../MyApp Releases/Paddle/" + versionedPath
    zipFilename = versionedFullPath + "/MyApp Paddle " + version + "-" + buildNumber + ".zip"
    appFilename = versionedFullPath + "/MyApp 4.app"

    # Set up certificates and provisioning profiles
    match(
      platform: "macos",
      type: "developer_id"
    )

    # Note: To make this work, currently need to edit /Users/blah/Work/Xcode Projects/MyApp/vendor/bundle/ruby/2.6.0/gems/fastlane-2.141.0/gym/lib/gym/generators/package_command_generator_xcode7.rb
    # around line 102 and replace all ".pkg" with ".app"
    build_mac_app(scheme: "MyApp Paddle Beta",
      output_directory: versionedFullPath,
      export_method: "developer-id",
      )

    notarize(
      package: appFilename,
      print_log: 'true',
      verbose: 'true'
    )      
      
    # Compress to a zip file
    zip(path: versionedFullPath + "/MyApp 4.app",
        output_path: zipFilename
    )
  end

  # Generate MAS Beta and export it to Latest folder
  lane :masbeta do
    buildNumber = get_info_plist_value(path: "./Info.plist", key: "CFBundleVersion")
    version = get_version_number(xcodeproj: projectFilename,
                                  target: "MyAppMAS"
    )
    versionedPath = "MyApp " + version
    versionedFullPath = "../MyApp Releases/MAS/" + versionedPath
    zipFilename = versionedFullPath + "/MyApp MAS " + version + "-" + buildNumber + ".zip"
    appFilename = versionedFullPath + "/MyApp 4.app"

    # Set up certificates and provisioning profiles
    match(
      platform: "macos",
      type: "developer_id"
    )
    build_mac_app(scheme: "MyApp MAS Beta",
        output_directory: versionedFullPath,
        export_method: "developer-id",
      )

    notarize(
      package: appFilename,
      print_log: 'true',
      verbose: 'true'
    )      
  
    # Compress to a zip file
    zip(path: versionedFullPath + "/MyApp 4.app",
        output_path: zipFilename
    )
  end  

  # Build the Paddle release version, export it and create the Disk Image distribution
  lane :buildpaddle do
    buildNumber = get_info_plist_value(path: "./Info.plist", key: "CFBundleVersion")
    version = get_version_number(xcodeproj: projectFilename,
                                  target: "MyAppPaddle"
    )
    versionedPath = "MyApp " + version
    versionedFullPath = "../MyApp Releases/Paddle/" + versionedPath
    appFilename = versionedFullPath + "/MyApp 4.app"
    zipFilename = versionedFullPath + "/MyApp " + version + ".zip"
    dmgFilename = versionedFullPath + "/MyApp " + version + ".dmg"
    dsymFilename = versionedFullPath + "/MyApp 4.app.dSYM.zip"

    # Set up certificates and provisioning profiles
    match(
      platform: "macos",
      type: "developer_id"
    )

    # Build
    gym(scheme: "MyApp Paddle",
        output_directory: versionedFullPath,
        export_method: "developer-id",
        # export_options: {
        #   method: "developer-id",
        #   provisioningProfiles: { 
        #     "com.xxx.myapp" => "Direct_com.xxx.myapp.provisionprofile"
        #   },
        # },
        # export_xcargs: "-allowProvisioningUpdates"
      )
    
    # Unfortunately, Fastlane doesn't properly export the built product (it simply copies it from the xcarchive) and it doesn't
    # use the provided provisioning profile for signing.
    # UI.important "\n\nUnfortunately, right now, this is as far as Fastlane can go.\nNext step is to visit the Organiser, Notarise the app and export the notarised copy to " +appFilename + ".\nOnce that is done, run the paddlerelease lane to continue with distribution."
    # Notarize the app
    notarize(
      package: appFilename,
      print_log: 'true',
      verbose: 'true'
    )      
  end

  # Peform the release of the Paddle version. Notarize, ZIP, upload to AppCenter, DropDMG and upload to xxx.
  lane :releasepaddle do
    buildNumber = get_info_plist_value(path: "./Info.plist", key: "CFBundleVersion")
    version = get_version_number(xcodeproj: projectFilename,
                                  target: "MyAppPaddle"
    )
    versionedPath = "MyApp " + version
    versionedFullPath = "../MyApp Releases/Paddle/" + versionedPath
    appFilename = versionedFullPath + "/MyApp 4.app"
    zipFilename = versionedFullPath + "/MyApp " + version + ".zip"
    dmgFilename = versionedFullPath + "/MyApp " + version + ".dmg"
    dsymFilename = versionedFullPath + "/MyApp 4.app.dSYM.zip"
    
    # Compress to a zip file
    begin
      # Put this item in an error handler because it may fail (and otherwise cause execution to stop)
      sh("rm", "../" + zipFilename)
    rescue => ex
      UI.error(ex)
    end    
    zip(path: appFilename,
        output_path: zipFilename
    )

    # Upload to MS AppCenter
    appcenter_upload(
      api_token: ENV["APPCENTER_API_TOKEN"],
      owner_name: ENV["APPCENTER_OWNER_NAME"],
      app_name: ENV["APPCENTER_MACOS_APP_NAME_PADDLE"],
      app_os: 'MacOS',  
      file: appFilename,
      dsym: dsymFilename,
    )    

    # Generate custom Disk Image
    begin
      # Put this item in an error handler because it may fail (and otherwise cause execution to stop)
      sh("rm", "../" + dmgFilename)
    rescue => ex
      UI.error(ex)
    end    
    sh("dropdmg", 
       "--license-folder", 
       "./DropDMG/Default", 
       "--layout-folder", 
       "DropDMG", 
       "--config-name", 
       "MyApp 4", 
       "--base-name", 
       versionedPath, 
       "../" + versionedFullPath + "/MyApp 4.app"
    )

    # Upload disk image to xxx.xxx.com
    scp(host: "xxx.xxx.com",
        username: "username",
        upload: {
          src: dmgFilename,
          dst: "/var/www/xxx/releases"
        }
    )
    # Upload ZIP to xxx.xxx.com
    scp(host: "xxx.xxx.com",
        username: "username",
        upload: {
          src: zipFilename,
          dst: "/var/www/xxx/releases"
        }
    )
  end

  # Generate MAS Beta and export it to Latest folder
  lane :masrelease do
    buildNumber = get_info_plist_value(path: "./Info.plist", key: "CFBundleVersion")
    version = get_version_number(xcodeproj: projectFilename,
                                  target: "MyAppMAS"
    )
    versionedPath = "MyApp " + version
    versionedFullPath = "../MyApp Releases/MAS/" + versionedPath
    zipFilename = versionedFullPath + "/MyApp MAS " + version + "-" + buildNumber + ".zip"
    dsymFilename = versionedFullPath + "/MyApp 4.app.dSYM.zip"
    appFilename = versionedFullPath + "/MyApp 4.app"

    # Set up certificates and provisioning profiles
    match(
      platform: "macos",
      type: "appstore"
    )

    build_mac_app(scheme: "MyApp MAS",
      output_directory: versionedFullPath,
      # export_options: {
      #   method: "package",
      #   provisioningProfiles: { 
      #     "com.xxx.myapp" => "AppStore_com.xxx.myapp.provisionprofile"
      #   }
      # },
      # export_xcargs: "-allowProvisioningUpdates"
    )

    ### Note, Gym does not yet support exporting a .pkg required for uploading to the AppStore.
    ### Once Gym is complete, go to the Xcode Organizer and submit the build to the App Store.
    ### Keep an eye on this PR that adds support for Mac Pkg and AppStore uploads:
    ### https://github.com/fastlane/fastlane/pull/12195
    deliver(
      platform: "osx",
      skip_screenshots: "true",
      skip_metadata: "true",
      run_precheck_before_submit: "false",
      force: "true"
    )      

    # Upload to MS AppCenter
    appcenter_upload(
      api_token: ENV["APPCENTER_API_TOKEN"],
      owner_name: ENV["APPCENTER_OWNER_NAME"],
      app_name: ENV["APPCENTER_MACOS_APP_NAME_MAS"],
      app_os: 'MacOS',  
      file: appFilename,
      dsym: dsymFilename,
    )    
  end  

end

`./fastlane/Appfile`
app_identifier("com.xxx.myapp") # The bundle identifier of your app
apple_id("emailaddress") # Your Apple email address

# For more information about the Appfile, see:
#     https://docs.fastlane.tools/advanced/#appfile

fastlane gems

Gem Version Update-Status
fastlane 2.141.0 ✅ Up-To-Date

Loaded fastlane plugins:

Plugin Version Update-Status
fastlane-plugin-appcenter 1.7.1 ✅ Up-To-Date
fastlane-plugin-notarize 1.1.2 ✅ Up-To-Date
Loaded gems
Gem Version
did_you_mean 1.3.0
bundler 1.17.2
etc 1.0.1
forwardable 1.2.0
CFPropertyList 3.0.2
public_suffix 2.0.5
addressable 2.7.0
atomos 0.1.3
babosa 1.0.3
claide 1.0.3
colored 1.2
colored2 3.1.2
highline 1.7.10
commander-fastlane 4.4.6
declarative 0.0.10
declarative-option 0.1.0
digest-crc 0.4.1
unf_ext 0.0.7.6
unf 0.1.4
domain_name 0.5.20190701
dotenv 2.7.5
emoji_regex 1.0.1
excon 0.72.0
multipart-post 2.0.0
faraday 0.17.3
http-cookie 1.0.3
faraday-cookie_jar 0.0.6
faraday_middleware 0.13.1
fastimage 2.1.7
gh_inspector 1.1.3
jwt 2.1.0
memoist 0.16.2
multi_json 1.14.1
os 1.0.1
signet 0.12.0
googleauth 0.10.0
httpclient 2.8.3
mini_mime 1.0.2
uber 0.1.0
representable 3.0.4
retriable 3.1.2
google-api-client 0.36.4
google-cloud-env 1.3.0
google-cloud-errors 1.0.0
google-cloud-core 1.5.0
google-cloud-storage 1.25.1
json 2.3.0
mini_magick 4.10.1
multi_xml 0.6.0
plist 3.5.0
rubyzip 1.3.0
security 0.1.3
naturally 2.2.0
simctl 1.6.7
slack-notifier 2.3.2
terminal-notifier 2.0.0
unicode-display_width 1.6.1
terminal-table 1.8.0
tty-screen 0.7.0
tty-cursor 0.7.1
tty-spinner 0.9.3
word_wrap 1.0.0
nanaimo 0.2.6
xcodeproj 1.14.0
rouge 2.0.7
xcpretty 0.3.0
xcpretty-travis-formatter 1.0.0
fastlane-plugin-appcenter 1.7.1
fastlane-plugin-notarize 1.1.2
net-ssh 5.2.0
net-scp 2.0.0

generated on: 2020-02-02

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 3
  • Comments: 57 (29 by maintainers)

Most upvoted comments

I had the same issue: Exporting a Developer ID signed Mac OS application fails with a mysterious “archive invalid” message. It turns out that Fastlane 2.140.0 introduced a change to gym (see #16073) which causes it to always try to export a .pkg file instead of .app. Adding skip_package_pkg: true restores the old behavior and fixes the issue.

Confirming the same error. Can’t export Developer ID signed application. Adding skip_package_pkg: true to the gym settings fixes the issue.

@trondkr @eliottha Does setting export_method: ‘developer-id’ and skip_package_pkg: true work for you? If so, I can add a fix this week to do that by default for developer ID 💪

It worked for me.

I had the same issue: Exporting a Developer ID signed Mac OS application fails with a mysterious “archive invalid” message. It turns out that Fastlane 2.140.0 introduced a change to gym (see #16073) which causes it to always try to export a .pkg file instead of .app. Adding skip_package_pkg: true restores the old behavior and fixes the issue.

Actually, this workaround also has a rather nasty unintended side-effect of breaking exporting. Adding skip_package_pkg: true fixes the original error, but it then no longer processes any of the export options, rendering it basically useless for packaging macOS apps for distribution.

Seems this may need a proper fix after all…

@trondkr I used the one generated from Xcode when exporting the app. The options you select during the export change what goes into the file.

<?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>destination</key>
	<string>export</string>
	<key>method</key>
	<string>developer-id</string>
	<key>signingCertificate</key>
	<string>286A48D7AB9A32F47FE5DF8775A154</string>
	<key>signingStyle</key>
	<string>manual</string>
	<key>teamID</key>
	<string>xxxxxxx</string>
</dict>
</plist>

This issue will be auto-closed because there hasn’t been any activity for a few months. Feel free to open a new one if you still experience this problem 👍