app-info 2.8.5 → 3.0.0.beta2

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +12 -7
  3. data/.github/workflows/ci.yml +3 -1
  4. data/.rubocop.yml +33 -11
  5. data/CHANGELOG.md +34 -1
  6. data/Gemfile +7 -1
  7. data/README.md +68 -13
  8. data/Rakefile +11 -0
  9. data/app_info.gemspec +12 -3
  10. data/lib/app_info/aab.rb +48 -108
  11. data/lib/app_info/android/signature.rb +114 -0
  12. data/lib/app_info/android/signatures/base.rb +53 -0
  13. data/lib/app_info/android/signatures/info.rb +158 -0
  14. data/lib/app_info/android/signatures/v1.rb +63 -0
  15. data/lib/app_info/android/signatures/v2.rb +121 -0
  16. data/lib/app_info/android/signatures/v3.rb +131 -0
  17. data/lib/app_info/android/signatures/v4.rb +18 -0
  18. data/lib/app_info/android.rb +162 -0
  19. data/lib/app_info/apk.rb +54 -111
  20. data/lib/app_info/apple.rb +192 -0
  21. data/lib/app_info/certificate.rb +175 -0
  22. data/lib/app_info/const.rb +75 -0
  23. data/lib/app_info/core_ext/object/try.rb +3 -1
  24. data/lib/app_info/core_ext/string/inflector.rb +2 -0
  25. data/lib/app_info/dsym/debug_info.rb +72 -0
  26. data/lib/app_info/dsym/macho.rb +55 -0
  27. data/lib/app_info/dsym.rb +31 -135
  28. data/lib/app_info/error.rb +2 -2
  29. data/lib/app_info/file.rb +49 -0
  30. data/lib/app_info/helper/archive.rb +37 -0
  31. data/lib/app_info/helper/file_size.rb +25 -0
  32. data/lib/app_info/helper/generate_class.rb +29 -0
  33. data/lib/app_info/helper/protobuf.rb +12 -0
  34. data/lib/app_info/helper/signatures.rb +229 -0
  35. data/lib/app_info/helper.rb +5 -126
  36. data/lib/app_info/info_plist.rb +66 -29
  37. data/lib/app_info/ipa/framework.rb +4 -4
  38. data/lib/app_info/ipa.rb +61 -135
  39. data/lib/app_info/macos.rb +54 -102
  40. data/lib/app_info/mobile_provision.rb +67 -49
  41. data/lib/app_info/pe.rb +260 -0
  42. data/lib/app_info/png_uncrush.rb +24 -4
  43. data/lib/app_info/proguard.rb +29 -16
  44. data/lib/app_info/protobuf/manifest.rb +6 -3
  45. data/lib/app_info/protobuf/models/Configuration_pb.rb +1 -0
  46. data/lib/app_info/protobuf/models/README.md +7 -0
  47. data/lib/app_info/protobuf/models/Resources_pb.rb +2 -0
  48. data/lib/app_info/protobuf/resources.rb +5 -5
  49. data/lib/app_info/version.rb +1 -1
  50. data/lib/app_info.rb +90 -46
  51. metadata +48 -35
@@ -4,20 +4,37 @@ require 'openssl'
4
4
  require 'cfpropertylist'
5
5
 
6
6
  module AppInfo
7
- # .mobileprovision file parser
8
- class MobileProvision
9
- def initialize(path)
10
- @path = path
7
+ # Apple code signing: provisioning profile parser
8
+ # @see https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles
9
+ class MobileProvision < File
10
+ # @return [Symbol] {Platform}
11
+ def platform
12
+ Platform::APPLE
13
+ end
14
+
15
+ # @return [Symbol] {OperaSystem}
16
+ def opera_system
17
+ case opera_systems[0]
18
+ when :macos
19
+ OperaSystem::MACOS
20
+ when :ios
21
+ OperaSystem::IOS
22
+ else
23
+ raise NotImplementedError, "Unkonwn opera_system: #{opera_systems[0]}"
24
+ end
11
25
  end
12
26
 
27
+ # @return [String, nil]
13
28
  def name
14
29
  mobileprovision.try(:[], 'Name')
15
30
  end
16
31
 
32
+ # @return [String, nil]
17
33
  def app_name
18
34
  mobileprovision.try(:[], 'AppIDName')
19
35
  end
20
36
 
37
+ # @return [Symbol, nil]
21
38
  def type
22
39
  return :development if development?
23
40
  return :adhoc if adhoc?
@@ -25,7 +42,8 @@ module AppInfo
25
42
  return :enterprise if enterprise?
26
43
  end
27
44
 
28
- def platforms
45
+ # @return [Array<Symbol>]
46
+ def opera_systems
29
47
  return unless platforms = mobileprovision.try(:[], 'Platform')
30
48
 
31
49
  platforms.map do |v|
@@ -34,83 +52,100 @@ module AppInfo
34
52
  end
35
53
  end
36
54
 
37
- def platform
38
- platforms[0]
39
- end
40
-
55
+ # @return [Array<String>, nil]
41
56
  def devices
42
57
  mobileprovision.try(:[], 'ProvisionedDevices')
43
58
  end
44
59
 
60
+ # @return [String, nil]
45
61
  def team_identifier
46
62
  mobileprovision.try(:[], 'TeamIdentifier')
47
63
  end
48
64
 
65
+ # @return [String, nil]
49
66
  def team_name
50
67
  mobileprovision.try(:[], 'TeamName')
51
68
  end
52
69
 
70
+ # @return [String, nil]
53
71
  def profile_name
54
72
  mobileprovision.try(:[], 'Name')
55
73
  end
56
74
 
75
+ # @return [String, nil]
57
76
  def created_date
58
77
  mobileprovision.try(:[], 'CreationDate')
59
78
  end
60
79
 
80
+ # @return [String, nil]
61
81
  def expired_date
62
82
  mobileprovision.try(:[], 'ExpirationDate')
63
83
  end
64
84
 
85
+ # @return [Array<String>, nil]
65
86
  def entitlements
66
87
  mobileprovision.try(:[], 'Entitlements')
67
88
  end
68
89
 
90
+ # return developer certificates.
91
+ #
92
+ # @deprecated Use {#certificates} instead of this method.
69
93
  def developer_certs
94
+ certificates
95
+ end
96
+
97
+ # return developer certificates.
98
+ #
99
+ # @return [Array<Certificate>]
100
+ def certificates
70
101
  certs = mobileprovision.try(:[], 'DeveloperCertificates')
71
102
  return if certs.empty?
72
103
 
73
- certs.each_with_object([]) do |cert, obj|
74
- obj << DeveloperCertificate.new(cert)
104
+ certs.each_with_object([]) do |cert_data, obj|
105
+ obj << Certificate.parse(cert_data)
75
106
  end
76
107
  end
77
108
 
78
109
  # Detect is development type of mobileprovision
79
110
  #
80
- # related link: https://stackoverflow.com/questions/1003066/what-does-get-task-allow-do-in-xcode
111
+ # @see https://stackoverflow.com/questions/1003066/what-does-get-task-allow-do-in-xcode
112
+ # @return [Boolea]
81
113
  def development?
82
- case platform.downcase.to_sym
83
- when :ios
114
+ case opera_system
115
+ when OperaSystem::IOS
84
116
  entitlements['get-task-allow'] == true
85
- when :macos
117
+ when OperaSystem::MACOS
86
118
  !devices.nil?
87
119
  else
88
- raise Error, "Not implement with platform: #{platform}"
120
+ raise NotImplementedError, "Unknown opera_system: #{opera_system}"
89
121
  end
90
122
  end
91
123
 
92
124
  # Detect app store type
93
125
  #
94
- # related link: https://developer.apple.com/library/archive/qa/qa1830/_index.html
126
+ # @see https://developer.apple.com/library/archive/qa/qa1830/_index.html
127
+ # @return [Boolea]
95
128
  def appstore?
96
- case platform.downcase.to_sym
97
- when :ios
129
+ case opera_system
130
+ when OperaSystem::IOS
98
131
  !development? && entitlements.key?('beta-reports-active')
99
- when :macos
132
+ when OperaSystem::MACOS
100
133
  !development?
101
134
  else
102
- raise Error, "Not implement with platform: #{platform}"
135
+ raise NotImplementedError, "Unknown opera_system: #{opera_system}"
103
136
  end
104
137
  end
105
138
 
139
+ # @return [Boolea]
106
140
  def adhoc?
107
- return false if platform == :macos # macOS no need adhoc
141
+ return false if opera_system == OperaSystem::MACOS # macOS no need adhoc
108
142
 
109
143
  !development? && !devices.nil?
110
144
  end
111
145
 
146
+ # @return [Boolea]
112
147
  def enterprise?
113
- return false if platform == :macos # macOS no need adhoc
148
+ return false if opera_system == OperaSystem::MACOS # macOS no need adhoc
114
149
 
115
150
  !development? && !adhoc? && !appstore?
116
151
  end
@@ -118,7 +153,8 @@ module AppInfo
118
153
 
119
154
  # Enabled Capabilites
120
155
  #
121
- # Related link: https://developer.apple.com/support/app-capabilities/
156
+ # @see https://developer.apple.com/support/app-capabilities/
157
+ # @return [Array<String>]
122
158
  def enabled_capabilities
123
159
  capabilities = []
124
160
  capabilities << 'In-App Purchase' << 'GameKit' if adhoc? || appstore?
@@ -142,10 +178,10 @@ module AppInfo
142
178
  when 'com.apple.developer.networking.vpn.api'
143
179
  capabilities << 'Personal VPN'
144
180
  when 'com.apple.developer.healthkit',
145
- 'com.apple.developer.healthkit.access'
181
+ 'com.apple.developer.healthkit.access'
146
182
  capabilities << 'HealthKit' unless capabilities.include?('HealthKit')
147
183
  when 'com.apple.developer.icloud-services',
148
- 'com.apple.developer.icloud-container-identifiers'
184
+ 'com.apple.developer.icloud-container-identifiers'
149
185
  capabilities << 'iCloud' unless capabilities.include?('iCloud')
150
186
  when 'com.apple.developer.in-app-payments'
151
187
  capabilities << 'Apple Pay'
@@ -192,18 +228,21 @@ module AppInfo
192
228
  capabilities
193
229
  end
194
230
 
231
+ # @return [String, nil]
195
232
  def [](key)
196
233
  mobileprovision.try(:[], key.to_s)
197
234
  end
198
235
 
236
+ # @return [Boolea]
199
237
  def empty?
200
238
  mobileprovision.nil?
201
239
  end
202
240
 
241
+ # @return [CFPropertyList]
203
242
  def mobileprovision
204
- return @mobileprovision = nil unless File.exist?(@path)
243
+ return @mobileprovision = nil unless ::File.exist?(@file)
205
244
 
206
- data = File.read(@path)
245
+ data = ::File.read(@file)
207
246
  data = strip_plist_wrapper(data) unless bplist?(data)
208
247
  list = CFPropertyList::List.new(data: data).value
209
248
  @mobileprovision = CFPropertyList.native_types(list)
@@ -235,26 +274,5 @@ module AppInfo
235
274
  end_point = raw.index(end_tag) + end_tag.size - 1
236
275
  raw[start_point..end_point]
237
276
  end
238
-
239
- # Developer Certificate
240
- class DeveloperCertificate
241
- attr_reader :raw
242
-
243
- def initialize(data)
244
- @raw = OpenSSL::X509::Certificate.new(data)
245
- end
246
-
247
- def name
248
- @raw.subject.to_a.find { |name, _, _| name == 'CN' }[1].force_encoding('UTF-8')
249
- end
250
-
251
- def created_date
252
- @raw.not_after
253
- end
254
-
255
- def expired_date
256
- @raw.not_before
257
- end
258
- end
259
277
  end
260
278
  end
@@ -0,0 +1,260 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pedump'
4
+ require 'fileutils'
5
+ require 'forwardable'
6
+
7
+ module AppInfo
8
+ # Windows PE parser
9
+ #
10
+ # @see https://learn.microsoft.com/zh-cn/windows/win32/debug/pe-format Microsoft PE Format
11
+ class PE < File
12
+ include Helper::HumanFileSize
13
+ include Helper::Archive
14
+ extend Forwardable
15
+
16
+ ARCH = {
17
+ 0x014c => 'x86',
18
+ 0x0200 => 'Intel Itanium',
19
+ 0x8664 => 'x64',
20
+ 0x1c0 => 'arm',
21
+ 0xaa64 => 'arm64',
22
+ 0x5032 => 'RISC-v 32',
23
+ 0x5064 => 'RISC-v 64',
24
+ 0x5128 => 'RISC-v 128'
25
+ }.freeze
26
+
27
+ # @return [Symbol] {Platform}
28
+ def platform
29
+ Platform::WINDOWS
30
+ end
31
+
32
+ # @return [Symbol] {OperaSystem}
33
+ def opera_system
34
+ OperaSystem::WINDOWS
35
+ end
36
+
37
+ # @return [Symbol] {Device}
38
+ def device
39
+ Device::WINDOWS
40
+ end
41
+
42
+ # return file size
43
+ # @example Read file size in integer
44
+ # aab.size # => 3618865
45
+ #
46
+ # @example Read file size in human readabale
47
+ # aab.size(human_size: true) # => '3.45 MB'
48
+ #
49
+ # @param [Boolean] human_size Convert integer value to human readable.
50
+ # @return [Integer, String]
51
+ def size(human_size: false)
52
+ file_to_human_size(@file, human_size: human_size)
53
+ end
54
+
55
+ def binary_size(human_size: false)
56
+ file_to_human_size(binary_file, human_size: human_size)
57
+ end
58
+
59
+ # @!method product_name
60
+ # @see VersionInfo#product_name
61
+ # @return [String]
62
+ # @!method product_version
63
+ # @see VersionInfo#product_version
64
+ # @return [String]
65
+ # @!method company_name
66
+ # @see VersionInfo#company_name
67
+ # @return [String]
68
+ # @!method assembly_version
69
+ # @see VersionInfo#assembly_version
70
+ # @return [String]
71
+ def_delegators :version_info, :product_name, :product_version, :company_name, :assembly_version
72
+
73
+ alias name product_name
74
+ alias release_version product_version
75
+ alias build_version assembly_version
76
+
77
+ # @return [String]
78
+ def archs
79
+ ARCH[image_file_header.Machine] || 'unknown'
80
+ end
81
+ alias architectures archs
82
+
83
+ # @return [Hash{String => String}] imports imports of libraries
84
+ def imports
85
+ @imports ||= pe.imports.each_with_object({}) do |import, obj|
86
+ obj[import.module_name] = import.first_thunk.map(&:name).compact
87
+ end
88
+ end
89
+
90
+ # @return [Array{String}] icons paths of bmp image icons
91
+ def icons
92
+ @icons ||= lambda {
93
+ # Fetch the largest size icon
94
+ files = []
95
+ pe.resources&.find_all do |res|
96
+ next unless res.type == 'ICON'
97
+
98
+ filename = "#{::File.basename(file, '.*')}-#{res.type}-#{res.id}.bmp"
99
+ icon_file = tempdir(filename, prefix: 'pe', system: true)
100
+ mask_icon_file = icon_file.sub('.bmp', '.mask.bmp')
101
+
102
+ begin
103
+ ::File.open(icon_file, 'wb') do |f|
104
+ f << res.restore_bitmap(io)
105
+ end
106
+
107
+ if res.bitmap_mask(io)
108
+ mask_icon_file = icon_file.sub('.bmp', '.mask.bmp')
109
+ ::File.open(mask_icon_file, 'wb') do |f|
110
+ f << res.bitmap_mask(io)
111
+ end
112
+ end
113
+ rescue StandardError => e
114
+ # ignore pedump throws any exception.
115
+ raise e unless e.backtrace.first.include?('pedump')
116
+
117
+ FileUtils.rm_f(icon_file)
118
+ ensure
119
+ next unless ::File.exist?(icon_file)
120
+
121
+ mask_file = ::File.exist?(mask_icon_file) ? mask_icon_file : nil
122
+ files << icon_metadata(icon_file, mask_file: mask_file)
123
+ end
124
+ end
125
+
126
+ files
127
+ }.call
128
+ end
129
+
130
+ # @return [PEdump]
131
+ def pe
132
+ @pe ||= lambda {
133
+ pe = PEdump.new(io)
134
+ pe.logger.level = Logger::FATAL # ignore :warn logger output
135
+ pe
136
+ }.call
137
+ end
138
+
139
+ # @return [VersionInfo]
140
+ def version_info
141
+ @version_info ||= VersionInfo.new(pe.version_info)
142
+ end
143
+
144
+ def clear!
145
+ @io = nil
146
+ @pe = nil
147
+ @icons = nil
148
+ @imports = nil
149
+ end
150
+
151
+ # @return [String] binary_file path
152
+ def binary_file
153
+ @binary_file ||= lambda {
154
+ file_io = ::File.open(@file, 'rb')
155
+ return @file unless file_io.read(100) =~ AppInfo::ZIP_RETGEX
156
+
157
+ zip_file = Zip::File.open(@file)
158
+ zip_entry = zip_file.glob('*.exe').first
159
+ raise NotFoundError, 'Not found .exe file in archive file' if zip_entry.nil?
160
+
161
+ exe_file = tempdir(zip_entry.name, prefix: 'pe-exe', system: true)
162
+ zip_entry.extract(exe_file)
163
+ zip_file.close
164
+
165
+ return exe_file
166
+ }.call
167
+ end
168
+
169
+ private
170
+
171
+ def image_file_header
172
+ @image_file_header ||= pe.pe.image_file_header
173
+ end
174
+
175
+ # @return [Hash{Symbol => String}]
176
+ def icon_metadata(file, mask_file: nil)
177
+ {
178
+ name: ::File.basename(file),
179
+ file: file,
180
+ mask: mask_file,
181
+ dimensions: ImageSize.path(file).size
182
+ }
183
+ end
184
+
185
+ # @return [File]
186
+ def io
187
+ @io ||= ::File.open(binary_file, 'rb')
188
+ end
189
+
190
+ # VersionInfo class
191
+ #
192
+ # Ref: https://learn.microsoft.com/zh-cn/windows/win32/menurc/versioninfo-resource
193
+ class VersionInfo
194
+ def initialize(raw)
195
+ @raw = raw
196
+ end
197
+
198
+ # @return [String]
199
+ def company_name
200
+ @company_name ||= value_of('CompanyName')
201
+ end
202
+
203
+ # @return [String]
204
+ def product_name
205
+ @product_name ||= value_of('ProductName')
206
+ end
207
+
208
+ # @return [String]
209
+ def product_version
210
+ @product_version ||= value_of('ProductVersion')
211
+ end
212
+
213
+ # @return [String]
214
+ def assembly_version
215
+ @assembly_version ||= value_of('Assembly Version')
216
+ end
217
+
218
+ # @return [String]
219
+ def file_version
220
+ @file_version ||= value_of('FileVersion')
221
+ end
222
+
223
+ # @return [String]
224
+ def file_description
225
+ @file_description ||= value_of('FileDescription')
226
+ end
227
+
228
+ # @return [String]
229
+ def copyright
230
+ @copyright ||= value_of('LegalCopyright')
231
+ end
232
+
233
+ private
234
+
235
+ def value_of(key)
236
+ info.each do |v|
237
+ return v[:Value] if v[:szKey] == key.to_s
238
+ end
239
+
240
+ nil
241
+ end
242
+
243
+ def info
244
+ return @info if @info
245
+
246
+ @raw.each do |item|
247
+ next unless item.is_a?(PEdump::VS_VERSIONINFO)
248
+
249
+ versions = item[:Children].select { |v| v.is_a?(PEdump::StringFileInfo) }
250
+ next if versions.empty?
251
+
252
+ @info = versions[0][:Children][0][:Children]
253
+ return @info
254
+ end
255
+
256
+ @info = []
257
+ end
258
+ end
259
+ end
260
+ end
@@ -7,9 +7,10 @@ require 'zlib'
7
7
  require 'stringio'
8
8
 
9
9
  module AppInfo
10
+ # Decompress iOS Png image file.
11
+ # @see https://github.com/swcai/iphone-png-normalizer swcai/iphone-png-normalizer
12
+ # @author Wenwei Cai
10
13
  class PngUncrush
11
- class Error < StandardError; end
12
-
13
14
  class FormatError < Error; end
14
15
 
15
16
  class PngReader # :nodoc:
@@ -31,18 +32,24 @@ module AppInfo
31
32
  @data = String.new
32
33
  end
33
34
 
35
+ # @return [Integer]
34
36
  def size
35
37
  @io.size
36
38
  end
37
39
 
40
+ # @param [String] format
41
+ # @return [String]
42
+ # @see IO package data
38
43
  def unpack(format)
39
44
  @io.unpack(format)
40
45
  end
41
46
 
47
+ # @return [String]
42
48
  def header
43
49
  @header ||= self[0, 8]
44
50
  end
45
51
 
52
+ # @return [Boolean]
46
53
  def png?
47
54
  header.bytes == PNG_HEADER
48
55
  end
@@ -60,23 +67,36 @@ module AppInfo
60
67
  end
61
68
  end
62
69
 
70
+ # Decompress crushed png file.
71
+ # @param [String] input path of png file
72
+ # @param [String] output path of output file
73
+ # @return [Boolean] result whether decompress successfully
63
74
  def self.decompress(input, output)
64
75
  new(input).decompress(output)
65
76
  end
66
77
 
78
+ # get png dimensions
79
+ # @param [String] input path of png file
80
+ # @return [Array<Integer>] dimensions width, height value of png file
67
81
  def self.dimensions(input)
68
82
  new(input).dimensions
69
83
  end
70
84
 
71
85
  def initialize(filename)
72
- @io = PngReader.new(File.open(filename))
86
+ @io = PngReader.new(::File.open(filename))
73
87
  raise FormatError, 'not a png file' unless @io.png?
74
88
  end
75
89
 
90
+ # get png dimensions
91
+ # @param [String] input path of png file
92
+ # @return [Array<Integer>] dimensions width, height value of png file
76
93
  def dimensions
77
94
  _dump_sections(dimensions: true)
78
95
  end
79
96
 
97
+ # Decompress crushed png file.
98
+ # @param [String] output path of output file
99
+ # @return [Boolean] result whether decompress successfully
80
100
  def decompress(output)
81
101
  content = _remap(_dump_sections)
82
102
  return false unless content
@@ -125,7 +145,7 @@ module AppInfo
125
145
  end
126
146
 
127
147
  def write_file(path, content)
128
- File.write(path, content, encoding: Encoding::BINARY)
148
+ ::File.write(path, content, encoding: Encoding::BINARY)
129
149
  true
130
150
  end
131
151
 
@@ -5,52 +5,59 @@ require 'rexml/document'
5
5
 
6
6
  module AppInfo
7
7
  # Proguard parser
8
- class Proguard
8
+ class Proguard < File
9
9
  include Helper::Archive
10
10
 
11
11
  NAMESPACE = UUIDTools::UUID.sha1_create(UUIDTools::UUID_DNS_NAMESPACE, 'icyleaf.com')
12
12
 
13
- attr_reader :file
14
-
15
- def initialize(file)
16
- @file = file
13
+ # @return [Symbol] {Platform}
14
+ def platform
15
+ Platform::GOOGLE
17
16
  end
18
17
 
19
- def file_type
20
- Platform::PROGUARD
18
+ # @return [Symbol] {OperaSystem}
19
+ def opera_system
20
+ OperaSystem::ANDROID
21
21
  end
22
22
 
23
+ # @return [String]
23
24
  def uuid
24
25
  # Similar to https://docs.sentry.io/workflow/debug-files/#proguard-uuids
25
- UUIDTools::UUID.sha1_create(NAMESPACE, File.read(mapping_path)).to_s
26
+ UUIDTools::UUID.sha1_create(NAMESPACE, ::File.read(mapping_path)).to_s
26
27
  end
27
28
  alias debug_id uuid
28
29
 
30
+ # @return [Boolean]
29
31
  def mapping?
30
- File.exist?(mapping_path)
32
+ ::File.exist?(mapping_path)
31
33
  end
32
34
 
35
+ # @return [Boolean]
33
36
  def manifest?
34
- File.exist?(manifest_path)
37
+ ::File.exist?(manifest_path)
35
38
  end
36
39
 
40
+ # @return [Boolean]
37
41
  def symbol?
38
- File.exist?(symbol_path)
42
+ ::File.exist?(symbol_path)
39
43
  end
40
44
  alias resource? symbol?
41
45
 
46
+ # @return [String, nil]
42
47
  def package_name
43
48
  return unless manifest?
44
49
 
45
50
  manifest.root.attributes['package']
46
51
  end
47
52
 
53
+ # @return [String, nil]
48
54
  def releasd_version
49
55
  return unless manifest?
50
56
 
51
57
  manifest.root.attributes['package']
52
58
  end
53
59
 
60
+ # @return [String, nil]
54
61
  def version_name
55
62
  return unless manifest?
56
63
 
@@ -58,6 +65,7 @@ module AppInfo
58
65
  end
59
66
  alias release_version version_name
60
67
 
68
+ # @return [String, nil]
61
69
  def version_code
62
70
  return unless manifest?
63
71
 
@@ -65,27 +73,32 @@ module AppInfo
65
73
  end
66
74
  alias build_version version_code
67
75
 
76
+ # @return [REXML::Document]
68
77
  def manifest
69
78
  return unless manifest?
70
79
 
71
- @manifest ||= REXML::Document.new(File.new(manifest_path))
80
+ @manifest ||= REXML::Document.new(::File.new(manifest_path))
72
81
  end
73
82
 
83
+ # @return [String]
74
84
  def mapping_path
75
- @mapping_path ||= Dir.glob(File.join(contents, '*mapping*.txt')).first
85
+ @mapping_path ||= Dir.glob(::File.join(contents, '*mapping*.txt')).first
76
86
  end
77
87
 
88
+ # @return [String]
78
89
  def manifest_path
79
- @manifest_path ||= File.join(contents, 'AndroidManifest.xml')
90
+ @manifest_path ||= ::File.join(contents, 'AndroidManifest.xml')
80
91
  end
81
92
 
93
+ # @return [String]
82
94
  def symbol_path
83
- @symbol_path ||= File.join(contents, 'R.txt')
95
+ @symbol_path ||= ::File.join(contents, 'R.txt')
84
96
  end
85
97
  alias resource_path symbol_path
86
98
 
99
+ # @return [String] contents path of contents
87
100
  def contents
88
- @contents ||= unarchive(@file, path: 'proguard')
101
+ @contents ||= unarchive(@file, prefix: 'proguard')
89
102
  end
90
103
 
91
104
  def clear!