To quickly play around with spaceship launch irb
in your terminal and execute require "spaceship"
.
In general the classes are pre-fixed with the ConnectAPI
module. If you want to use the legacy web API, make sure to use Tunes
, which is an artifact from when "App Store Connect" was still called "iTunes Connect".
Note: If you use both the Developer Portal and App Store Connect API, you'll have to login on both, as the user might have different user credentials.
token = Spaceship::ConnectAPI::Token.create(
key_id: 'the-key-id',
issuer_id: 'the-issuer-id',
filepath: File.absolute_path("../AuthKey_the-key-id.p8")
)
Spaceship::ConnectAPI.token = token
# Fetch all available applications
all_apps = Spaceship::ConnectAPI::App.all
# Find a specific app based on the bundle identifier
app = Spaceship::ConnectAPI::App.find("com.krausefx.app")
app = Spaceship::ConnectAPI.get_app(app_id: 1013943394).first
# Access information about the app
app.id # => 1013943394
app.name # => "Spaceship App"
app.bundle_id # => "com.krausefx.app"
app.sku # => "SpaceshipApp01"
app.primary_locale # => "en-US"
# Show the names of all your apps
Spaceship::ConnectAPI::App.all.collect do |app|
app.name
end
# Create a new app
# Currently only works with Apple ID login (not API Key)
app = Spaceship::ConnectAPI::App.create(name: "App Name",
version_string: "1.0", # initial version
sku: "123",
primary_locale: "English",
bundle_id: "com.krausefx.app",
platforms: ["IOS"],
company_name: "krause inc")
To update non version specific details, use the following code
app = Spaceship::Tunes::Application.find("com.krausefx.app")
details = app.details
details.name['en-US'] = "App Name"
details.privacy_url['en-US'] = "https://fastlane.tools"
details.save!
To change the price of the app (it's not necessary to call save!
when updating the price)
app = Spaceship::Tunes::Application.find("com.krausefx.app")
app.update_price_tier!("3")
You can have up to 2 app versions at the same time. One is usually the version already available in the App Store (get_live_app_store_version
) and one being the one you can edit (get_edit_app_store_version
).
While you usually can modify some values in the production version (e.g. app description), most options are already locked.
With spaceship you can access the versions like this
app.get_live_app_store_version # the version that's currently available in the App Store
app.get_edit_app_store_version # the version that's in `Prepare for Submission`, `Metadata Rejected`, `Rejected`, `Developer Rejected`, `Waiting for Review`, `Invalid Binary` mode
app.get_latest_app_store_version # the version that's the latest one
app.get_pending_release_app_store_version # the version that's in `Pending Developer Release` or `Pending Apple Release` mode
app.get_in_review_app_store_version # the version that is in `In Review` mode
You can then go ahead and modify app metadata on the version objects:
v = app.get_edit_app_store_version
# Access information
v.app_version_state # => "Waiting for Review"
v.version_string # => "0.9.14"
# Build is not always available in all app_version_state, e.g. not available in `Prepare for Submission`
build_number = v.build.nil? ? nil : v.build.version
# Update app metadata
copyright = "#{Time.now.year} Felix Krause"
v.update(attributes: { "copyright": copyright })
# Get a list of available languages for this app
version = app.get_edit_app_store_version(includes: 'appStoreVersionSubmission,build,appStoreVersionLocalizations')
localizations = version.appStoreVersionLocalizations
localization = localizations.first
localization.locale # => "en-GB"
localization.description # => "App description"
# Update localized app metadata
localization.update(attributes: { description: "New Description" })
# set the app age rating
# fetch_age_rating_declaration with `fetch_live_app_info` or `fetch_edit_app_info`
app_info = app.fetch_edit_app_info
declaration = app_info.fetch_age_rating_declaration unless app_info.nil?
# update age_rating_declaration
declaration.update(attributes: {
"violenceCartoonOrFantasy": "NONE",
"matureOrSuggestiveThemes": "NONE",
"unrestrictedWebAccess": false
})
# Available values:
# https://github.com/fastlane/fastlane/blob/master/deliver/assets/example_rating_config.json
# https://docs.fastlane.tools/actions/deliver/#reference (Open "View all available categories, languages, etc.")
Available options:
####
# General app store version metadata (app_store_version)
####
attr_accessor :platform
attr_accessor :version_string
attr_accessor :app_store_state
attr_accessor :app_version_state
attr_accessor :store_icon
attr_accessor :watch_store_icon
attr_accessor :copyright
attr_accessor :release_type
attr_accessor :earliest_release_date
attr_accessor :is_watch_only
attr_accessor :downloadable
attr_accessor :created_date
attr_accessor :app_store_version_submission
attr_accessor :app_store_version_phased_release
attr_accessor :app_store_review_detail
attr_accessor :app_store_version_localizations
####
# App Review Information (app_store_review_detail)
####
attr_accessor :contact_first_name
attr_accessor :contact_last_name
attr_accessor :contact_phone
attr_accessor :contact_email
attr_accessor :demo_account_name
attr_accessor :demo_account_password
attr_accessor :demo_account_required
attr_accessor :notes
attr_accessor :app_store_review_attachments
####
# Localized values (app_store_version_localization)
####
attr_accessor :description
attr_accessor :locale
attr_accessor :keywords
attr_accessor :marketing_url
attr_accessor :promotional_text
attr_accessor :support_url
attr_accessor :whats_new
attr_accessor :app_screenshot_sets
attr_accessor :app_preview_sets
Important: For a complete documentation with the return type, description and notes for each of the properties, check out app_store_version.rb and other models.
For a full list of available options, check out submit_for_review.rb
version = app.get_edit_app_store_version
build = Spaceship::ConnectAPI::Build.all(app_id: app.id, platform: platform).first
version.select_build(build_id: build.id)
# Check out submit_for_review.rb to get an overview how to modify submission information
version.create_app_store_version_submission
Important: For a complete example how to prepare version for review and submit it for review check out submit_for_review.rb.
version = app.get_pending_release_app_store_version
unless version.nil?
Spaceship::ConnectAPI.post_app_store_version_release_request(app_store_version_id: version.id)
end
or
version = app.get_pending_release_app_store_version
version.create_app_store_version_release_request unless version.nil?
To clarify:
- version number: Is set via the
CFBundleShortVersionString
property. It's the version number that appears on the App Store. (0.9.21
on the screenshot) - build number: Is set via the
CFBundleVersion
property. It's not visible in the App Store. It has to be incremented before uploading a new build. (99993
on the screenshot)
A build train contains all builds for a give version number
(e.g. 0.9.21
). Within the build train you have n builds, each having a different build number
(e.g. 99993
).
app = Spaceship::Tunes::Application.find("com.krausefx.app")
# Access all build trains for an app
app.all_build_train_numbers # => ["0.9.21"]
# Access the build train via the version number
train = app.build_trains["0.9.21"]
# Access all builds for a given train
train.count # => 1
build = train.first
# Continue from the BuildTrains example
build.build_version # => "99993" (the build number)
build.train_version # => "0.9.21" (the version number)
build.install_count # => 1
build.crash_count # => 0
build.internal_state # => testflight.build.state.testing.ready
build.external_state # => testflight.build.state.submit.ready
You can even submit a build for external beta review (after you have set all necessary metadata - see above)
build.submit_for_testflight_review!
To also access those builds that are "stuck" at Processing
at App Store Connect for a while:
Spaceship::ConnectAPI::Build.all(app_id: app.id, processing_states: "PROCESSING") # => Array of processing builds for this application
There are 3 types of testers:
- External testers: usually not part of your team. You can invite up to 10000 external testers. Before distributing a build to those testers you need to submit your app to beta review.
- Internal testers: Employees that are registered in your App Store Connect team. They get access to all builds without having to wait for review.
- Sandbox testers: Dummy accounts to test development-mode apps with in-app purchase or Apple Pay.
# Find a tester based on the email address
tester = Spaceship::TestFlight::Tester.find(app_id: "some_app_id", email: "felix@krausefx.com")
tester = Spaceship::ConnectAPI::BetaTester.find(email: "felix@krausefx.com")
# Creating new testers
Spaceship::TestFlight::Tester.create_app_level_tester(
app_id: "io.myapp",
email: "github@krausefx.com",
first_name: "Felix",
last_name: "Krause"
)
Right now, spaceship can't modify or create internal testers.
# Load all sandbox testers
testers = Spaceship::ConnectAPI::SandboxTester.all
# Delete sandbox testers
testers.each do |tester|
if UI.confirm("Delete #{tester.email}?")
tester.delete!
end
end
# Create a sandbox tester
testers = Spaceship::ConnectAPI::SandboxTester.create(
first_name: "Test", # required
last_name: "Three", # required
email: "sandbox@test.com", # required
password: "Passwordtest1", # required. Must contain >=8 characters, >=1 uppercase, >=1 lowercase, >=1 numeric.
confirm_password: "Passwordtest1", # required
secret_question: "Question", # required. Must contain >=6 characters
secret_answer: "Answer", # required. Must contain >=6 characters
birth_date: "1980-03-01", # required
app_store_territory: "USA" # required
)
app = Spaceship::Tunes::Application.find("com.krausefx.app")
# Get the rating summary for an application
ratings = app.ratings # => Spaceship::Tunes::AppRatings
# Get the number of 5 star ratings
five_star_count = ratings.five_star_rating_count
# Find the average rating across all stores
average_rating = ratings.average_rating
# Find the average rating for a given store front
average_rating = app.ratings(storefront: "US").average_rating
# Get reviews for a given store front
reviews = ratings.reviews("US") # => Array of hashes representing review data
app = Spaceship::Tunes::Application.find("com.krausefx.app")
# Start app analytics
analytics = app.analytics # => Spaceship::Tunes::AppAnalytics
# Get all the different metrics from App Analytics
# By default covering the last 7 days
# Get app units
units = analytics.app_units # => Array of dates representing raw data for each day
# Get app store page views
views = analytics.app_views # => Array of dates representing raw data for each day
# Get impressions metrics
impressions = analytics.app_impressions # => Array of dates representing raw data for each day
# Get app sales
sales = analytics.app_sales # => Array of dates representing raw data for each day
# Get paying users
users = analytics.paying_users # => Array of dates representing raw data for each day
# Get in app purchases
iap = analytics.app_in_app_purchases # => Array of dates representing raw data for each day
# Get app installs
installs = analytics.app_installs # => Array of dates representing raw data for each day
# Get app sessions
sessions = analytics.app_sessions # => Array of dates representing raw data for each day
# Get active devices
devices = analytics.app_active_devices # => Array of dates representing raw data for each day
# Get crashes
crashes = analytics.app_crashes # => Array of dates representing raw data for each day
# Fetch all bundle identifiers
all_identifiers = Spaceship::ConnectAPI::BundleId.all
# Find a specific identifier based on the bundle identifier
bundle_id = Spaceship::ConnectAPI::BundleId.find("com.krausefx.app")
# Access information about the bundle identifier
bundle_id.name
bundle_id.platform
bundle_id.identifier
bundle_id.seed_id
# Create a new identifier
identifier = Spaceship::ConnectAPI::BundleId.create(name: "Description of the identifier",
identifier: "com.krausefx.app")
Note: Platform will be set to UNIVERSAL no matter if you specify IOS or MAC_OS and seed_id is by default set to team_id
# Fetch all capabilities for bundle identifier
bundle_id = Spaceship::ConnectAPI::BundleId.find("com.krausefx.app")
capabilities = bundle_id.get_capabilities
# Create a new capability for bundle identifier
bundle_id.create_capability(Spaceship::ConnectAPI::BundleIdCapability::Type::MAPS)
# Create a new capability with known bundle identifier id
bundle_id_capability = Spaceship::ConnectAPI::BundleIdCapability.create(bundle_id_id: "123456789",
capability_type: Spaceship::ConnectAPI::BundleIdCapability::Type::MAPS)
# Delete an capability from bundle identifier
capabilities.each do |capability|
if capability.capability_type == Spaceship::ConnectAPI::BundleIdCapability::Type::MAPS
capability.delete!
end
end
This project and all fastlane tools are in no way affiliated with Apple Inc. This project is open source under the MIT license, which means you have full access to the source code and can modify it to fit your own needs. All fastlane tools run on your own computer or server, so your credentials or other sensitive information will never leave your own computer. You are responsible for how you use fastlane tools.