Fastlane AppStore 执行流程分析

Fastlane AppStore 执行流程分析 

主要看   spaceship 和deliver 两个模块

 

spaceship 导出了 Apple Developer Center and the App Store Connect API 据说是 所有你能在浏览器端做的 它都可以做到

而 deliver 模块 则是 负责进行数据的上传和下载,根据 AppStore 上传的流程  跟以下 主要跟一下 deliver 的执行流程

我们在终端执行 fastlane deliver 的时候  fastlane 会根据加载的  Actions 列表里面匹配出 Deliver Action

之前的过程略过不讲 从 Deliver Run 讲起!

Fastlane AppStore 执行流程分析

 

 

 每个Action 的 commands_generator 中,能够找到匹配的 command, 直接查看它的 run 流程,这里以 deliver 为例 生成命令的过程略过

 1、 首先 根据配置项 从 Deliverfile 配置文件中读取配置 加载相关数据

 2、如果配置加载失败 就 启动 Runner 登陆后台,拉取远程默认配置 启动Setup 创建默认配置文件

Fastlane AppStore 执行流程分析

 

 

 这里可以看到 new出来的  Deliver::Runner 干了些啥事情呢 就是登陆 然后 检查数据 DetectValue 

Fastlane AppStore 执行流程分析

 

 

 DetectValue 找到 各个相关主要对象,包括本地配置和远程拉取数据。比如 App, AppID, AppVersion, 检查可用的语言版本等等。总而言之 这一切都是为了构造 option 这个数据结构 为了接下来的操作 

 Fastlane AppStore 执行流程分析

 

 

 setup 就是检查 Fastlane 的配置文件系统 根据配置 如果没有就创建默认的

 3、配置加载成功了 就启动 Deliver::Runner  run 开始上传或者下载

看看 Deliver::Runner 的 run 

    def run
      verify_version if options[:app_version].to_s.length > 0 && !options[:skip_app_version_update]
      upload_metadata

      has_binary = (options[:ipa] || options[:pkg])
      if !options[:skip_binary_upload] && !options[:build_number] && has_binary
        upload_binary
      end

      UI.success("Finished the upload to App Store Connect") unless options[:skip_binary_upload]

      reject_version_if_possible if options[:reject_if_possible]

      precheck_success = precheck_app
      submit_for_review if options[:submit_for_review] && precheck_success
    end

 上传metadata  上传二进制 binary  检查app  完了后提交

 其中 upload_metadata 方法就是每个事情一个对象,代码很清晰。从本地加载后,开始 upload 。

def upload_metadata
      upload_metadata = UploadMetadata.new
      upload_screenshots = UploadScreenshots.new

      # First, collect all the things for the HTML Report
      screenshots = upload_screenshots.collect_screenshots(options)
      upload_metadata.load_from_filesystem(options)

      # Assign "default" values to all languages
      upload_metadata.assign_defaults(options)

      # Handle app icon / watch icon
      prepare_app_icons(options)

      # Validate
      validate_html(screenshots)

      # Commit
      upload_metadata.upload(options)
      upload_screenshots.upload(options, screenshots)
      UploadPriceTier.new.upload(options)
    end

 着重看一下 UploadMetadata 的 upload 方法 

def upload(options)
      return if options[:skip_metadata]
      require pp

      legacy_app = options[:app]
      app_id = legacy_app.apple_id
      app = Spaceship::ConnectAPI::App.get(app_id: app_id)

      platform = Spaceship::ConnectAPI::Platform.map(options[:platform])

      app_store_version_localizations = verify_available_languages!(options, app) unless options[:edit_live]

      if options[:edit_live]
        # not all values are editable when using live_version
        version = app.get_ready_for_sale_app_store_version(platform: platform)
        localised_options = LOCALISED_LIVE_VALUES
        non_localised_options = NON_LOCALISED_LIVE_VALUES

        if v.nil?
          UI.message("Couldn‘t find live version, editing the current version on App Store Connect instead")
          version = app.get_edit_app_store_version(platform: platform)
          # we don‘t want to update the localised_options and non_localised_options
          # as we also check for `options[:edit_live]` at other areas in the code
          # by not touching those 2 variables, deliver is more consistent with what the option says
          # in the documentation
        else
          UI.message("Found live version")
        end
      else
        version = app.get_edit_app_store_version(platform: platform)
        localised_options = (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES)
        non_localised_options = NON_LOCALISED_VERSION_VALUES.keys
        category_options = NON_LOCALISED_APP_VALUES
      end

      UI.important("Will begin uploading metadata for ‘#{version.version_string}‘ on App Store Connect")

      localized_version_attributes_by_locale = {}

      individual = options[:individual_metadata_items] || []
      localised_options.each do |key|
        current = options[key]
        next unless current

        unless current.kind_of?(Hash)
          UI.error("Error with provided ‘#{key}‘. Must be a hash, the key being the language.")
          next
        end

        current.each do |language, value|
          next unless value.to_s.length > 0
          strip_value = value.to_s.strip
          
          if LOCALISED_VERSION_VALUES.include?(key) && !strip_value.empty?
            attribute_name = LOCALISED_VERSION_VALUES[key]

            localized_version_attributes_by_locale[language] ||= {}
            localized_version_attributes_by_locale[language][attribute_name] = strip_value
          end

          if LOCALISED_APP_VALUES.include?(key)
            # puts "LOCALISED_APP_VALUES: NEED TO SEND #{key} #{language}"
            # puts "\t#{value}"
          end

        end
      end

      non_localized_version_attributes = {}
      non_localised_options.each do |key|
        strip_value = options[key].to_s.strip
        next unless strip_value.to_s.length > 0

        if NON_LOCALISED_VERSION_VALUES.include?(key) && !strip_value.empty?
          attribute_name = NON_LOCALISED_VERSION_VALUES[key]
          non_localized_version_attributes[attribute_name] = strip_value
        end
      end

      release_type = if options[:auto_release_date]
        non_localized_version_attributes[earliestReleaseDate] = options[:auto_release_date]
        Spaceship::ConnectAPI::AppStoreVersion::ReleaseType::SCHEDULED
      elsif options[:automatic_release]
        Spaceship::ConnectAPI::AppStoreVersion::ReleaseType::AFTER_APPROVAL
      else
        Spaceship::ConnectAPI::AppStoreVersion::ReleaseType::MANUAL
      end
      non_localized_version_attributes[releaseType] = release_type

      # Update app store version localizations
      app_store_version_localizations.each do |app_store_version_localization|
        attributes = localized_version_attributes_by_locale[app_store_version_localization.locale]
        if attributes
          UI.message("Uploading metadata to App Store Connect for localized version ‘#{app_store_version_localization.locale}‘")
          app_store_version_localization.update(attributes: attributes)
        end
      end

      # Update app store version
      UI.message("Uploading metadata to App Store Connect for version")
      version.update(attributes: non_localized_version_attributes)

      # Update categories
      app_info = app.get_edit_app_info
      if app_info
        app_info.update_categories(
          primary_category_id: Spaceship::ConnectAPI::AppCategory.map_category_from_itc(
            options[:primary_category].to_s.strip
          ), 
          secondary_category_id: Spaceship::ConnectAPI::AppCategory.map_category_from_itc(
            options[:secondary_category].to_s.strip
          ), 
          primary_subcategory_one_id: Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
            options[:primary_first_sub_category].to_s.strip
          ), 
          primary_subcategory_two_id: Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
            options[:primary_second_sub_category].to_s.strip
          ), 
          secondary_subcategory_one_id: Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
            options[:secondary_first_sub_category].to_s.strip
          ), 
          secondary_subcategory_two_id: Spaceship::ConnectAPI::AppCategory.map_subcategory_from_itc(
            options[:secondary_second_sub_category].to_s.strip
          )
        )
      end


      # Update phased release
      unless options[:phased_release].nil?
        phased_release = version.get_app_store_version_phased_release rescue nil # returns no data error so need to rescue
        if !!options[:phased_release]
          unless phased_release
            UI.message("Creating phased release on App Store Connect")
            version.create_app_store_version_phased_release(attributes: {
              phasedReleaseState: Spaceship::ConnectAPI::AppStoreVersionPhasedRelease::PhasedReleaseState::INACTIVE
            })
          end
        elsif phased_release
          UI.message("Removing phased release on App Store Connect")
          phased_release.delete!
        end
      end

      # Update rating reset
      unless options[:reset_ratings].nil?
        reset_rating_request = version.get_reset_ratings_request rescue nil # returns no data error so need to rescue
        if !!options[:reset_ratings]
          unless reset_rating_request
            UI.message("Creating reset ratings request on App Store Connect")
            version.create_reset_ratings_request
          end
        elsif reset_rating_request
          UI.message("Removing reset ratings request on App Store Connect")
          reset_rating_request.delete!
        end
      end

      set_review_information(version, options)
      set_review_attachment_file(version, options)

      # set_app_rating(version, options)
    end

流程很清晰 针对AppStore 后台的各个模块 做了相应的操作!

 

前面 ItuneConnect 后台做了较大的改版  fastlane 也做了较大的更新 以前的接口会报 Potential Server Errors

https://github.com/fastlane/fastlane/blob/master/spaceship/docs/DeveloperPortal.md

这个接口文档 基本用不了了

新版 参考这里  

Support new App Store Connect APIs

https://github.com/fastlane/fastlane/pull/16640

Fastlane AppStore 执行流程分析

上一篇:svg上实现图形移动


下一篇:软件开发人员的编程障碍,你知道多少?