class Spaceship::Portal::ProvisioningProfile

Represents a provisioning profile of the Apple Dev Portal

NOTE: If the environment variable `SPACESHIP_AVOID_XCODE_API` is present when using this class, all requests will be made via Apple developer portal API. In the default case, this class will use the Xcode API for fetching provisioning profiles. This is an optimization that results in 1 query for all Profiles vs 1+N queries.

Attributes

app[RW]

A reference to the app this profile is for. You can then easily access the value directly @return (App) The app this profile is for

@example Example Value

<Spaceship::Portal::App
  @app_id="2UMR2S6PAA"
  @name="App Name"
  @platform="ios"
  @prefix="5A997XSAAA"
  @bundle_id="com.krausefx.app"
  @is_wildcard=false
  @dev_push_enabled=false
  @prod_push_enabled=false>

@example Usage

profile.app.name
certificates[RW]

@return (Array) A list of certificates used for this profile @example Example Value

[
 <Spaceship::Portal::Certificate::Production
   @status=nil
   @id="XC5PH8D4AA"
   @name="iOS Distribution"
   @created=nil
   @expires=#<DateTime: 2015-11-25T22:45:50+00:00 ((2457352j,81950s,0n),+0s,2299161j)>
   @owner_type="team"
   @owner_name=nil
   @owner_id=nil
   @type_display_id="R58UK2EWAA">]
]

@example Usage

profile.certificates.first.id
devices[RW]

@return (Array) A list of devices this profile is enabled for.

This will always be [] for AppStore profiles

@example Example Value

<Spaceship::Portal::Device
  @id="WXQ7V239BE"
  @name="Grahams iPhone 4s"
  @udid="ba0ac7d70f7a14c6fa02ef0e02f4fe9c5178e2f7"
  @platform="ios"
  @status="c">]

@example Usage

profile.devices.first.name
distribution_method[RW]

@return (String) The profile distribution type. You probably want to

use the class type to detect the profile type instead of this string.

@example AppStore Profile

"store"

@example AdHoc Profile

"adhoc"

@example Development Profile

"limited"

@example Mac Developer ID Profile

"direct"
expires[RW]

@return (DateTime) The date and time of when the profile

expires.

@example

#<DateTime: 2015-11-25T22:45:50+00:00 ((2457352j,81950s,0n),+0s,2299161j)>
id[RW]

@return (String) The ID generated by the Dev Portal

You'll probably not really need this value

@example

"2MAY7NPHAA"
is_template_profile[RW]

@return (Bool) Does the profile use a template (has extended entitlements)?

@example

false
managing_app[RW]

No information about this attribute

name[RW]

@return (String) The name of this profile @example

"com.krausefx.app AppStore"
platform[RW]

@return (String) The supported platform for this profile @example

"ios"
profile_details[RW]

This is the second level request, which is done before creating the object this includes information about the devices and the certificates more information on this issue github.com/fastlane/fastlane/issues/6137

status[RW]

@return (String) The status of this profile @example Active (profile is fine)

"Active"

@example Expired (time ran out)

"Expired"

@example Invalid (e.g. code signing identity not available any more)

"Invalid"
sub_platform[RW]

@return (String) The supported sub_platform for this profile @example

"tvOS"
template[RW]

@return (Spaceship::Portal::ProvisioningProfileTemplate)

Model representation of the provisioning profile template.
This will be always nil if is_template_profile returns false

@example Example Value

<Spaceship::Portal::ProvisioningProfileTemplate
  @template_description="Subscription Service iOS (dist)",
  @entitlements=nil,
  @purpose_description="Generic Provisioning Profile Template for App: com.apple.smoot.subscriptionservice",
  @purpose_display_name="Subscription Service iOS (dist)",
  @purpose_name="Subscription Service iOS (dist)",
  @version=1>

@example Usage

profile.template.purpose_display_name
type[RW]

@return (String) The type of the profile (development or distribution).

You'll probably not need this value

@example Distribution

"iOS Distribution"

@example Development

"iOS Development"
uuid[RW]

@return (String) The UDID of this provisioning profile

This value is used for example for code signing
It is also contained in the actual profile

@example

"23d7df3b-9767-4e85-a1ea-1df4d8f32fec"
version[RW]

@return (String) This will always be “2” @example

"2"

Public Class Methods

all(mac: false, xcode: false) click to toggle source

@return (Array) Returns all profiles registered for this account

If you're calling this from a subclass (like AdHoc), this will
only return the profiles that are of this type

@param mac (Bool) (optional): Pass true to get all Mac provisioning profiles @param xcode (Bool) (optional): Pass true to include Xcode managed provisioning profiles

# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 315
def all(mac: false, xcode: false)
  if ENV['SPACESHIP_AVOID_XCODE_API']
    profiles = client.provisioning_profiles(mac: mac)
  else
    profiles = client.provisioning_profiles_via_xcode_api(mac: mac)
  end

  # transform raw data to class instances
  profiles.map! { |profile| self.factory(profile) }

  # filter out the profiles managed by xcode
  unless xcode
    profiles.delete_if(&:managed_by_xcode?)
  end

  return profiles if self == ProvisioningProfile
  return profiles.select { |profile| profile.class == self }
end
all_tvos() click to toggle source

@return (Array) Returns all profiles registered for this account

If you're calling this from a subclass (like AdHoc), this will
only return the profiles that are of this type
# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 337
def all_tvos
  profiles = all(mac: false)
  tv_os_profiles = []
  profiles.each do |tv_os_profile|
    if tv_os_profile.tvos?
      tv_os_profiles << tv_os_profile
    end
  end
  return tv_os_profiles
end
create!(name: nil, bundle_id: nil, certificate: nil, devices: [], mac: false, sub_platform: nil, template_name: nil) click to toggle source

Create a new provisioning profile @param name (String): The name of the provisioning profile on the Dev Portal @param bundle_id (String): The app identifier, this parameter is required @param certificate (Certificate): The certificate that should be used with this

provisioning profile. You can also pass an array of certificates to this method. This will
only work for development profiles

@param devices (Array) (optional): An array of Device objects that should be used in this profile.

It is recommend to not pass devices as spaceship will automatically add all devices for AdHoc
and Development profiles and add none for AppStore and Enterprise Profiles

@param mac (Bool) (optional): Pass true if you're making a Mac provisioning profile @param sub_platform (String) Used to create tvOS profiles at the moment. Value should equal 'tvOS' or nil. @param template_name (String) (optional): The name of the provisioning profile template.

The value can be found by inspecting the Entitlements drop-down when creating/editing a
provisioning profile in Developer Portal.

@return (ProvisioningProfile): The profile that was just created

# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 260
def create!(name: nil, bundle_id: nil, certificate: nil, devices: [], mac: false, sub_platform: nil, template_name: nil)
  raise "Missing required parameter 'bundle_id'" if bundle_id.to_s.empty?
  raise "Missing required parameter 'certificate'. e.g. use `Spaceship::Portal::Certificate::Production.all.first`" if certificate.to_s.empty?

  app = Spaceship::Portal::App.find(bundle_id, mac: mac)
  raise "Could not find app with bundle id '#{bundle_id}'" unless app

  raise "Invalid sub_platform #{sub_platform}, valid values are tvOS" if !sub_platform.nil? && sub_platform != 'tvOS'

  # Fill in sensible default values
  name ||= [bundle_id, self.pretty_type].join(' ')

  if self == AppStore || self == InHouse || self == Direct
    # Distribution Profiles MUST NOT have devices
    devices = []
  end

  certificate_parameter = certificate.collect(&:id) if certificate.kind_of?(Array)
  certificate_parameter ||= [certificate.id]

  # Fix https://github.com/KrauseFx/fastlane/issues/349
  certificate_parameter = certificate_parameter.first if certificate_parameter.count == 1

  if devices.nil? || devices.count == 0
    if self == Development || self == AdHoc
      # For Development and AdHoc we usually want all compatible devices by default
      if mac
        devices = Spaceship::Portal::Device.all_macs
      elsif sub_platform == 'tvOS'
        devices = Spaceship::Portal::Device.all_apple_tvs
      else
        devices = Spaceship::Portal::Device.all_ios_profile_devices
      end
    end
  end

  profile = client.with_retry do
    client.create_provisioning_profile!(name,
                                        self.type,
                                        app.app_id,
                                        certificate_parameter,
                                        devices.map(&:id),
                                        mac: mac,
                                        sub_platform: sub_platform,
                                        template_name: template_name)
  end

  self.new(profile)
end
factory(attrs) click to toggle source

Create a new object based on a hash. This is used to create a new object based on the server response.

# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 195
def factory(attrs)
  # available values of `distributionMethod` at this point: ['adhoc', 'store', 'limited', 'direct', 'inhouse']
  klass = case attrs['distributionMethod']
          when 'limited'
            Development
          when 'store'
            AppStore
          when 'adhoc'
            AdHoc
          when 'inhouse'
            InHouse
          when 'direct'
            Direct # Mac-only
          else
            raise "Can't find class '#{attrs['distributionMethod']}'"
          end

  # Parse the dates
  # rubocop:disable Style/RescueModifier
  attrs['dateExpire'] = (Time.parse(attrs['dateExpire']) rescue attrs['dateExpire'])
  # rubocop:enable Style/RescueModifier

  # When a profile is created with a template name, the response
  # (provisioning profiles info) already contains the data about
  # template, which is used to instantiate the
  # ProvisioningProfileTemplate model.
  # Doing so saves an API call needed to fetch profile details.
  #
  # Verify if `attrs` contains the info needed to instantiate a template.
  # If not, the template will be lazily loaded.
  if attrs['profile'] && attrs['profile']['description']
    attrs['template'] = ProvisioningProfileTemplate.factory(attrs['template'])
  end

  klass.client = @client
  obj = klass.new(attrs)

  return obj
end
find_by_bundle_id(bundle_id: nil, mac: false, sub_platform: nil) click to toggle source

@return (Array) Returns an array of provisioning

profiles matching the bundle identifier
Returns [] if no profiles were found
This may also contain invalid or expired profiles
# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 352
def find_by_bundle_id(bundle_id: nil, mac: false, sub_platform: nil)
  raise "Missing required parameter 'bundle_id'" if bundle_id.to_s.empty?
  raise "Invalid sub_platform #{sub_platform}, valid values are tvOS" if !sub_platform.nil? && sub_platform != 'tvOS'
  find_tvos_profiles = sub_platform == 'tvOS'
  all(mac: mac).find_all do |profile|
    profile.app.bundle_id == bundle_id && profile.tvos? == find_tvos_profiles
  end
end
pretty_type() click to toggle source

@return (String) The human readable name of this profile type. @example

"AppStore"
"AdHoc"
"Development"
"InHouse"
# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 241
def pretty_type
  name.split('::').last
end
type() click to toggle source

@return (String) The profile type used for web requests to the Dev Portal @example

"limited"
"store"
"adhoc"
"inhouse"
# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 189
def type
  raise "You cannot create a ProvisioningProfile without a type. Use a subclass."
end

Public Instance Methods

certificate_valid?() click to toggle source

Is the certificate of this profile available? @return (Bool) is the certificate valid?

# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 474
def certificate_valid?
  return false if (certificates || []).count == 0
  certificates.each do |c|
    if Spaceship::Portal::Certificate.all(mac: mac?).collect(&:id).include?(c.id)
      return true
    end
  end
  return false
end
delete!() click to toggle source

Delete the provisioning profile

# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 409
def delete!
  client.delete_provisioning_profile!(self.id, mac: mac?)
end
download() click to toggle source

Download the current provisioning profile. This will not store the provisioning profile on the file system. Instead this method will return the content of the profile. @return (String) The content of the provisioning profile

You'll probably want to store it on the file system

@example

File.write("path.mobileprovision", profile.download)
# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 404
def download
  client.download_provisioning_profile(self.id, mac: mac?)
end
mac?() click to toggle source

@return (Bool) Is this a Mac provisioning profile?

# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 496
def mac?
  platform == 'mac'
end
managed_by_xcode?() click to toggle source

@return (Bool) Is this profile managed by Xcode?

# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 491
def managed_by_xcode?
  managing_app == 'Xcode'
end
repair!() click to toggle source

Repair an existing provisioning profile alias to update! @return (ProvisioningProfile) A new provisioning profile, as

the repair method will generate a profile with a new ID
# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 417
def repair!
  update!
end
template_name() click to toggle source

@return (String) The name of the template (as displayed in Dev Portal)

or nil if provisioning profile doesn't have a template
# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 554
def template_name
  is_template_profile ? template.purpose_display_name : nil
end
tvos?() click to toggle source

@return (Bool) Is this a tvos provisioning profile?

# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 501
def tvos?
  sub_platform == 'tvOS'
end
update!() click to toggle source

Updates the provisioning profile from the local data e.g. after you added new devices to the profile This will also update the code signing identity if necessary @return (ProvisioningProfile) A new provisioning profile, as

the repair method will generate a profile with a new ID
# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 426
def update!
  # sigh handles more specific filtering and validation steps that make this logic OK
  #
  # This is the minimum protection needed for people using spaceship directly
  unless certificate_valid?
    if mac?
      if self.kind_of?(Development)
        self.certificates = [Spaceship::Portal::Certificate::MacDevelopment.all.first]
      elsif self.kind_of?(Direct)
        self.certificates = [Spaceship::Portal::Certificate::DeveloperIdApplication.all.first]
      else
        self.certificates = [Spaceship::Portal::Certificate::MacAppDistribution.all.first]
      end
    else
      if self.kind_of?(Development)
        self.certificates = [Spaceship::Portal::Certificate::Development.all.first]
      elsif self.kind_of?(InHouse)
        self.certificates = [Spaceship::Portal::Certificate::InHouse.all.first]
      else
        self.certificates = [Spaceship::Portal::Certificate::Production.all.first]
      end
    end
  end

  client.with_retry do
    client.repair_provisioning_profile!(
      id,
      name,
      distribution_method,
      app.app_id,
      certificates.map(&:id),
      devices.map(&:id),
      mac: mac?,
      sub_platform: tvos? ? 'tvOS' : nil,
      template_name: is_template_profile ? template.purpose_name : nil
    )
  end

  # We need to fetch the provisioning profile again, as the ID changes
  profile = Spaceship::Portal::ProvisioningProfile.all(mac: mac?).find do |p|
    p.name == self.name # we can use the name as it's valid
  end

  return profile
end
valid?() click to toggle source

@return (Bool) Is the current provisioning profile valid?

To also verify the certificate call certificate_valid?
# File spaceship/lib/spaceship/portal/provisioning_profile.rb, line 486
def valid?
  return status == 'Active'
end