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
data/lib/app_info/ipa.rb CHANGED
@@ -6,179 +6,106 @@ require 'forwardable'
6
6
  require 'cfpropertylist'
7
7
 
8
8
  module AppInfo
9
- # IPA parser
10
- class IPA
11
- include Helper::HumanFileSize
12
- include Helper::Archive
13
- extend Forwardable
14
-
15
- attr_reader :file
16
-
17
- # iOS Export types
18
- module ExportType
19
- DEBUG = 'Debug'
20
- ADHOC = 'AdHoc'
21
- ENTERPRISE = 'Enterprise'
22
- RELEASE = 'Release'
23
- UNKOWN = nil
24
-
25
- INHOUSE = 'Enterprise' # Rename and Alias to enterprise
26
- end
27
-
28
- def initialize(file)
29
- @file = file
30
- end
31
-
32
- def size(human_size: false)
33
- file_to_human_size(@file, human_size: human_size)
34
- end
35
-
36
- def os
37
- Platform::IOS
38
- end
39
- alias file_type os
40
-
41
- def_delegators :info, :iphone?, :ipad?, :universal?, :build_version, :name,
42
- :release_version, :identifier, :bundle_id, :display_name,
43
- :bundle_name, :min_sdk_version, :min_os_version, :device_type
44
-
45
- def_delegators :mobileprovision, :devices, :team_name, :team_identifier,
46
- :profile_name, :expired_date
47
-
48
- def distribution_name
49
- "#{profile_name} - #{team_name}" if profile_name && team_name
50
- end
51
-
52
- def release_type
53
- if stored?
54
- ExportType::RELEASE
55
- else
56
- build_type
57
- end
58
- end
59
-
60
- def build_type
61
- if mobileprovision?
62
- if devices
63
- ExportType::ADHOC
64
- else
65
- ExportType::ENTERPRISE
66
- end
67
- else
68
- ExportType::DEBUG
69
- end
70
- end
71
-
72
- def archs
73
- return unless File.exist?(bundle_path)
74
-
75
- file = MachO.open(bundle_path)
76
- case file
77
- when MachO::MachOFile
78
- [file.cpusubtype]
79
- else
80
- file.machos.each_with_object([]) do |arch, obj|
81
- obj << arch.cpusubtype
82
- end
83
- end
84
- end
85
- alias architectures archs
86
-
9
+ class IPA < Apple
10
+ # Full icons metadata
11
+ # @example
12
+ # aab.icons
13
+ # # => [
14
+ # # {
15
+ # # name: 'icon.png',
16
+ # # file: '/path/to/icon.png',
17
+ # # uncrushed_file: '/path/to/uncrushed_icon.png',
18
+ # # dimensions: [64, 64]
19
+ # # },
20
+ # # {
21
+ # # name: 'icon1.png',
22
+ # # file: '/path/to/icon1.png',
23
+ # # uncrushed_file: '/path/to/uncrushed_icon1.png',
24
+ # # dimensions: [120, 120]
25
+ # # }
26
+ # # ]
27
+ # @return [Array<Hash{Symbol => String, Array<Integer>}>] icons paths of icons
87
28
  def icons(uncrush: true)
88
29
  @icons ||= icons_path.each_with_object([]) do |file, obj|
89
30
  obj << build_icon_metadata(file, uncrush: uncrush)
90
31
  end
91
32
  end
92
33
 
34
+ # @return [Boolean]
93
35
  def stored?
94
36
  !!metadata?
95
37
  end
96
38
 
39
+ # @return [Array<Plugin>]
97
40
  def plugins
98
41
  @plugins ||= Plugin.parse(app_path)
99
42
  end
100
43
 
44
+ # @return [Array<Framework>]
101
45
  def frameworks
102
46
  @frameworks ||= Framework.parse(app_path)
103
47
  end
104
48
 
105
- def hide_developer_certificates
106
- mobileprovision.delete('DeveloperCertificates') if mobileprovision?
107
- end
108
-
109
- def mobileprovision
110
- return unless mobileprovision?
111
- return @mobileprovision if @mobileprovision
112
-
113
- @mobileprovision = MobileProvision.new(mobileprovision_path)
114
- end
115
-
116
- def mobileprovision?
117
- File.exist?(mobileprovision_path)
118
- end
119
-
49
+ # @return [String]
120
50
  def mobileprovision_path
121
51
  filename = 'embedded.mobileprovision'
122
- @mobileprovision_path ||= File.join(@file, filename)
123
- unless File.exist?(@mobileprovision_path)
124
- @mobileprovision_path = File.join(app_path, filename)
52
+ @mobileprovision_path ||= ::File.join(@file, filename)
53
+ unless ::File.exist?(@mobileprovision_path)
54
+ @mobileprovision_path = ::File.join(app_path, filename)
125
55
  end
126
56
 
127
57
  @mobileprovision_path
128
58
  end
129
59
 
60
+ # @return [CFPropertyList]
130
61
  def metadata
131
62
  return unless metadata?
132
63
 
133
64
  @metadata ||= CFPropertyList.native_types(CFPropertyList::List.new(file: metadata_path).value)
134
65
  end
135
66
 
67
+ # @return [Boolean]
136
68
  def metadata?
137
- File.exist?(metadata_path)
69
+ ::File.exist?(metadata_path)
138
70
  end
139
71
 
72
+ # @return [String]
140
73
  def metadata_path
141
- @metadata_path ||= File.join(contents, 'iTunesMetadata.plist')
74
+ @metadata_path ||= ::File.join(contents, 'iTunesMetadata.plist')
142
75
  end
143
76
 
144
- def bundle_path
145
- @bundle_path ||= File.join(app_path, info.bundle_name)
146
- end
147
-
148
- def info
149
- @info ||= InfoPlist.new(info_path)
77
+ # @return [String]
78
+ def binary_path
79
+ @binary_path ||= ::File.join(app_path, info.bundle_name)
150
80
  end
151
81
 
82
+ # @return [String]
152
83
  def info_path
153
- @info_path ||= File.join(app_path, 'Info.plist')
84
+ @info_path ||= ::File.join(app_path, 'Info.plist')
154
85
  end
155
86
 
87
+ # @return [String]
156
88
  def app_path
157
- @app_path ||= Dir.glob(File.join(contents, 'Payload', '*.app')).first
89
+ @app_path ||= Dir.glob(::File.join(contents, 'Payload', '*.app')).first
158
90
  end
159
91
 
160
- IPHONE_KEY = 'CFBundleIcons'
161
- IPAD_KEY = 'CFBundleIcons~ipad'
162
-
92
+ # @return [Array<String>]
163
93
  def icons_path
164
- return @icons_path if @icons_path
165
-
166
- @icons_path = []
167
- icon_keys.each do |name|
168
- filenames = info.try(:[], name)
169
- .try(:[], 'CFBundlePrimaryIcon')
170
- .try(:[], 'CFBundleIconFiles')
171
-
172
- next if filenames.nil? || filenames.empty?
173
-
174
- filenames.each do |filename|
175
- Dir.glob(File.join(app_path, "#{filename}*")).find_all.each do |file|
176
- @icons_path << file
94
+ @icons_path ||= lambda {
95
+ icon_keys.each_with_object([]) do |name, icons|
96
+ filenames = info.try(:[], name)
97
+ .try(:[], 'CFBundlePrimaryIcon')
98
+ .try(:[], 'CFBundleIconFiles')
99
+
100
+ next if filenames.nil? || filenames.empty?
101
+
102
+ filenames.each do |filename|
103
+ Dir.glob(::File.join(app_path, "#{filename}*")).find_all.each do |file|
104
+ icons << file
105
+ end
177
106
  end
178
107
  end
179
- end
180
-
181
- @icons_path
108
+ }.call
182
109
  end
183
110
 
184
111
  def clear!
@@ -196,17 +123,13 @@ module AppInfo
196
123
  @icons = nil
197
124
  end
198
125
 
199
- def contents
200
- @contents ||= unarchive(@file, path: 'ios')
201
- end
202
-
203
126
  private
204
127
 
205
128
  def build_icon_metadata(file, uncrush: true)
206
129
  uncrushed_file = uncrush ? uncrush_png(file) : nil
207
130
 
208
131
  {
209
- name: File.basename(file),
132
+ name: ::File.basename(file),
210
133
  file: file,
211
134
  uncrushed_file: uncrushed_file,
212
135
  dimensions: PngUncrush.dimensions(file)
@@ -217,16 +140,19 @@ module AppInfo
217
140
  def uncrush_png(src_file)
218
141
  dest_file = tempdir(src_file, prefix: 'uncrushed')
219
142
  PngUncrush.decompress(src_file, dest_file)
220
- File.exist?(dest_file) ? dest_file : nil
143
+ ::File.exist?(dest_file) ? dest_file : nil
221
144
  end
222
145
 
146
+ IPHONE_KEY = 'CFBundleIcons'
147
+ IPAD_KEY = 'CFBundleIcons~ipad'
148
+
223
149
  def icon_keys
224
- @icon_keys ||= case device_type
225
- when 'iPhone'
150
+ @icon_keys ||= case device
151
+ when Device::IPHONE
226
152
  [IPHONE_KEY]
227
- when 'iPad'
153
+ when Device::IPAD
228
154
  [IPAD_KEY]
229
- when 'Universal'
155
+ when Device::UNIVERSAL
230
156
  [IPHONE_KEY, IPAD_KEY]
231
157
  end
232
158
  end
@@ -7,63 +7,42 @@ require 'cfpropertylist'
7
7
 
8
8
  module AppInfo
9
9
  # MacOS App parser
10
- class Macos
11
- include Helper::HumanFileSize
12
- include Helper::Archive
13
- extend Forwardable
14
-
15
- attr_reader :file
16
-
17
- # macOS Export types
18
- module ExportType
19
- DEBUG = 'Debug'
20
- RELEASE = 'Release'
21
- APPSTORE = 'AppStore'
22
- end
23
-
24
- def initialize(file)
25
- @file = file
26
- end
27
-
28
- def size(human_size: false)
29
- file_to_human_size(@file, human_size: human_size)
30
- end
31
-
32
- def os
33
- Platform::MACOS
34
- end
35
- alias file_type os
36
-
37
- def_delegators :info, :macos?, :iphone?, :ipad?, :universal?, :build_version, :name,
38
- :release_version, :identifier, :bundle_id, :display_name,
39
- :bundle_name, :min_system_version, :min_os_version, :device_type
40
-
41
- def_delegators :mobileprovision, :team_name, :team_identifier,
42
- :profile_name, :expired_date
43
-
44
- def distribution_name
45
- "#{profile_name} - #{team_name}" if profile_name && team_name
46
- end
47
-
48
- def release_type
49
- if stored?
50
- ExportType::APPSTORE
51
- elsif mobileprovision?
52
- ExportType::RELEASE
53
- else
54
- ExportType::DEBUG
55
- end
56
- end
57
-
58
- def stored?
59
- File.exist?(store_path)
60
- end
61
-
10
+ class Macos < Apple
11
+ # @!method min_sdk_version
12
+ # @see InfoPlist#min_sdk_version
13
+ def_delegators :info, :min_system_version
14
+
15
+ # Full icons metadata
16
+ # @param [Boolean] convert Convert .icons to .png format
17
+ # @example uncovert .icons
18
+ # macos.icons
19
+ # # => [
20
+ # # {
21
+ # # name: 'icon.icns',
22
+ # # file: '/path/to/icon.icns',
23
+ # # }
24
+ # # ]
25
+ #
26
+ # @example coverted .icons
27
+ # macos.icons(convert: true)
28
+ # # => [
29
+ # # {
30
+ # # name: 'converted_icon_32x32.png',
31
+ # # file: '/path/to/converted_icon_32x32.png',
32
+ # # dimensions: [32, 32]
33
+ # # },
34
+ # # {
35
+ # # name: 'converted_icon_120x120.png',
36
+ # # file: '/path/to/converted_icon_120x120.png',
37
+ # # dimensions: [120, 120]
38
+ # # },
39
+ # # ]
40
+ # @return [Array<Hash{Symbol => String, Array<Integer>}>] icons paths of icons
62
41
  def icons(convert: true)
63
42
  return unless icon_file
64
43
 
65
44
  data = {
66
- name: File.basename(icon_file),
45
+ name: ::File.basename(icon_file),
67
46
  file: icon_file
68
47
  }
69
48
 
@@ -71,63 +50,40 @@ module AppInfo
71
50
  data
72
51
  end
73
52
 
74
- def archs
75
- return unless File.exist?(binary_path)
76
-
77
- file = MachO.open(binary_path)
78
- case file
79
- when MachO::MachOFile
80
- [file.cpusubtype]
81
- else
82
- file.machos.each_with_object([]) do |arch, obj|
83
- obj << arch.cpusubtype
84
- end
85
- end
86
- end
87
- alias architectures archs
88
-
89
- def hide_developer_certificates
90
- mobileprovision.delete('DeveloperCertificates') if mobileprovision?
91
- end
92
-
93
- def mobileprovision
94
- return unless mobileprovision?
95
-
96
- @mobileprovision ||= MobileProvision.new(mobileprovision_path)
97
- end
98
-
99
- def mobileprovision?
100
- File.exist?(mobileprovision_path)
53
+ # @return [Boolean]
54
+ def stored?
55
+ ::File.exist?(store_path)
101
56
  end
102
57
 
58
+ # @return [String]
103
59
  def mobileprovision_path
104
- @mobileprovision_path ||= File.join(app_path, 'Contents', 'embedded.provisionprofile')
60
+ @mobileprovision_path ||= ::File.join(app_path, 'Contents', 'embedded.provisionprofile')
105
61
  end
106
62
 
63
+ # @return [String]
107
64
  def store_path
108
- @store_path ||= File.join(app_path, 'Contents', '_MASReceipt', 'receipt')
65
+ @store_path ||= ::File.join(app_path, 'Contents', '_MASReceipt', 'receipt')
109
66
  end
110
67
 
68
+ # @return [String]
111
69
  def binary_path
112
70
  return @binary_path if @binary_path
113
71
 
114
- base_path = File.join(app_path, 'Contents', 'MacOS')
72
+ base_path = ::File.join(app_path, 'Contents', 'MacOS')
115
73
  binary = info['CFBundleExecutable']
116
- return File.join(base_path, binary) if binary
74
+ return ::File.join(base_path, binary) if binary
117
75
 
118
- @binary_path ||= Dir.glob(File.join(base_path, '*')).first
119
- end
120
-
121
- def info
122
- @info ||= InfoPlist.new(info_path)
76
+ @binary_path ||= Dir.glob(::File.join(base_path, '*')).first
123
77
  end
124
78
 
79
+ # @return [String]
125
80
  def info_path
126
- @info_path ||= File.join(app_path, 'Contents', 'Info.plist')
81
+ @info_path ||= ::File.join(app_path, 'Contents', 'Info.plist')
127
82
  end
128
83
 
84
+ # @return [String]
129
85
  def app_path
130
- @app_path ||= Dir.glob(File.join(contents, '*.app')).first
86
+ @app_path ||= Dir.glob(::File.join(contents, '*.app')).first
131
87
  end
132
88
 
133
89
  def clear!
@@ -137,16 +93,12 @@ module AppInfo
137
93
 
138
94
  @contents = nil
139
95
  @app_path = nil
140
- @binrary_path = nil
96
+ @binary_path = nil
141
97
  @info_path = nil
142
98
  @info = nil
143
99
  @icons = nil
144
100
  end
145
101
 
146
- def contents
147
- @contents ||= unarchive(@file, path: 'macos')
148
- end
149
-
150
102
  private
151
103
 
152
104
  def icon_file
@@ -155,8 +107,8 @@ module AppInfo
155
107
  info.icons.each do |key|
156
108
  next unless value = info[key]
157
109
 
158
- file = File.join(app_path, 'Contents', 'Resources', "#{value}.icns")
159
- next unless File.file?(file)
110
+ file = ::File.join(app_path, 'Contents', 'Resources', "#{value}.icns")
111
+ next unless ::File.file?(file)
160
112
 
161
113
  return @icon_file = file
162
114
  end
@@ -173,14 +125,14 @@ module AppInfo
173
125
  file = data[:file]
174
126
  reader = Icns::Reader.new(file)
175
127
  Icns::SIZE_TO_TYPE.each do |size, _|
176
- dest_filename = "#{File.basename(file, '.icns')}_#{size}x#{size}.png"
177
- dest_file = tempdir(File.join(File.dirname(file), dest_filename), prefix: 'converted')
128
+ dest_filename = "#{::File.basename(file, '.icns')}_#{size}x#{size}.png"
129
+ dest_file = tempdir(::File.join(::File.dirname(file), dest_filename), prefix: 'converted')
178
130
  next unless icon_data = reader.image(size: size)
179
131
 
180
- File.write(dest_file, icon_data, encoding: Encoding::BINARY)
132
+ ::File.write(dest_file, icon_data, encoding: Encoding::BINARY)
181
133
 
182
134
  data[:sets] << {
183
- name: File.basename(dest_filename),
135
+ name: ::File.basename(dest_filename),
184
136
  file: dest_file,
185
137
  dimensions: ImageSize.path(dest_file).size
186
138
  }