app-info 2.6.5 → 2.7.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79a5669bb25288b95dda6a7f02181e6375fe192234a88eb17957358590e12870
4
- data.tar.gz: 73bbe25cc149955b7140105108090a5a4db0019ca1e5408358a6439f8c606599
3
+ metadata.gz: b37b084ef666db1fad604e2aa19698faad80d68d7d79a031c55d60e3f8b97f48
4
+ data.tar.gz: 2a8da24c6adc6b9f003d8a8016569f2f20772f1c7524ea411a6b4946f32fd0a7
5
5
  SHA512:
6
- metadata.gz: f3ae7c2886106af7ffdbb69ab031fb7ec81b196a12ba05544e467398850d7299e2152ad24d3523b0a4d1ebd0f005dba0fcbd37f826b67aa848eece592359a01b
7
- data.tar.gz: 33f09022fbaec5f95997bec8fee7a73dd4f9fe7dd85837b9541337e44330ee6fee8db5cbee975e1248433ccd2fa7f0857c82d6f67700cd498959284c0002f921
6
+ metadata.gz: 9041485898807902ce753c4114b82037cf900c45fc4ce183fb2af0ec57c0fd05ebe96314a89016e3f423531daa528d48d6ea566445296be045d18dc6ab4da4cb
7
+ data.tar.gz: fd22abedeea11ba62dd7f4575f19a08348d146cc6ffd3a6d69b54652a869b9dc095467d9922031a84d79336fbbc4e3dc485a428e8a96d66fc4bedc378d1e962f
data/.rubocop.yml CHANGED
@@ -20,10 +20,12 @@ AllCops:
20
20
  Exclude:
21
21
  - 'bin/*'
22
22
  - 'spec/**/*'
23
- - vendor/bundle/**/*
23
+ - 'vendor/bundle/**/*'
24
24
  - 'Rakefile'
25
25
  - 'app_info.gemspec'
26
26
  - 'lib/app-info.rb'
27
+ - 'lib/app_info/protobuf/models/*_pb.rb'
28
+ - 'main.rb'
27
29
 
28
30
  Metrics/AbcSize:
29
31
  Max: 100
@@ -56,4 +58,19 @@ Lint/AssignmentInCondition:
56
58
  Enabled: false
57
59
 
58
60
  Style/Documentation:
59
- Enabled: false
61
+ Enabled: false
62
+
63
+ Style/PerlBackrefs:
64
+ Exclude:
65
+ - 'lib/app_info/core_ext/string/inflector.rb'
66
+
67
+ Style/DocumentDynamicEvalDefinition:
68
+ Enabled: false
69
+
70
+ Metrics/BlockNesting:
71
+ Exclude:
72
+ - 'lib/app_info/dsym.rb'
73
+
74
+
75
+ Style/SlicingWithRange:
76
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
9
9
 
10
10
  > List all changes before release a new version.
11
11
 
12
+ ## [2.7.0.beta1] (2021-09-27)
13
+
14
+ ### Added
15
+
16
+ - Android App Bundle a.k.a `aab` file parts support [#36](https://github.com/icyleaf/app_info/pull/36)
17
+
12
18
  ## [2.6.5] (2021-09-17)
13
19
 
14
20
  ### Added
@@ -185,7 +191,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
185
191
 
186
192
  - Updated dependency of CFPropertly list be a range between 2.3.4. (thanks @[cschroed](https://github.com/cschroed))
187
193
 
188
- [Unreleased]: https://github.com/icyleaf/app-info/compare/v2.6.5..HEAD
194
+ [Unreleased]: https://github.com/icyleaf/app-info/compare/v2.7.0.beta1..HEAD
195
+ [2.7.0.beta1]: https://github.com/icyleaf/app-info/compare/v2.6.5...v2.7.0.beta1
189
196
  [2.6.5]: https://github.com/icyleaf/app-info/compare/v2.6.4...v2.6.5
190
197
  [2.6.4]: https://github.com/icyleaf/app-info/compare/v2.6.3...v2.6.4
191
198
  [2.6.3]: https://github.com/icyleaf/app-info/compare/v2.6.1...v2.6.3
data/README.md CHANGED
@@ -9,12 +9,14 @@ Teardown tool for mobile(ipa/apk) app, macOS app and dSYM.zip file, analysis met
9
9
 
10
10
  ## Support
11
11
 
12
- - Android apk file
12
+ - Android file
13
+ - `.apk`
14
+ - `.aab` (Androld App Bundle)
13
15
  - iOS ipa file
14
- - Info.plist file
15
- - .mobileprovision/.provisionprofile file
16
- - macOS App(.zip) file
17
- - dSYM(.zip) file
16
+ - `Info.plist` file
17
+ - `.mobileprovision`/`.provisionprofile` file
18
+ - Zipped macOS App file
19
+ - Zipped dSYMs file
18
20
 
19
21
  ## Installation
20
22
 
@@ -54,6 +56,7 @@ parser = AppInfo.parse('App.dSYm.zip')
54
56
  # If detect file type failed, you can parse in other way
55
57
  parser = AppInfo::IPA.new('iphone.ipa')
56
58
  parser = AppInfo::APK.new('android.apk')
59
+ parser = AppInfo::AAB.new('android.aab')
57
60
  parser = AppInfo::InfoPlist.new('Info.plist')
58
61
  parser = AppInfo::MobileProvision.new('uuid.mobileprovision')
59
62
  parser = AppInfo::Macos.new('App.dSYm.zip')
data/app_info.gemspec CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency 'rubyzip', '>= 1.2', '< 3.0'
28
28
  spec.add_dependency 'uuidtools', '>= 2.1.5', '< 2.3.0'
29
29
  spec.add_dependency 'icns', '~> 0.2.0'
30
+ spec.add_dependency 'google-protobuf', '~> 3.18.0'
30
31
 
31
32
  spec.add_development_dependency 'bundler', '>= 1.12'
32
33
  spec.add_development_dependency 'rake', '>= 10.0'
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'app_info/protobuf/manifest'
4
+ require 'image_size'
5
+ require 'forwardable'
6
+
7
+ module AppInfo
8
+ # Parse APK file
9
+ class AAB
10
+ include Helper::HumanFileSize
11
+ extend Forwardable
12
+
13
+ attr_reader :file
14
+
15
+ # APK Devices
16
+ module Device
17
+ PHONE = 'Phone'
18
+ TABLET = 'Tablet'
19
+ WATCH = 'Watch'
20
+ TV = 'Television'
21
+ end
22
+
23
+ BASE_PATH = 'base'
24
+ BASE_MANIFEST = "#{BASE_PATH}/manifest/AndroidManifest.xml"
25
+ BASE_RESOURCES = "#{BASE_PATH}/resources.pb"
26
+
27
+ def initialize(file)
28
+ @file = file
29
+ end
30
+
31
+ def size(human_size: false)
32
+ file_to_human_size(@file, human_size: human_size)
33
+ end
34
+
35
+ def os
36
+ Platform::ANDROID
37
+ end
38
+ alias file_type os
39
+
40
+ def_delegators :manifest, :version_name
41
+
42
+ alias release_version version_name
43
+
44
+ def package_name
45
+ manifest.package
46
+ end
47
+ alias identifier package_name
48
+ alias bundle_id package_name
49
+
50
+ def version_code
51
+ manifest.version_code.to_s
52
+ end
53
+ alias build_version version_code
54
+
55
+ def name
56
+ manifest.label
57
+ end
58
+
59
+ def device_type
60
+ if wear?
61
+ Device::WATCH
62
+ elsif tv?
63
+ Device::TV
64
+ else
65
+ Device::PHONE
66
+ end
67
+ end
68
+
69
+ # TODO: find a way to detect
70
+ # Found answer but not works: https://stackoverflow.com/questions/9279111/determine-if-the-device-is-a-smartphone-or-tablet
71
+ # def tablet?
72
+ # resource.first_package
73
+ # .entries('bool')
74
+ # .select{|e| e.name == 'isTablet' }
75
+ # .size >= 1
76
+ # end
77
+
78
+ def wear?
79
+ use_features.include?('android.hardware.type.watch')
80
+ end
81
+
82
+ def tv?
83
+ use_features.include?('android.software.leanback')
84
+ end
85
+
86
+ def min_sdk_version
87
+ manifest.uses_sdk.min_sdk_version
88
+ end
89
+ alias min_os_version min_sdk_version
90
+
91
+ def target_sdk_version
92
+ manifest.uses_sdk.target_sdk_version
93
+ end
94
+
95
+ def use_features
96
+ @use_features ||= manifest&.uses_feature&.map(&:name)
97
+ end
98
+
99
+ def use_permissions
100
+ @use_permissions ||= manifest&.uses_permission&.map(&:name)
101
+ end
102
+
103
+ def activities
104
+ @activities ||= manifest.activities.map(&:name)
105
+ end
106
+
107
+ def services
108
+ @services ||= manifest.services.map(&:name)
109
+ end
110
+
111
+ def components
112
+ @components ||= manifest.components.transform_values do |child|
113
+ child.map(&:name)
114
+ end
115
+ end
116
+
117
+ def signs
118
+ return @signs if @signs
119
+
120
+ @signs = []
121
+ each_file do |path, data|
122
+ # find META-INF/xxx.{RSA|DSA}
123
+ next unless path =~ %r{^META-INF/} && data.unpack('CC') == [0x30, 0x82]
124
+
125
+ @signs << APK::Sign.new(path, OpenSSL::PKCS7.new(data))
126
+ end
127
+
128
+ @signs
129
+ end
130
+
131
+ def certificates
132
+ @certificates ||= signs.each_with_object([]) do |sign, obj|
133
+ obj << APK::Certificate.new(sign.path, sign.sign.certificates[0])
134
+ end
135
+ end
136
+
137
+ def each_file
138
+ zip.each do |entry|
139
+ next unless entry.file?
140
+
141
+ yield entry.name, @zip.read(entry)
142
+ end
143
+ end
144
+
145
+ def read_file(name, base_path: BASE_PATH)
146
+ content = @zip.read(entry(name, base_path: base_path))
147
+ return parse_binary_xml(content) if xml_file?(name)
148
+
149
+ content
150
+ end
151
+
152
+ def entry(name, base_path: BASE_PATH)
153
+ entry = @zip.find_entry(File.join(base_path, name))
154
+ raise NotFoundError, "'#{name}'" if entry.nil?
155
+
156
+ entry
157
+ end
158
+
159
+ def manifest
160
+ io = zip.read(zip.find_entry(BASE_MANIFEST))
161
+ @manifest ||= Protobuf::Manifest.parse(io, resource)
162
+ end
163
+
164
+ def resource
165
+ io = zip.read(zip.find_entry(BASE_RESOURCES))
166
+ @resource ||= Protobuf::Resources.parse(io)
167
+ end
168
+
169
+ def zip
170
+ @zip ||= Zip::File.open(@file)
171
+ end
172
+
173
+ def icons
174
+ @icons ||= manifest.icons.each_with_object([]) do |res, obj|
175
+ path = res.value
176
+ filename = File.basename(path)
177
+ filepath = File.join(contents, File.dirname(path))
178
+ file = File.join(filepath, filename)
179
+ FileUtils.mkdir_p filepath
180
+
181
+ binary_data = read_file(path)
182
+ File.write(file, binary_data, encoding: Encoding::BINARY)
183
+
184
+ obj << {
185
+ name: filename,
186
+ file: file,
187
+ dimensions: ImageSize.path(file).size
188
+ }
189
+ end
190
+ end
191
+
192
+ def clear!
193
+ return unless @contents
194
+
195
+ FileUtils.rm_rf(@contents)
196
+
197
+ @aab = nil
198
+ @contents = nil
199
+ @icons = nil
200
+ @app_path = nil
201
+ @info = nil
202
+ end
203
+
204
+ def contents
205
+ @contents ||= File.join(Dir.mktmpdir, "AppInfo-android-#{SecureRandom.hex}")
206
+ end
207
+
208
+ private
209
+
210
+ def xml_file?(file)
211
+ File.extname(file) == '.xml'
212
+ end
213
+
214
+ # TODO: how to convert xml content after decode protoubufed content
215
+ def parse_binary_xml(io)
216
+ io
217
+ # Aapt::Pb::XmlNode.decode(io)
218
+ end
219
+ end
220
+ end
data/lib/app_info/apk.rb CHANGED
@@ -7,6 +7,7 @@ require 'forwardable'
7
7
  module AppInfo
8
8
  # Parse APK file
9
9
  class APK
10
+ include Helper::HumanFileSize
10
11
  extend Forwardable
11
12
 
12
13
  attr_reader :file
@@ -24,11 +25,11 @@ module AppInfo
24
25
  end
25
26
 
26
27
  def size(human_size: false)
27
- AppInfo::Util.file_size(@file, human_size)
28
+ file_to_human_size(@file, human_size: human_size)
28
29
  end
29
30
 
30
31
  def os
31
- AppInfo::Platform::ANDROID
32
+ Platform::ANDROID
32
33
  end
33
34
  alias file_type os
34
35
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppInfo
4
+ module Inflector
5
+ def snakecase
6
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
7
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
8
+ .tr('-', '_')
9
+ .gsub(/\s/, '_')
10
+ .gsub(/__+/, '_')
11
+ .downcase
12
+ end
13
+
14
+ def camelcase(first_letter: :upper, separators: ['-', '_', '\s'])
15
+ str = dup
16
+
17
+ separators.each do |s|
18
+ str = str.gsub(/(?:#{s}+)([a-z])/) { $1.upcase }
19
+ end
20
+
21
+ case first_letter
22
+ when :upper, true
23
+ str = str.gsub(/(\A|\s)([a-z])/) { $1 + $2.upcase }
24
+ when :lower, false
25
+ str = str.gsub(/(\A|\s)([A-Z])/) { $1 + $2.downcase }
26
+ end
27
+
28
+ str
29
+ end
30
+ end
31
+ end
32
+
33
+ class String
34
+ include AppInfo::Inflector
35
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'app_info/core_ext/object/try'
4
+ require 'app_info/core_ext/string/inflector'
data/lib/app_info/dsym.rb CHANGED
@@ -5,6 +5,8 @@ require 'macho'
5
5
  module AppInfo
6
6
  # DSYM parser
7
7
  class DSYM
8
+ include Helper::Archive
9
+
8
10
  attr_reader :file
9
11
 
10
12
  def initialize(file)
@@ -12,7 +14,7 @@ module AppInfo
12
14
  end
13
15
 
14
16
  def file_type
15
- AppInfo::Platform::DSYM
17
+ Platform::DSYM
16
18
  end
17
19
 
18
20
  def object
@@ -91,7 +93,7 @@ module AppInfo
91
93
  @contents = @file
92
94
  else
93
95
  dsym_dir = nil
94
- @contents = Util.unarchive(@file, path: 'dsym') do |path, zip_file|
96
+ @contents = unarchive(@file, path: 'dsym') do |path, zip_file|
95
97
  zip_file.each do |f|
96
98
  unless dsym_dir
97
99
  dsym_dir = f.name
@@ -114,6 +116,8 @@ module AppInfo
114
116
 
115
117
  # DSYM Mach-O
116
118
  class MachO
119
+ include Helper::HumanFileSize
120
+
117
121
  def initialize(file, size = 0)
118
122
  @file = file
119
123
  @size = size
@@ -132,7 +136,7 @@ module AppInfo
132
136
  end
133
137
 
134
138
  def size(human_size: false)
135
- return Util.size_to_human_size(@size) if human_size
139
+ return number_to_human_size(@size) if human_size
136
140
 
137
141
  @size
138
142
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zip'
4
+ require 'fileutils'
5
+ require 'securerandom'
6
+
7
+ module AppInfo
8
+ class Error < StandardError; end
9
+
10
+ class NotFoundError < Error; end
11
+
12
+ class UnkownFileTypeError < Error; end
13
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppInfo
4
+ # App Platform
5
+ module Platform
6
+ MACOS = 'macOS'
7
+ IOS = 'iOS'
8
+ ANDROID = 'Android'
9
+ DSYM = 'dSYM'
10
+ PROGUARD = 'Proguard'
11
+ end
12
+
13
+ # Device Type
14
+ module Device
15
+ MACOS = 'macOS'
16
+ IPHONE = 'iPhone'
17
+ IPAD = 'iPad'
18
+ UNIVERSAL = 'Universal'
19
+ end
20
+
21
+ module AndroidDevice
22
+ PHONE = 'Phone'
23
+ TABLET = 'Tablet'
24
+ WATCH = 'Watch'
25
+ TV = 'Television'
26
+ end
27
+
28
+ # Icon Key
29
+ ICON_KEYS = {
30
+ Device::IPHONE => ['CFBundleIcons'],
31
+ Device::IPAD => ['CFBundleIcons~ipad'],
32
+ Device::UNIVERSAL => ['CFBundleIcons', 'CFBundleIcons~ipad'],
33
+ Device::MACOS => %w[CFBundleIconFile CFBundleIconName]
34
+ }.freeze
35
+
36
+ module Helper
37
+ module HumanFileSize
38
+ def file_to_human_size(file, human_size:)
39
+ number = File.size(file)
40
+ human_size ? number_to_human_size(number) : number
41
+ end
42
+
43
+ FILE_SIZE_UNITS = %w[B KB MB GB TB].freeze
44
+
45
+ def number_to_human_size(number)
46
+ if number.to_i < 1024
47
+ exponent = 0
48
+ else
49
+ max_exp = FILE_SIZE_UNITS.size - 1
50
+ exponent = (Math.log(number) / Math.log(1024)).to_i
51
+ exponent = max_exp if exponent > max_exp
52
+ number = format('%<number>.2f', number: (number / (1024**exponent.to_f)))
53
+ end
54
+
55
+ "#{number} #{FILE_SIZE_UNITS[exponent]}"
56
+ end
57
+ end
58
+
59
+ module Archive
60
+ require 'zip'
61
+ require 'fileutils'
62
+ require 'securerandom'
63
+
64
+ # Unarchive zip file
65
+ #
66
+ # source: https://github.com/soffes/lagunitas/blob/master/lib/lagunitas/ipa.rb
67
+ def unarchive(file, path: nil)
68
+ path = path ? "#{path}-" : ''
69
+ root_path = "#{Dir.mktmpdir}/AppInfo-#{path}#{SecureRandom.hex}"
70
+ Zip::File.open(file) do |zip_file|
71
+ if block_given?
72
+ yield root_path, zip_file
73
+ else
74
+ zip_file.each do |f|
75
+ f_path = File.join(root_path, f.name)
76
+ FileUtils.mkdir_p(File.dirname(f_path))
77
+ zip_file.extract(f, f_path) unless File.exist?(f_path)
78
+ end
79
+ end
80
+ end
81
+
82
+ root_path
83
+ end
84
+
85
+ def tempdir(file, prefix:)
86
+ dest_path ||= File.join(File.dirname(file), prefix)
87
+ dest_file = File.join(dest_path, File.basename(file))
88
+
89
+ Dir.mkdir(dest_path, 0_700) unless Dir.exist?(dest_path)
90
+
91
+ dest_file
92
+ end
93
+ end
94
+
95
+ module Defines
96
+ def create_class(klass_name, parent_class, namespace:)
97
+ klass = Class.new(parent_class) do
98
+ yield if block_given?
99
+ end
100
+
101
+ name = namespace.to_s.empty? ? klass_name : "#{namespace}::#{klass_name}"
102
+ if Object.const_defined?(name)
103
+ Object.const_get(name)
104
+ else
105
+ Object.const_get(namespace).const_set(klass_name, klass)
106
+ end
107
+ end
108
+
109
+ def define_instance_method(key, value)
110
+ instance_variable_set("@#{key}", value)
111
+ self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
112
+ def #{key}
113
+ @#{key}
114
+ end
115
+ RUBY
116
+ end
117
+ end
118
+
119
+ module ReferenceParser
120
+ def reference_segments(value)
121
+ new_value = value.is_a?(Aapt::Pb::Reference) ? value.name : value
122
+ return new_value.split('/', 2) if new_value.include?('/')
123
+
124
+ [nil, new_value]
125
+ end
126
+ end
127
+ end
128
+ end
@@ -67,13 +67,13 @@ module AppInfo
67
67
  def device_type
68
68
  device_family = info.try(:[], 'UIDeviceFamily')
69
69
  if device_family == [1]
70
- AppInfo::Device::IPHONE
70
+ Device::IPHONE
71
71
  elsif device_family == [2]
72
- AppInfo::Device::IPAD
72
+ Device::IPAD
73
73
  elsif device_family == [1, 2]
74
- AppInfo::Device::UNIVERSAL
74
+ Device::UNIVERSAL
75
75
  elsif !info.try(:[], 'DTSDKName').nil? || !info.try(:[], 'DTPlatformName').nil?
76
- AppInfo::Device::MACOS
76
+ Device::MACOS
77
77
  end
78
78
  end
79
79
 
@@ -112,13 +112,13 @@ module AppInfo
112
112
  def_delegators :info, :to_h
113
113
 
114
114
  def method_missing(method_name, *args, &block)
115
- info.try(:[], Util.format_key(method_name)) ||
115
+ info.try(:[], method_name.to_s.camelcase) ||
116
116
  info.send(method_name) ||
117
117
  super
118
118
  end
119
119
 
120
120
  def respond_to_missing?(method_name, *args)
121
- info.key?(Util.format_key(method_name)) ||
121
+ info.key?(method_name.to_s.camelcase) ||
122
122
  info.respond_to?(method_name) ||
123
123
  super
124
124
  end
data/lib/app_info/ipa.rb CHANGED
@@ -8,6 +8,8 @@ require 'cfpropertylist'
8
8
  module AppInfo
9
9
  # IPA parser
10
10
  class IPA
11
+ include Helper::HumanFileSize
12
+ include Helper::Archive
11
13
  extend Forwardable
12
14
 
13
15
  attr_reader :file
@@ -28,11 +30,11 @@ module AppInfo
28
30
  end
29
31
 
30
32
  def size(human_size: false)
31
- AppInfo::Util.file_size(@file, human_size)
33
+ file_to_human_size(@file, human_size: human_size)
32
34
  end
33
35
 
34
36
  def os
35
- AppInfo::Platform::IOS
37
+ Platform::IOS
36
38
  end
37
39
  alias file_type os
38
40
 
@@ -195,7 +197,7 @@ module AppInfo
195
197
  end
196
198
 
197
199
  def contents
198
- @contents ||= Util.unarchive(@file, path: 'ios')
200
+ @contents ||= unarchive(@file, path: 'ios')
199
201
  end
200
202
 
201
203
  private
@@ -213,7 +215,7 @@ module AppInfo
213
215
 
214
216
  # Uncrush png to normal png file (iOS)
215
217
  def uncrush_png(src_file)
216
- dest_file = Util.tempdir(src_file, prefix: 'uncrushed')
218
+ dest_file = tempdir(src_file, prefix: 'uncrushed')
217
219
  PngUncrush.decompress(src_file, dest_file)
218
220
  File.exist?(dest_file) ? dest_file : nil
219
221
  end
@@ -8,6 +8,8 @@ require 'cfpropertylist'
8
8
  module AppInfo
9
9
  # MacOS App parser
10
10
  class Macos
11
+ include Helper::HumanFileSize
12
+ include Helper::Archive
11
13
  extend Forwardable
12
14
 
13
15
  attr_reader :file
@@ -24,11 +26,11 @@ module AppInfo
24
26
  end
25
27
 
26
28
  def size(human_size: false)
27
- AppInfo::Util.file_size(@file, human_size)
29
+ file_to_human_size(@file, human_size: human_size)
28
30
  end
29
31
 
30
32
  def os
31
- AppInfo::Platform::MACOS
33
+ Platform::MACOS
32
34
  end
33
35
  alias file_type os
34
36
 
@@ -142,7 +144,7 @@ module AppInfo
142
144
  end
143
145
 
144
146
  def contents
145
- @contents ||= Util.unarchive(@file, path: 'macos')
147
+ @contents ||= unarchive(@file, path: 'macos')
146
148
  end
147
149
 
148
150
  private
@@ -172,7 +174,7 @@ module AppInfo
172
174
  reader = Icns::Reader.new(file)
173
175
  Icns::SIZE_TO_TYPE.each do |size, _|
174
176
  dest_filename = "#{File.basename(file, '.icns')}_#{size}x#{size}.png"
175
- dest_file = Util.tempdir(File.join(File.dirname(file), dest_filename), prefix: 'converted')
177
+ dest_file = tempdir(File.join(File.dirname(file), dest_filename), prefix: 'converted')
176
178
  next unless icon_data = reader.image(size: size)
177
179
 
178
180
  File.write(dest_file, icon_data, encoding: Encoding::BINARY)