app-info 2.6.3 → 2.7.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9eef87bb332f9254d735c87fee5c1b97fe52f46c2a170330dfb2e97b0da53820
4
- data.tar.gz: dd9ca88176f686024e9df28db23912a3e417973872d8a8641ba308dec0310828
3
+ metadata.gz: '09f29a3f5c7efa6e39d589cfc5d4a168d5267bb88ebf9434a377dbe1ba9d6326'
4
+ data.tar.gz: 45bb2036a6777b043ab85b399d0559f92f144750d98097ea3ad6007ffed39c0d
5
5
  SHA512:
6
- metadata.gz: 63f890a680ec379ea50865884350b26b974db6ab90e093543f03383d9cbf6387cdf22265373d50178fd529bd7b069aeb87618b81c63a7274d2c1f25f69a3a577
7
- data.tar.gz: 027331c8ed5da50e17aae317c800cc8418c8a1453e5422778b4d8a2cd3467ef6fac89e2045faa6a5becff9aaf25617e04b711011589e92801b22c051d628b1c4
6
+ metadata.gz: 99af334d2500db7df891232986366e390943a11689b593f0b827edeabc68fdc3df38b0c2d675c09282941f4f3870ad8afa6ee46c95b18acf1d40c41990698b19
7
+ data.tar.gz: 45c1da2efa47617b4dccd315fb868097df4814492e6e9e6371082c9f84171ed493eb9de8449483a8d640e8b0d2a830f0840eff199e4a786ff937f8662b102240
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,30 @@ 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.beta2] (2021-09-29)
13
+
14
+ ### Fixed
15
+
16
+ - Fix allocator undefined data class [#38](https://github.com/icyleaf/app_info/pull/38)
17
+
18
+ ## [2.7.0.beta1] (2021-09-27)
19
+
20
+ ### Added
21
+
22
+ - Android App Bundle a.k.a `aab` file parts support [#36](https://github.com/icyleaf/app_info/pull/36)
23
+
24
+ ## [2.6.5] (2021-09-17)
25
+
26
+ ### Added
27
+
28
+ - Add ability to retrieve manifest metadata (depend on playtestcloud/ruby_apk forked one)
29
+
30
+ ## [2.6.4] (2021-09-10)
31
+
32
+ ### Fixed
33
+
34
+ - Error on extract dSYM zipped file occasionally
35
+
12
36
  ## [2.6.3] (2021-08-27)
13
37
 
14
38
  ### Fixed
@@ -173,7 +197,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
173
197
 
174
198
  - Updated dependency of CFPropertly list be a range between 2.3.4. (thanks @[cschroed](https://github.com/cschroed))
175
199
 
176
- [Unreleased]: https://github.com/icyleaf/app-info/compare/v2.6.3..HEAD
200
+ [Unreleased]: https://github.com/icyleaf/app-info/compare/v2.7.0.beta2..HEAD
201
+ [2.7.0.beta2]: https://github.com/icyleaf/app-info/compare/v2.7.0.beta1...v2.7.0.beta2
202
+ [2.7.0.beta1]: https://github.com/icyleaf/app-info/compare/v2.6.5...v2.7.0.beta1
203
+ [2.6.5]: https://github.com/icyleaf/app-info/compare/v2.6.4...v2.6.5
204
+ [2.6.4]: https://github.com/icyleaf/app-info/compare/v2.6.3...v2.6.4
177
205
  [2.6.3]: https://github.com/icyleaf/app-info/compare/v2.6.1...v2.6.3
178
206
  [2.6.1]: https://github.com/icyleaf/app-info/compare/v2.6.0...v2.6.1
179
207
  [2.6.0]: https://github.com/icyleaf/app-info/compare/v2.5.4...v2.6.0
data/README.md CHANGED
@@ -5,16 +5,18 @@
5
5
  [![Gem version](https://img.shields.io/gem/v/app-info.svg?style=flat)](https://rubygems.org/gems/app_info)
6
6
  [![License](https://img.shields.io/badge/license-MIT-red.svg?style=flat)](LICENSE)
7
7
 
8
- Teardown tool for mobile(ipa/apk) app, macOS app and dSYM.zip file, analysis metedata like version, name, icon etc.
8
+ Teardown tool for mobile app (ipa, apk and aab file), macOS app and dSYM.zip file, analysis metedata like version, name, icon etc.
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
@@ -23,10 +23,11 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency 'CFPropertyList', '< 3.1.0', '>= 2.3.4'
24
24
  spec.add_dependency 'image_size', '>= 1.5', '< 2.2'
25
25
  spec.add_dependency 'ruby-macho', '< 3', '>= 1.4'
26
- spec.add_dependency 'ruby_android', '~> 0.7.7'
26
+ spec.add_dependency 'android_parser', '~> 2.4.1'
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,15 +93,17 @@ 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
98
- dsym_dir = dsym_dir.split('/')[0] # fix filename is xxx.app.dSYM/Contents
100
+ # fix filename is xxx.app.dSYM/Contents
101
+ dsym_dir = dsym_dir.split('/')[0] if dsym_dir.include?('/')
99
102
  end
100
103
 
101
104
  f_path = File.join(path, f.name)
102
- zip_file.extract(f, f_path) unless File.exist?(f_path)
105
+ FileUtils.mkdir_p(File.dirname(f_path))
106
+ f.extract(f_path) unless File.exist?(f_path)
103
107
  end
104
108
  end
105
109
 
@@ -112,6 +116,8 @@ module AppInfo
112
116
 
113
117
  # DSYM Mach-O
114
118
  class MachO
119
+ include Helper::HumanFileSize
120
+
115
121
  def initialize(file, size = 0)
116
122
  @file = file
117
123
  @size = size
@@ -130,7 +136,7 @@ module AppInfo
130
136
  end
131
137
 
132
138
  def size(human_size: false)
133
- return Util.size_to_human_size(@size) if human_size
139
+ return number_to_human_size(@size) if human_size
134
140
 
135
141
  @size
136
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,130 @@
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_get(namespace).const_defined?(klass_name)
103
+ Object.const_get(namespace).const_get(klass_name)
104
+ elsif Object.const_defined?(name)
105
+ Object.const_get(name)
106
+ else
107
+ Object.const_get(namespace).const_set(klass_name, klass)
108
+ end
109
+ end
110
+
111
+ def define_instance_method(key, value)
112
+ instance_variable_set("@#{key}", value)
113
+ self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
114
+ def #{key}
115
+ @#{key}
116
+ end
117
+ RUBY
118
+ end
119
+ end
120
+
121
+ module ReferenceParser
122
+ def reference_segments(value)
123
+ new_value = value.is_a?(Aapt::Pb::Reference) ? value.name : value
124
+ return new_value.split('/', 2) if new_value.include?('/')
125
+
126
+ [nil, new_value]
127
+ end
128
+ end
129
+ end
130
+ 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