Class: Fastlane::Actions::IconsetAction

Inherits:
Action
  • Object
show all
Defined in:
lib/fastlane/plugin/rearchive/actions/iconset_action.rb

Class Method Summary collapse

Class Method Details

.authorsObject



117
118
119
# File 'lib/fastlane/plugin/rearchive/actions/iconset_action.rb', line 117

def self.authors
  ["naoigcat"]
end

.available_optionsObject



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/fastlane/plugin/rearchive/actions/iconset_action.rb', line 121

def self.available_options
  [
    FastlaneCore::ConfigItem.new(key: :archive_path,
                         description: "The path of the .ipa or .xcarchive to be modified",
                            optional: false,
                                type: String),

    FastlaneCore::ConfigItem.new(key: :iconset_path,
                         description: "The path to iconset to swap into the .ipa or .xcarchive",
                            optional: false,
                                type: String),

    FastlaneCore::ConfigItem.new(key: :verbose,
                         description: "Display the output of commands",
                            optional: true,
                       default_value: false,
                                type: Boolean)
  ]
end

.descriptionObject



113
114
115
# File 'lib/fastlane/plugin/rearchive/actions/iconset_action.rb', line 113

def self.description
  "Replace icons inside .ipa/.xcarchive"
end

.is_supported?(platform) ⇒ Boolean

Returns:

  • (Boolean)


141
142
143
# File 'lib/fastlane/plugin/rearchive/actions/iconset_action.rb', line 141

def self.is_supported?(platform)
  [:ios].include?(platform)
end

.run(params) ⇒ Object

rubocop:disable Metrics/PerceivedComplexity



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/fastlane/plugin/rearchive/actions/iconset_action.rb', line 9

def self.run(params) # rubocop:disable Metrics/PerceivedComplexity
  archive_path = File.expand_path(params[:archive_path])
  raise "Archive path #{archive_path} does not exist" unless File.exist?(archive_path)

  iconset_path = File.expand_path(params[:iconset_path])
  iconset_manifest_path = File.expand_path("#{iconset_path}/Contents.json")
  raise ".iconset manifest #{iconset_manifest_path} does not exist" unless File.exist?(iconset_manifest_path)

  if File.directory?(archive_path)
    archive = RearchiveHelper::XCArchive.new(archive_path)
  else
    archive = RearchiveHelper::IPAArchive.new(archive_path)
  end
  FastlaneCore::UI.message("Patching icons from: #{iconset_path}")
  plist_path = archive.extract(archive.app_path("Info.plist"))
  plist_buddy = RearchiveHelper::PlistBuddy.new(archive.local_path(plist_path))
  plist_buddy.parse_dict_keys(plist_buddy.exec("Print")).filter_map do |key|
    key.match(/^CFBundleIcons(~.+)?$/)
  end.map do |(key, idiom_suffix)|
    [":#{key}:CFBundlePrimaryIcon:CFBundleIconFiles", idiom_suffix]
  end.each do |(icon_files_key, idiom_suffix)|
    plist_buddy.parse_scalar_array(plist_buddy.exec("Print #{icon_files_key}")).map do |name|
      %W[#{name}#{idiom_suffix}* #{name}@*x#{idiom_suffix}*].each do |path|
        archive.delete(archive.app_path(path))
      end
    end
  rescue RuntimeError => e
    FastlaneCore::UI.message(e)
    next
  end.each do |(icon_files_key, _)|
    plist_buddy.exec("Delete #{icon_files_key}")
  end
  JSON.parse(File.read(iconset_manifest_path))["images"].select do |image|
    image["filename"]
  end.map do |entry|
    scale_suffix = entry["scale"] == "1x" ? "" : "@#{entry["scale"]}"
    idiom_suffix = entry["idiom"] == "iphone" ? "" : "~#{entry["idiom"]}"
    file_extension = File.extname(entry["filename"])
    {
      source: "#{iconset_path}/#{entry["filename"]}",
      name: "#{File.basename(iconset_path, ".appiconset")}#{entry["size"]}",
      idiom: entry["idiom"],
      target: "#{File.basename(iconset_path, ".appiconset")}#{entry["size"]}#{scale_suffix}#{idiom_suffix}#{file_extension}"
    }
  end.group_by do |icon|
    icon[:idiom]
  end.each do |idiom, icons|
    idiom_suffix = idiom == "iphone" ? "" : "~#{idiom}"
    icons_plist_key = ":CFBundleIcons#{idiom_suffix}:CFBundlePrimaryIcon:CFBundleIconFiles"
    plist_buddy.exec("Add #{icons_plist_key} array")
    icons.each do |icon|
      relative_path = archive.app_path((icon[:target]).to_s)
      local_path = archive.local_path(relative_path)
      FastlaneCore::UI.message("Copy icon from #{icon[:source].shellescape} to #{local_path.shellescape}")
      system("cp #{icon[:source].shellescape} #{local_path.shellescape}", exception: true)
      archive.replace(relative_path)
    end.map do |icon|
      icon[:name]
    end.uniq.each do |key|
      plist_buddy.exec("Add #{icons_plist_key}: string #{key}")
    end
  end
  Dir.mktmpdir do |dir|
    Dir.chdir(dir) do
      FastlaneCore::UI.message("Current Directory: #{dir}")
      FastlaneCore::UI.message("Iconset: #{iconset_path}")
      IO.popen(%W[
        /usr/bin/actool
        --output-format human-readable-text
        --notices
        --warnings
        --output-partial-info-plist assetcatalog_generated_info.plist
        --app-icon #{File.basename(iconset_path, ".appiconset")}
        --compress-pngs
        --enable-on-demand-resources YES
        --sticker-pack-identifier-prefix #{plist_buddy.exec("Print CFBundleIdentifier")}.sticker-pack.
        --target-device iphone
        --target-device ipad
        --minimum-deployment-target #{plist_buddy.exec("Print MinimumOSVersion")}
        --platform iphoneos
        --product-type com.apple.product-type.application
        --compile
        .
        #{File.dirname(iconset_path)}
      ].map(&:shellescape).join(" "), "r") do |io|
        FastlaneCore::UI.verbose(io.read) if params[:verbose]
      end
      generated_plist_buddy = RearchiveHelper::PlistBuddy.new("assetcatalog_generated_info.plist")
      plist_buddy.parse_dict_keys(generated_plist_buddy.exec("Print")).filter_map do |key|
        key.match(/^CFBundleIcons(~.+)?$/)
      end.each do |key|
        plist_buddy.exec("Delete #{key}")
      end
      plist_buddy.exec("Merge assetcatalog_generated_info.plist")
      archive.replace(plist_path)
      relative_path = archive.app_path("Assets.car")
      local_path = archive.local_path(relative_path)
      system("mkdir -p #{File.dirname(local_path).shellescape}", exception: true)
      system("mv Assets.car #{local_path.shellescape}", exception: true)
      archive.replace(relative_path)
    end
  end
end