Repository: KrauseFx/fastlane-plugin-appicon Branch: master Commit: 452dc1539c67 Files: 18 Total size: 30.5 KB Directory structure: gitextract_fqhyqhsc/ ├── .gitignore ├── .rspec ├── .rubocop.yml ├── .travis.yml ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── fastlane/ │ ├── Fastfile │ └── Pluginfile ├── fastlane-plugin-appicon.gemspec ├── lib/ │ └── fastlane/ │ └── plugin/ │ ├── appicon/ │ │ ├── actions/ │ │ │ ├── android_appicon_action.rb │ │ │ └── appicon_action.rb │ │ ├── helper/ │ │ │ └── appicon_helper.rb │ │ └── version.rb │ └── appicon.rb └── spec/ ├── appicon_action_spec.rb └── spec_helper.rb ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.gem /gems/ Gemfile.lock ## Documentation cache and generated files: /.yardoc/ /_yardoc/ /doc/ /rdoc/ fastlane/README.md fastlane/report.xml .DS_Store ## Ignore generated asset catalogue Assets.xcassets/ ## Ignore android generated icon app/ ================================================ FILE: .rspec ================================================ --require spec_helper --color --format d ================================================ FILE: .rubocop.yml ================================================ # kind_of? is a good way to check a type Style/ClassCheck: EnforcedStyle: kind_of? # specs sometimes have useless assignments, which is fine Lint/UselessAssignment: Exclude: - '**/spec/**/*' # We could potentially enable the 2 below: Layout/FirstHashElementIndentation: Enabled: false Layout/HashAlignment: Enabled: false # HoundCI doesn't like this rule Layout/DotPosition: Enabled: false # We allow !! as it's an easy way to convert ot boolean Style/DoubleNegation: Enabled: false # Sometimes we allow a rescue block that doesn't contain code Lint/SuppressedException: Enabled: false # Cop supports --auto-correct. Lint/UnusedBlockArgument: Enabled: false # Needed for $verbose Style/GlobalVars: Enabled: false # We want to allow class Fastlane::Class Style/ClassAndModuleChildren: Enabled: false # $? Exit Style/SpecialGlobalVars: Enabled: false Metrics/AbcSize: Max: 60 Exclude: - '**/lib/*/options.rb' # The %w might be confusing for new users Style/WordArray: MinSize: 19 # raise and fail are both okay Style/SignalException: Enabled: false # Better too much 'return' than one missing Style/RedundantReturn: Enabled: false # Having if in the same line might not always be good Style/IfUnlessModifier: Enabled: false # and and or is okay Style/AndOr: Enabled: false # Configuration parameters: CountComments. Metrics/ClassLength: Max: 320 Metrics/CyclomaticComplexity: Max: 17 # Configuration parameters: AllowURI, URISchemes. Layout/LineLength: Max: 370 # Configuration parameters: CountKeywordArgs. Metrics/ParameterLists: Max: 17 Metrics/PerceivedComplexity: Max: 18 # Sometimes it's easier to read without guards Style/GuardClause: Enabled: false # We allow both " and ' Style/StringLiterals: Enabled: false # something = if something_else # that's confusing Style/ConditionalAssignment: Enabled: false # Better to have too much self than missing a self Style/RedundantSelf: Enabled: false # e.g. # def self.is_supported?(platform) # we may never use `platform` Lint/UnusedMethodArgument: Enabled: false # the let(:key) { ... } Lint/ParenthesesAsGroupedExpression: Exclude: - '**/spec/**/*' # This would reject is_ in front of methods # We use `is_supported?` everywhere already Naming/PredicateName: Enabled: false # We allow the $ Style/PerlBackrefs: Enabled: false # Disable '+ should be surrounded with a single space' for xcodebuild_spec.rb Layout/SpaceAroundOperators: Exclude: - '**/spec/actions_specs/xcodebuild_spec.rb' Metrics/MethodLength: Exclude: - '**/lib/fastlane/actions/*.rb' - '**/bin/fastlane' - '**/lib/*/options.rb' Max: 60 AllCops: Include: - '**/fastlane/Fastfile' Exclude: - '**/lib/assets/custom_action_template.rb' - './vendor/**/*' # We're not there yet Style/Documentation: Enabled: false # Added after upgrade to 0.38.0 Style/MutableConstant: Enabled: false # length > 0 is good Style/ZeroLengthPredicate: Enabled: false # Adds complexity Style/IfInsideElse: Enabled: false ================================================ FILE: .travis.yml ================================================ # os: osx # enable this if you need OS X support language: ruby rvm: - 2.2.4 ================================================ FILE: Gemfile ================================================ source 'https://rubygems.org' gemspec plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') eval(File.read(plugins_path), binding) if File.exist?(plugins_path) gem 'activesupport', '~> 4.0' ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016 Boris Bügling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # appicon plugin [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-appicon) ![Demo image](demo.png) ## Getting Started This project is a [fastlane](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-appicon`, add it to your project by running: ```bash fastlane add_plugin appicon ``` Please note that this plugin uses [minimagick](https://github.com/minimagick/minimagick), which requires either GraphicsMagick or ImageMagick library. If you have neither, you can install either via Homebrew: ``` brew install graphicsmagick ``` or ``` brew install imagemagick ``` The default CLI for the `mini_magick` gem is set to auto pick. It will first try to use `GraphicsMagick` (if you have it installed) otherwise it will use `ImageMagick`. If you want to be explicit about which CLI you use, set the `minimagick_cli` option to `graphicsmagick` or `imagemagick`. Not specifying this option will set `MiniMagick` to use auto which will choose what's available. ## About appicon Generate required icon sizes and iconset from a master application icon. Since many apps use a single 1024x1024 icon to produce all the required sizes from, why not automate the process and save lots of time? ## Example Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`. Just specify the source image using the `appicon_image_file`. Optionally specify the devices using `appicon_devices` and the destination path using `appicon_path`. We recommend storing the full-size picture at `fastlane/metadata/app_icon.png` so it can be picked up by _deliver_, as well as this plugin. If you want to use this plugin to generate a app icon for Messages(sticker) extension, set `messages_extension` to `true` and add `messages` to the `appicon_devices`. ```ruby lane :basic do appicon( appicon_devices: [:ipad, :iphone, :ios_marketing], appicon_path: "MajorKey/Assets.xcassets" ) end lane :test1 do appicon(appicon_image_file: 'spec/fixtures/Themoji.png', appicon_devices: [:ipad, :iphone, :ios_marketing]) end lane :test2 do appicon(appicon_image_file: 'spec/fixtures/Themoji.png', appicon_devices: [:ipad, :iphone, :ios_marketing, :watch, :watch_marketing]) end lane :test3 do # `appicon_image_file` defaults to "fastlane/metadata/app_icon.png" appicon( appicon_devices: [:iphone], appicon_path: 'wwdcfamily/Images.xcassets' # output path ) end lane :test4 do appicon(appicon_image_file: 'spec/fixtures/Themoji.png', appicon_devices: [:macos]) end lane :splash_screen do appicon( appicon_image_file: 'spec/fixtures/splash_screen.png', appicon_devices: [:universal], appicon_path: "ios/App/App/Assets.xcassets", appicon_name: 'Splash.imageset' ) end lane :messages_extension do appicon( appicon_image_file: "fastlane/metadata/iMessageAppIcon.png", appicon_devices: [:iphone, :ipad, :ios_marketing, :messages], appicon_path: 'iMessageStickers/Stickers.xcassets', messages_extension: true ) end # or lane :android do android_appicon( appicon_image_file: 'spec/fixtures/Themoji.png', appicon_icon_types: [:launcher], appicon_path: 'app/res/mipmap' ) android_appicon( appicon_image_file: 'spec/fixtures/ThemojiNotification.png', appicon_icon_types: [:notification], appicon_path: 'app/res/drawable', appicon_filename: 'ic_notification', generate_rounded: true ) android_appicon( appicon_image_file: 'spec/fixtures/splash_base_image.png', appicon_icon_types: [:splash_port, :splash_land], appicon_path: 'app/res/drawable', appicon_filename: 'splash' ) end ``` ## Run tests for this plugin To run both the tests, and code style validation, run ``` rake ``` To automatically fix many of the styling issues, use ``` rubocop -a ``` ## Issues and Feedback For any other issues and feedback about this plugin, please submit it to this repository. ## Troubleshooting If you have trouble using plugins, check out the [Plugins Troubleshooting](https://github.com/fastlane/fastlane/blob/master/fastlane/docs/PluginsTroubleshooting.md) doc in the main `fastlane` repo. ## Using `fastlane` Plugins For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/). ## About `fastlane` `fastlane` is the easiest way to automate building and releasing your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools). ================================================ FILE: Rakefile ================================================ require 'bundler/gem_tasks' require 'rspec/core/rake_task' RSpec::Core::RakeTask.new require 'rubocop/rake_task' RuboCop::RakeTask.new(:rubocop) task default: [:spec, :rubocop] ================================================ FILE: fastlane/Fastfile ================================================ # frozen_string_literal: true lane :ios do appicon( appicon_image_file: 'spec/fixtures/Themoji.png', appicon_devices: %i[ipad iphone ios_marketing watch watch_marketing], appicon_path: 'app' ) end lane :ios_splash do appicon( appicon_image_file: 'spec/fixtures/ThemojiSplash.png', appicon_devices: [:universal], appicon_path: 'app', appicon_name: 'Splash.imageset' ) end lane :ios_messages_extension do appicon( appicon_image_file: 'spec/fixtures/ThemojiSplash.png', appicon_devices: %i[iphone ipad ios_marketing messages], appicon_path: 'app/iMessageStickers/Stickers.xcassets', messages_extension: true ) end lane :macos do appicon( appicon_image_file: 'spec/fixtures/ThemojiSplash.png', appicon_devices: [:macos], appicon_path: 'app', appicon_name: 'Mac.appiconset' ) end lane :android do android_appicon( appicon_image_file: 'spec/fixtures/Themoji.png', appicon_path: 'app/res/mipmap', generate_rounded: true ) end lane :android_splash do android_appicon( appicon_image_file: 'spec/fixtures/ThemojiSplash.png', appicon_icon_types: %i[splash_port splash_land], appicon_path: 'app/res/drawable', appicon_filename: 'splash' ) end ================================================ FILE: fastlane/Pluginfile ================================================ # Autogenerated by fastlane ================================================ FILE: fastlane-plugin-appicon.gemspec ================================================ # coding: utf-8 lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'fastlane/plugin/appicon/version' Gem::Specification.new do |spec| spec.name = 'fastlane-plugin-appicon' spec.version = Fastlane::Appicon::VERSION spec.author = ["Boris Bügling", "Felix Krause"] spec.email = %q{boris@icculus.org} spec.summary = %q{Generate required icon sizes and iconset from a master application icon.} spec.homepage = "https://github.com/fastlane-community/fastlane-plugin-appicon" spec.license = "MIT" spec.files = Dir["lib/**/*"] + %w(README.md LICENSE) spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] spec.add_dependency 'mini_magick', '>= 4.9.4', '< 5.0.0' spec.add_dependency 'json' spec.add_development_dependency 'pry' spec.add_development_dependency 'bundler' spec.add_development_dependency 'rspec' spec.add_development_dependency 'rake' spec.add_development_dependency 'rubocop' spec.add_development_dependency 'fastlane', '>= 1.95.0' end ================================================ FILE: lib/fastlane/plugin/appicon/actions/android_appicon_action.rb ================================================ require 'mini_magick' module Fastlane module Actions class AndroidAppiconAction < Action def self.needed_icons { launcher: { :ldpi => ['36x36'], :mdpi => ['48x48'], :hdpi => ['72x72'], :xhdpi => ['96x96'], :xxhdpi => ['144x144'], :xxxhdpi => ['192x192'] }, notification: { :ldpi => ['18x18'], :mdpi => ['24x24'], :hdpi => ['36x36'], :xhdpi => ['48x48'], :xxhdpi => ['72x72'], :xxxhdpi => ['96x96'], }, splash_land: { 'land-ldpi' => ['320x200'], 'land-mdpi' => ['480x320'], 'land-hdpi' => ['800x480'], 'land-xhdpi' => ['1280x720'], 'land-xxhdpi' => ['1600x960'], 'land-xxxhdpi' => ['1920x1280'] }, splash_port: { 'port-ldpi' => ['200x320'], 'port-mdpi' => ['320x480'], 'port-hdpi' => ['480x800'], 'port-xhdpi' => ['720x1280'], 'port-xxhdpi' => ['960x1600'], 'port-xxxhdpi' => ['1280x1920'] } } end def self.run(params) Helper::AppiconHelper.set_cli(params[:minimagick_cli]) fname = params[:appicon_image_file] custom_sizes = params[:appicon_custom_sizes] icons = Helper::AppiconHelper.get_needed_icons(params[:appicon_icon_types], self.needed_icons, true, custom_sizes) icons.each do |icon| image = MiniMagick::Image.open(fname) Helper::AppiconHelper.check_input_image_size(image, 1024, 1024) # Custom icons will have basepath and filename already defined if icon.has_key?('basepath') && icon.has_key?('filename') basepath = Pathname.new(icon['basepath']) filename = icon['filename'] else basepath = Pathname.new("#{params[:appicon_path]}-#{icon['scale']}") filename = "#{params[:appicon_filename]}.png" end width_height = [icon['width'], icon['height']].map(&:to_i) width, height = width_height max = width_height.max image.format 'png' image.resize "#{max}x#{max}" unless width == height offset = if width > height "+0+#{(width - height) / 2}" elsif height > width "+#{(height - width) / 2}+0" end image.crop "#{icon['size']}#{offset}" end FileUtils.mkdir_p(basepath) image.write basepath + filename if basepath.to_s.match("port-") default_portrait_path = basepath.to_s.gsub("port-","") FileUtils.mkdir_p(default_portrait_path) image.write default_portrait_path + '/' + filename end if params[:generate_rounded] rounded_image = MiniMagick::Image.open(fname) rounded_image.format 'png' rounded_image.resize "#{width}x#{height}" rounded_image = round(rounded_image) rounded_image.write basepath + filename.gsub('.png', '_round.png') end end UI.success("Successfully stored launcher icons at '#{params[:appicon_path]}'") end def self.round(img) require 'mini_magick' img.format 'png' width = img[:width]-2 radius = width/2 mask = ::MiniMagick::Image.open img.path mask.format 'png' mask.combine_options do |m| m.alpha 'transparent' m.background 'none' m.fill 'white' m.draw 'roundrectangle 1,1,%s,%s,%s,%s' % [width, width, radius, radius] end masked = img.composite(mask, 'png') do |i| i.alpha "set" i.compose 'DstIn' end return masked end def self.get_custom_sizes(image, custom_sizes) end def self.description "Generate required icon sizes from a master application icon" end def self.authors ["@adrum"] end def self.available_options [ FastlaneCore::ConfigItem.new(key: :appicon_image_file, env_name: "APPICON_IMAGE_FILE", description: "Path to a square image file, at least 512x512", optional: false, type: String), FastlaneCore::ConfigItem.new(key: :appicon_icon_types, env_name: "APPICON_ICON_TYPES", default_value: [:launcher], description: "Array of device types to generate icons for", optional: true, type: Array), FastlaneCore::ConfigItem.new(key: :appicon_path, env_name: "APPICON_PATH", default_value: 'app/res/mipmap', description: "Path to res subfolder", optional: true, type: String), FastlaneCore::ConfigItem.new(key: :appicon_filename, env_name: "APPICON_FILENAME", default_value: 'ic_launcher', description: "The output filename of each image", optional: true, type: String), FastlaneCore::ConfigItem.new(key: :appicon_custom_sizes, description: "Hash of custom sizes - {'path/icon.png' => '256x256'}", default_value: {}, optional: true, type: Hash), FastlaneCore::ConfigItem.new(key: :generate_rounded, description: "Generate round icons?", default_value: false, type: Boolean), FastlaneCore::ConfigItem.new(key: :minimagick_cli, env_name: "APPICON_MINIMAGICK_CLI", description: "Set MiniMagick CLI (auto picked by default). Values are: graphicsmagick, imagemagick", optional: true, type: String, verify_block: proc do |value| av = %w(graphicsmagick imagemagick) UI.user_error!("Unsupported minimagick cli '#{value}', must be: #{av}") unless av.include?(value) end) ] end def self.is_supported?(platform) [:android].include?(platform) end end end end ================================================ FILE: lib/fastlane/plugin/appicon/actions/appicon_action.rb ================================================ require 'json' require 'mini_magick' module Fastlane module Actions class AppiconAction < Action def self.needed_icons { universal: { '1x' => ['2732x2732'], '2x' => ['2732x2732'], '3x' => ['2732x2732'] }, iphone: { '2x' => ['20x20', '29x29', '40x40', '60x60'], '3x' => ['20x20', '29x29', '40x40', '60x60'] }, ipad: { '1x' => ['20x20', '29x29', '40x40', '76x76'], '2x' => ['20x20', '29x29', '40x40', '76x76', '83.5x83.5'] }, :ios_marketing => { '1x' => ['1024x1024'] }, :watch => { '2x' => [ ['24x24', 'notificationCenter', '38mm'], ['27.5x27.5', 'notificationCenter', '42mm'], ['29x29', 'companionSettings'], ['40x40', 'appLauncher', '38mm'], ['44x44', 'appLauncher', '40mm'], ['50x50', 'appLauncher', '44mm'], ['86x86', 'quickLook', '38mm'], ['98x98', 'quickLook', '42mm'], ['108x108', 'quickLook', '44mm'] ], '3x' => [['29x29', 'companionSettings']] }, :watch_marketing => { '1x' => ['1024x1024'] }, :macos => { '1x' => ['16x16', '32x32', '128x128', '256x256', '512x512'], '2x' => ['16x16', '32x32', '128x128', '256x256', '512x512'], } } end def self.needed_icons_messages_extension { iphone: { '2x' => ['60x45'], '3x' => ['60x45'] }, ipad: { '2x' => ['67x50', '74x55'] }, messages: { '2x' => ['27x20', '32x24'], '3x' => ['27x20', '32x24'] }, ios_marketing: { '1x' => ['1024x768'] } } end def self.run(params) fname = params[:appicon_image_file] basename = File.basename(fname, File.extname(fname)) Helper::AppiconHelper.set_cli(params[:minimagick_cli]) is_messages_extension = params[:messages_extension] basepath = Pathname.new(File.join(params[:appicon_path], is_messages_extension ? params[:appicon_messages_name] : params[:appicon_name])) image = MiniMagick::Image.open(fname) if is_messages_extension Helper::AppiconHelper.check_input_image_size(image, 1024, 768) else Helper::AppiconHelper.check_input_image_size(image, 1024, 1024) end # Convert image to png image.format 'png' # remove alpha channel if params[:remove_alpha] image.alpha 'remove' end # Recreate the base path FileUtils.rm_rf(basepath) FileUtils.mkdir_p(basepath) images = [] icons = Helper::AppiconHelper.get_needed_icons(params[:appicon_devices], is_messages_extension ? self.needed_icons_messages_extension : self.needed_icons, false) icons.each do |icon| width = icon['width'] height = icon['height'] filename = basename unless icon['device'] == 'universal' filename += "-#{width.to_i}x#{height.to_i}" end filename += ".png" # downsize icon # "!" resizes to exact size (needed for messages extension) image.resize "#{width}x#{height}!" # Don't write change/created times into the PNG properties # so unchanged files don't have different hashes. image.define("png:exclude-chunks=date,time") image.write basepath + filename info = { 'idiom' => icon['device'], 'filename' => filename, 'scale' => icon['scale'] } # if device is messages, we need to set it to universal if icon['device'] == 'messages' info['idiom'] = 'universal' info['platform'] = 'ios' end # if device is ios_marketing but we are generating messages extension app, set the idiom correctly if icon['device'] == 'ios_marketing' && is_messages_extension info['platform'] = 'ios' end unless icon['device'] == 'universal' info['size'] = icon['size'] end info['role'] = icon['role'] unless icon['role'].nil? info['subtype'] = icon['subtype'] unless icon['subtype'].nil? images << info end contents = { 'images' => images, 'info' => { 'version' => 1, 'author' => 'fastlane' } } File.write(File.join(basepath, 'Contents.json'), JSON.pretty_generate(contents)) UI.success("Successfully stored app icon at '#{basepath}'") end def self.description "Generate required icon sizes and iconset from a master application icon" end def self.authors ["@NeoNacho"] end def self.available_options [ FastlaneCore::ConfigItem.new(key: :appicon_image_file, env_name: "APPICON_IMAGE_FILE", description: "Path to a square image file, at least 1024x1024", optional: false, type: String, default_value: Dir["fastlane/metadata/app_icon.png"].last), # that's the default when using fastlane to manage app metadata FastlaneCore::ConfigItem.new(key: :appicon_devices, env_name: "APPICON_DEVICES", default_value: [:iphone], description: "Array of device idioms to generate icons for", optional: true, type: Array), FastlaneCore::ConfigItem.new(key: :appicon_path, env_name: "APPICON_PATH", default_value: 'Assets.xcassets', description: "Path to the Asset catalogue for the generated iconset", optional: true, type: String), FastlaneCore::ConfigItem.new(key: :appicon_name, env_name: "APPICON_NAME", default_value: 'AppIcon.appiconset', description: "Name of the appiconset inside the asset catalogue", optional: true, type: String), FastlaneCore::ConfigItem.new(key: :appicon_messages_name, env_name: "APPICON_MESSAGES_NAME", default_value: 'AppIcon.stickersiconset', description: "Name of the appiconset inside the asset catalogue", optional: true, type: String), FastlaneCore::ConfigItem.new(key: :remove_alpha, env_name: "REMOVE_ALPHA", default_value: false, description: "Remove the alpha channel from generated PNG", optional: true, type: Boolean), FastlaneCore::ConfigItem.new(key: :messages_extension, env_name: "APPICON_MESSAGES_EXTENSION", default_value: false, description: "App icon is generated for Messages extension", optional: true, type: Boolean), FastlaneCore::ConfigItem.new(key: :minimagick_cli, env_name: "APPICON_MINIMAGICK_CLI", description: "Set MiniMagick CLI (auto picked by default). Values are: graphicsmagick, imagemagick", optional: true, type: String, verify_block: proc do |value| av = %w(graphicsmagick imagemagick) UI.user_error!("Unsupported minimagick cli '#{value}', must be: #{av}") unless av.include?(value) end) ] end def self.is_supported?(platform) [:ios, :mac, :macos, :caros, :rocketos].include?(platform) end end end end ================================================ FILE: lib/fastlane/plugin/appicon/helper/appicon_helper.rb ================================================ require 'mini_magick' module Fastlane module Helper class AppiconHelper def self.check_input_image_size(image, width, height) UI.user_error!("Minimum width of input image should be #{width}") if image.width < width UI.user_error!("Minimum height of input image should be #{height}") if image.height < height UI.user_error!("Input image should be square") if image.width / image.height != width / height end def self.set_cli(minimagick_cli) MiniMagick.configure do |config| case minimagick_cli when "graphicsmagick" config.cli = :graphicsmagick when "imagemagick" config.cli = :imagemagick else config.cli = MiniMagick.cli() end config.timeout = 5 end end def self.get_needed_icons(devices, needed_icons, is_android = false, custom_sizes = {}) icons = [] devices.each do |device| needed_icons[device].each do |scale, sizes| sizes.each do |size| if size.kind_of?(Array) size, role, subtype = size end if is_android width, height = size.split('x').map { |v| v.to_f } else multiple = device.match(/universal/) ? 1 : scale.to_i width, height = size.split('x').map { |v| v.to_f * multiple } end icons << { 'width' => width, 'height' => height, 'size' => size, 'device' => device.to_s.gsub('_', '-'), 'scale' => scale, 'role' => role, 'subtype' => subtype } end end end # Add custom icon sizes (probably for notifications) custom_sizes.each do |path, size| path = path.to_s width, height = size.split('x').map { |v| v.to_f } icons << { 'width' => width, 'height' => height, 'size' => size, 'basepath' => File.dirname(path), 'filename' => File.basename(path) } end # Sort from the largest to the smallest needed icon icons = icons.sort_by {|value| value['width']} .reverse end end end end ================================================ FILE: lib/fastlane/plugin/appicon/version.rb ================================================ module Fastlane module Appicon VERSION = "0.16.0" end end ================================================ FILE: lib/fastlane/plugin/appicon.rb ================================================ require 'fastlane/plugin/appicon/version' module Fastlane module Appicon # Return all .rb files inside the "actions" directory def self.all_classes Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))] end end end # By default we want to import all available actions # A plugin can contain any number of actions and plugins Fastlane::Appicon.all_classes.each do |current| require current end ================================================ FILE: spec/appicon_action_spec.rb ================================================ describe Fastlane::Actions::AppiconAction do end ================================================ FILE: spec/spec_helper.rb ================================================ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) # This module is only used to check the environment is currently a testing env module SpecHelper end require 'fastlane' # to import the Action super class require 'fastlane/plugin/appicon' # import the actual plugin Fastlane.load_actions # load other actions (in case your plugin calls other actions or shared values)