module Fastlane module Actions module SharedValues end class UpdateInfoPlistAction < Action def self.run(params) # Check if parameters are set if params[:app_identifier] || params[:display_name] || params[:block] if (params[:app_identifier] || params[:display_name]) && params[:block] UI.important("block parameter can not be specified with app_identifier or display_name") return false end # Assign folder from parameter or search for xcodeproj file folder = params[:xcodeproj] || Dir["*.xcodeproj"].first if params[:scheme] project = Xcodeproj::Project.open(folder) scheme = project.native_targets.detect { |target| target.name == params[:scheme] } UI.user_error!("Couldn't find scheme named '#{params[:scheme]}'") unless scheme params[:plist_path] = scheme.build_configurations.first.build_settings["INFOPLIST_FILE"] UI.user_error!("Scheme named '#{params[:scheme]}' doesn't have a plist file") unless params[:plist_path] params[:plist_path] = params[:plist_path].gsub("$(SRCROOT)", ".") end if params[:plist_path].nil? UI.user_error!("You must specify either a plist path or a scheme") end # Read existing plist file info_plist_path = File.join(folder, "..", params[:plist_path]) UI.user_error!("Couldn't find info plist file at path '#{info_plist_path}'") unless File.exist?(info_plist_path) UpdatePlistAction.run( plist_path: info_plist_path, block: proc do |plist| plist['CFBundleIdentifier'] = params[:app_identifier] if params[:app_identifier] plist['CFBundleDisplayName'] = params[:display_name] if params[:display_name] params[:block].call(plist) if params[:block] end ) else UI.important("You haven't specified any parameters to update your plist.") false end end ##################################################### # @!group Documentation ##################################################### def self.is_supported?(platform) [:ios].include?(platform) end def self.description 'Update a Info.plist file with bundle identifier and display name' end def self.details "This action allows you to modify your `Info.plist` file before building. This may be useful if you want a separate build for alpha, beta or nightly builds, but don't want a separate target." end def self.available_options [ FastlaneCore::ConfigItem.new(key: :xcodeproj, env_name: "FL_UPDATE_PLIST_PROJECT_PATH", description: "Path to your Xcode project", optional: true, verify_block: proc do |value| UI.user_error!("Please pass the path to the project, not the workspace") if value.end_with?(".xcworkspace") UI.user_error!("Could not find Xcode project") unless File.exist?(value) end), FastlaneCore::ConfigItem.new(key: :plist_path, env_name: "FL_UPDATE_PLIST_PATH", description: "Path to info plist", optional: true, verify_block: proc do |value| UI.user_error!("Invalid plist file") unless value[-6..-1].casecmp(".plist").zero? end), FastlaneCore::ConfigItem.new(key: :scheme, env_name: "FL_UPDATE_PLIST_APP_SCHEME", description: "Scheme of info plist", optional: true), FastlaneCore::ConfigItem.new(key: :app_identifier, env_name: 'FL_UPDATE_PLIST_APP_IDENTIFIER', description: 'The App Identifier of your app', code_gen_sensitive: true, default_value: ENV['PRODUCE_APP_IDENTIFIER'], default_value_dynamic: true, optional: true), FastlaneCore::ConfigItem.new(key: :display_name, env_name: 'FL_UPDATE_PLIST_DISPLAY_NAME', description: 'The Display Name of your app', optional: true), FastlaneCore::ConfigItem.new(key: :block, is_string: false, description: 'A block to process plist with custom logic', optional: true) ] end def self.author 'tobiasstrebitzer' end def self.example_code [ 'update_info_plist( # update app identifier string plist_path: "path/to/Info.plist", app_identifier: "com.example.newappidentifier" )', 'update_info_plist( # Change the Display Name of your app plist_path: "path/to/Info.plist", display_name: "MyApp-Beta" )', 'update_info_plist( # Target a specific `xcodeproj` rather than finding the first available one xcodeproj: "path/to/Example.proj", plist_path: "path/to/Info.plist", display_name: "MyApp-Beta" )', 'update_info_plist( # Advanced processing: find URL scheme for particular key and replace value xcodeproj: "path/to/Example.proj", plist_path: "path/to/Info.plist", block: proc do |plist| urlScheme = plist["CFBundleURLTypes"].find{|scheme| scheme["CFBundleURLName"] == "com.acme.default-url-handler"} urlScheme[:CFBundleURLSchemes] = ["acme-production"] end )' ] end def self.category :project end end end end