app-info 3.0.0.beta1 → 3.0.0.beta3

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.
data/lib/app_info/ipa.rb CHANGED
@@ -6,125 +6,47 @@ require 'forwardable'
6
6
  require 'cfpropertylist'
7
7
 
8
8
  module AppInfo
9
- # IPA parser
10
- class IPA < File
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
- # return file size
29
- # @example Read file size in integer
30
- # aab.size # => 3618865
31
- #
32
- # @example Read file size in human readabale
33
- # aab.size(human_size: true) # => '3.45 MB'
34
- #
35
- # @param [Boolean] human_size Convert integer value to human readable.
36
- # @return [Integer, String]
37
- def size(human_size: false)
38
- file_to_human_size(@file, human_size: human_size)
39
- end
40
-
41
- def file_type
42
- Format::IPA
43
- end
44
-
45
- def platform
46
- Platform::IOS
47
- end
48
-
49
- def_delegators :info, :iphone?, :ipad?, :universal?, :build_version, :name,
50
- :release_version, :identifier, :bundle_id, :display_name,
51
- :bundle_name, :min_sdk_version, :min_os_version, :device_type
52
-
53
- def_delegators :mobileprovision, :devices, :team_name, :team_identifier,
54
- :profile_name, :expired_date
55
-
56
- def distribution_name
57
- "#{profile_name} - #{team_name}" if profile_name && team_name
58
- end
59
-
60
- def release_type
61
- if stored?
62
- ExportType::RELEASE
63
- else
64
- build_type
65
- end
66
- end
67
-
68
- def build_type
69
- if mobileprovision?
70
- if devices
71
- ExportType::ADHOC
72
- else
73
- ExportType::ENTERPRISE
74
- end
75
- else
76
- ExportType::DEBUG
77
- end
78
- end
79
-
80
- def archs
81
- return unless ::File.exist?(bundle_path)
82
-
83
- file = MachO.open(bundle_path)
84
- case file
85
- when MachO::MachOFile
86
- [file.cpusubtype]
87
- else
88
- file.machos.each_with_object([]) do |arch, obj|
89
- obj << arch.cpusubtype
90
- end
91
- end
92
- end
93
- alias architectures archs
94
-
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
95
28
  def icons(uncrush: true)
96
29
  @icons ||= icons_path.each_with_object([]) do |file, obj|
97
30
  obj << build_icon_metadata(file, uncrush: uncrush)
98
31
  end
99
32
  end
100
33
 
34
+ # @return [Boolean]
101
35
  def stored?
102
36
  !!metadata?
103
37
  end
104
38
 
39
+ # @return [Array<Plugin>]
105
40
  def plugins
106
41
  @plugins ||= Plugin.parse(app_path)
107
42
  end
108
43
 
44
+ # @return [Array<Framework>]
109
45
  def frameworks
110
46
  @frameworks ||= Framework.parse(app_path)
111
47
  end
112
48
 
113
- def hide_developer_certificates
114
- mobileprovision.delete('DeveloperCertificates') if mobileprovision?
115
- end
116
-
117
- def mobileprovision
118
- return unless mobileprovision?
119
- return @mobileprovision if @mobileprovision
120
-
121
- @mobileprovision = MobileProvision.new(mobileprovision_path)
122
- end
123
-
124
- def mobileprovision?
125
- ::File.exist?(mobileprovision_path)
126
- end
127
-
49
+ # @return [String]
128
50
  def mobileprovision_path
129
51
  filename = 'embedded.mobileprovision'
130
52
  @mobileprovision_path ||= ::File.join(@file, filename)
@@ -135,39 +57,39 @@ module AppInfo
135
57
  @mobileprovision_path
136
58
  end
137
59
 
60
+ # @return [CFPropertyList]
138
61
  def metadata
139
62
  return unless metadata?
140
63
 
141
64
  @metadata ||= CFPropertyList.native_types(CFPropertyList::List.new(file: metadata_path).value)
142
65
  end
143
66
 
67
+ # @return [Boolean]
144
68
  def metadata?
145
69
  ::File.exist?(metadata_path)
146
70
  end
147
71
 
72
+ # @return [String]
148
73
  def metadata_path
149
74
  @metadata_path ||= ::File.join(contents, 'iTunesMetadata.plist')
150
75
  end
151
76
 
152
- def bundle_path
153
- @bundle_path ||= ::File.join(app_path, info.bundle_name)
154
- end
155
-
156
- def info
157
- @info ||= InfoPlist.new(info_path)
77
+ # @return [String]
78
+ def binary_path
79
+ @binary_path ||= ::File.join(app_path, info.bundle_name)
158
80
  end
159
81
 
82
+ # @return [String]
160
83
  def info_path
161
84
  @info_path ||= ::File.join(app_path, 'Info.plist')
162
85
  end
163
86
 
87
+ # @return [String]
164
88
  def app_path
165
89
  @app_path ||= Dir.glob(::File.join(contents, 'Payload', '*.app')).first
166
90
  end
167
91
 
168
- IPHONE_KEY = 'CFBundleIcons'
169
- IPAD_KEY = 'CFBundleIcons~ipad'
170
-
92
+ # @return [Array<String>]
171
93
  def icons_path
172
94
  @icons_path ||= lambda {
173
95
  icon_keys.each_with_object([]) do |name, icons|
@@ -201,10 +123,6 @@ module AppInfo
201
123
  @icons = nil
202
124
  end
203
125
 
204
- def contents
205
- @contents ||= unarchive(@file, prefix: 'ios')
206
- end
207
-
208
126
  private
209
127
 
210
128
  def build_icon_metadata(file, uncrush: true)
@@ -225,13 +143,16 @@ module AppInfo
225
143
  ::File.exist?(dest_file) ? dest_file : nil
226
144
  end
227
145
 
146
+ IPHONE_KEY = 'CFBundleIcons'
147
+ IPAD_KEY = 'CFBundleIcons~ipad'
148
+
228
149
  def icon_keys
229
- @icon_keys ||= case device_type
230
- when 'iPhone'
150
+ @icon_keys ||= case device
151
+ when Device::IPHONE
231
152
  [IPHONE_KEY]
232
- when 'iPad'
153
+ when Device::IPAD
233
154
  [IPAD_KEY]
234
- when 'Universal'
155
+ when Device::UNIVERSAL
235
156
  [IPHONE_KEY, IPAD_KEY]
236
157
  end
237
158
  end
@@ -7,66 +7,37 @@ require 'cfpropertylist'
7
7
 
8
8
  module AppInfo
9
9
  # MacOS App parser
10
- class Macos < File
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
- # return file size
25
- # @example Read file size in integer
26
- # aab.size # => 3618865
27
- #
28
- # @example Read file size in human readabale
29
- # aab.size(human_size: true) # => '3.45 MB'
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
+ # # ]
30
25
  #
31
- # @param [Boolean] human_size Convert integer value to human readable.
32
- # @return [Integer, String]
33
- def size(human_size: false)
34
- file_to_human_size(@file, human_size: human_size)
35
- end
36
-
37
- def file_type
38
- Format::MACOS
39
- end
40
-
41
- def platform
42
- Platform::MACOS
43
- end
44
-
45
- def_delegators :info, :macos?, :iphone?, :ipad?, :universal?, :build_version, :name,
46
- :release_version, :identifier, :bundle_id, :display_name,
47
- :bundle_name, :min_system_version, :min_os_version, :device_type
48
-
49
- def_delegators :mobileprovision, :team_name, :team_identifier,
50
- :profile_name, :expired_date
51
-
52
- def distribution_name
53
- "#{profile_name} - #{team_name}" if profile_name && team_name
54
- end
55
-
56
- def release_type
57
- if stored?
58
- ExportType::APPSTORE
59
- elsif mobileprovision?
60
- ExportType::RELEASE
61
- else
62
- ExportType::DEBUG
63
- end
64
- end
65
-
66
- def stored?
67
- ::File.exist?(store_path)
68
- end
69
-
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
70
41
  def icons(convert: true)
71
42
  return unless icon_file
72
43
 
@@ -79,43 +50,22 @@ module AppInfo
79
50
  data
80
51
  end
81
52
 
82
- def archs
83
- return unless ::File.exist?(binary_path)
84
-
85
- file = MachO.open(binary_path)
86
- case file
87
- when MachO::MachOFile
88
- [file.cpusubtype]
89
- else
90
- file.machos.each_with_object([]) do |arch, obj|
91
- obj << arch.cpusubtype
92
- end
93
- end
94
- end
95
- alias architectures archs
96
-
97
- def hide_developer_certificates
98
- mobileprovision.delete('DeveloperCertificates') if mobileprovision?
99
- end
100
-
101
- def mobileprovision
102
- return unless mobileprovision?
103
-
104
- @mobileprovision ||= MobileProvision.new(mobileprovision_path)
105
- end
106
-
107
- def mobileprovision?
108
- ::File.exist?(mobileprovision_path)
53
+ # @return [Boolean]
54
+ def stored?
55
+ ::File.exist?(store_path)
109
56
  end
110
57
 
58
+ # @return [String]
111
59
  def mobileprovision_path
112
60
  @mobileprovision_path ||= ::File.join(app_path, 'Contents', 'embedded.provisionprofile')
113
61
  end
114
62
 
63
+ # @return [String]
115
64
  def store_path
116
65
  @store_path ||= ::File.join(app_path, 'Contents', '_MASReceipt', 'receipt')
117
66
  end
118
67
 
68
+ # @return [String]
119
69
  def binary_path
120
70
  return @binary_path if @binary_path
121
71
 
@@ -126,14 +76,12 @@ module AppInfo
126
76
  @binary_path ||= Dir.glob(::File.join(base_path, '*')).first
127
77
  end
128
78
 
129
- def info
130
- @info ||= InfoPlist.new(info_path)
131
- end
132
-
79
+ # @return [String]
133
80
  def info_path
134
81
  @info_path ||= ::File.join(app_path, 'Contents', 'Info.plist')
135
82
  end
136
83
 
84
+ # @return [String]
137
85
  def app_path
138
86
  @app_path ||= Dir.glob(::File.join(contents, '*.app')).first
139
87
  end
@@ -151,10 +99,6 @@ module AppInfo
151
99
  @icons = nil
152
100
  end
153
101
 
154
- def contents
155
- @contents ||= unarchive(@file, prefix: 'macos')
156
- end
157
-
158
102
  private
159
103
 
160
104
  def icon_file
@@ -4,20 +4,37 @@ require 'openssl'
4
4
  require 'cfpropertylist'
5
5
 
6
6
  module AppInfo
7
- # .mobileprovision file parser
7
+ # Apple code signing: provisioning profile parser
8
+ # @see https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles
8
9
  class MobileProvision < File
9
- def file_type
10
- Format::MOBILEPROVISION
10
+ # @return [Symbol] {Manufacturer}
11
+ def manufacturer
12
+ Manufacturer::APPLE
11
13
  end
12
14
 
15
+ # @return [Symbol] {Platform}
16
+ def platform
17
+ case platforms[0]
18
+ when :macos
19
+ Platform::MACOS
20
+ when :ios
21
+ Platform::IOS
22
+ else
23
+ raise NotImplementedError, "Unkonwn platform: #{platforms[0]}"
24
+ end
25
+ end
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,6 +42,7 @@ module AppInfo
25
42
  return :enterprise if enterprise?
26
43
  end
27
44
 
45
+ # @return [Array<Symbol>]
28
46
  def platforms
29
47
  return unless platforms = mobileprovision.try(:[], 'Platform')
30
48
 
@@ -34,34 +52,37 @@ 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
@@ -87,40 +108,44 @@ module AppInfo
87
108
 
88
109
  # Detect is development type of mobileprovision
89
110
  #
90
- # 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]
91
113
  def development?
92
- case platform.downcase.to_sym
93
- when :ios
114
+ case platform
115
+ when Platform::IOS
94
116
  entitlements['get-task-allow'] == true
95
- when :macos
117
+ when Platform::MACOS
96
118
  !devices.nil?
97
119
  else
98
- raise Error, "Not implement with platform: #{platform}"
120
+ raise NotImplementedError, "Unknown platform: #{platform}"
99
121
  end
100
122
  end
101
123
 
102
124
  # Detect app store type
103
125
  #
104
- # 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]
105
128
  def appstore?
106
- case platform.downcase.to_sym
107
- when :ios
129
+ case platform
130
+ when Platform::IOS
108
131
  !development? && entitlements.key?('beta-reports-active')
109
- when :macos
132
+ when Platform::MACOS
110
133
  !development?
111
134
  else
112
- raise Error, "Not implement with platform: #{platform}"
135
+ raise NotImplementedError, "Unknown platform: #{platform}"
113
136
  end
114
137
  end
115
138
 
139
+ # @return [Boolea]
116
140
  def adhoc?
117
- return false if platform == :macos # macOS no need adhoc
141
+ return false if platform == Platform::MACOS # macOS no need adhoc
118
142
 
119
143
  !development? && !devices.nil?
120
144
  end
121
145
 
146
+ # @return [Boolea]
122
147
  def enterprise?
123
- return false if platform == :macos # macOS no need adhoc
148
+ return false if platform == Platform::MACOS # macOS no need adhoc
124
149
 
125
150
  !development? && !adhoc? && !appstore?
126
151
  end
@@ -128,7 +153,8 @@ module AppInfo
128
153
 
129
154
  # Enabled Capabilites
130
155
  #
131
- # Related link: https://developer.apple.com/support/app-capabilities/
156
+ # @see https://developer.apple.com/support/app-capabilities/
157
+ # @return [Array<String>]
132
158
  def enabled_capabilities
133
159
  capabilities = []
134
160
  capabilities << 'In-App Purchase' << 'GameKit' if adhoc? || appstore?
@@ -202,14 +228,17 @@ module AppInfo
202
228
  capabilities
203
229
  end
204
230
 
231
+ # @return [String, nil]
205
232
  def [](key)
206
233
  mobileprovision.try(:[], key.to_s)
207
234
  end
208
235
 
236
+ # @return [Boolea]
209
237
  def empty?
210
238
  mobileprovision.nil?
211
239
  end
212
240
 
241
+ # @return [CFPropertyList]
213
242
  def mobileprovision
214
243
  return @mobileprovision = nil unless ::File.exist?(@file)
215
244