app-info 2.0.0.beta3 → 2.0.0.beta4

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.
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppInfo
4
+ # AppInfo Util
5
+ module Util
6
+ FILE_SIZE_UNITS = %w[B KB MB GB TB].freeze
7
+
8
+ def self.file_size(file, humanable)
9
+ file_size = File.size(file)
10
+ humanable ? size_to_humanable(file_size) : file_size
11
+ end
12
+
13
+ def self.size_to_humanable(number)
14
+ if number.to_i < 1024
15
+ exponent = 0
16
+ else
17
+ max_exp = FILE_SIZE_UNITS.size - 1
18
+ exponent = (Math.log(number) / Math.log(1024)).to_i
19
+ exponent = max_exp if exponent > max_exp
20
+ number = format('%<number>.2f', number: (number / (1024**exponent.to_f)))
21
+ end
22
+
23
+ "#{number} #{FILE_SIZE_UNITS[exponent]}"
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppInfo
4
- VERSION = '2.0.0.beta3'
4
+ VERSION = '2.0.0.beta4'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app-info
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta3
4
+ version: 2.0.0.beta4
5
5
  platform: ruby
6
6
  authors:
7
7
  - icyleaf
@@ -174,13 +174,13 @@ files:
174
174
  - app_info.gemspec
175
175
  - lib/app-info.rb
176
176
  - lib/app_info.rb
177
+ - lib/app_info/apk.rb
177
178
  - lib/app_info/core_ext/object/try.rb
178
- - lib/app_info/parser.rb
179
- - lib/app_info/parser/apk.rb
180
- - lib/app_info/parser/dsym.rb
181
- - lib/app_info/parser/ipa.rb
182
- - lib/app_info/parser/ipa/info_plist.rb
183
- - lib/app_info/parser/ipa/mobile_provision.rb
179
+ - lib/app_info/dsym.rb
180
+ - lib/app_info/ipa.rb
181
+ - lib/app_info/ipa/info_plist.rb
182
+ - lib/app_info/ipa/mobile_provision.rb
183
+ - lib/app_info/util.rb
184
184
  - lib/app_info/version.rb
185
185
  homepage: http://github.com/icyleaf/app-info
186
186
  licenses:
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'app_info/parser/ipa'
4
- require 'app_info/parser/ipa/info_plist'
5
- require 'app_info/parser/ipa/mobile_provision'
6
- require 'app_info/parser/apk'
7
- require 'app_info/parser/dsym'
8
-
9
- module AppInfo
10
- module Parser
11
- # App Platform
12
- module Platform
13
- IOS = 'iOS'
14
- ANDROID = 'Android'
15
- DSYM = 'dSYM'
16
- end
17
-
18
- module Util
19
- FILE_SIZE_UNITS = %w[B KB MB GB TB].freeze
20
-
21
- def self.file_size(file, humanable)
22
- file_size = File.size(file)
23
- humanable ? size_to_humanable(file_size) : file_size
24
- end
25
-
26
- def self.size_to_humanable(number)
27
- if number.to_i < 1024
28
- exponent = 0
29
- else
30
- max_exp = FILE_SIZE_UNITS.size - 1
31
- exponent = (Math.log(number) / Math.log(1024)).to_i
32
- exponent = max_exp if exponent > max_exp
33
- number = format('%.2f', (number / (1024**exponent.to_f)))
34
- end
35
-
36
- "#{number} #{FILE_SIZE_UNITS[exponent]}"
37
- end
38
- end
39
- end
40
- end
@@ -1,183 +0,0 @@
1
- require 'ruby_apk'
2
- require 'image_size'
3
-
4
- module AppInfo
5
- module Parser
6
- # Parse APK file
7
- class APK
8
- attr_reader :file, :apk
9
-
10
- # APK Devices
11
- module Device
12
- PHONE = 'Phone'.freeze
13
- TABLET = 'Tablet'.freeze
14
- WATCH = 'Watch'.freeze
15
- TV = 'Television'.freeze
16
- end
17
-
18
- def initialize(file)
19
- @file = file
20
-
21
- Zip.warn_invalid_date = false # fix invaild date format warnings
22
- @apk = ::Android::Apk.new(file)
23
- end
24
-
25
- def size(humanable = false)
26
- AppInfo::Parser::Util.file_size(@file, humanable)
27
- end
28
-
29
- def os
30
- Parser::Platform::ANDROID
31
- end
32
- alias file_type os
33
-
34
- def build_version
35
- manifest.version_code.to_s
36
- end
37
-
38
- def release_version
39
- manifest.version_name
40
- end
41
-
42
- def name
43
- resource.find('@string/app_name')
44
- end
45
-
46
- def bundle_id
47
- manifest.package_name
48
- end
49
- alias identifier bundle_id
50
- alias package_name bundle_id
51
-
52
- def device_type
53
- if wear?
54
- Device::WATCH
55
- elsif tv?
56
- Device::TV
57
- else
58
- Device::PHONE
59
- end
60
- end
61
-
62
- # TODO: find a way to detect
63
- # def tablet?
64
- # resource
65
- # end
66
-
67
- def wear?
68
- use_features.include?('android.hardware.type.watch')
69
- end
70
-
71
- def tv?
72
- use_features.include?('android.software.leanback')
73
- end
74
-
75
- def min_sdk_version
76
- manifest.min_sdk_ver
77
- end
78
-
79
- def target_sdk_version
80
- manifest.doc
81
- .elements['/manifest/uses-sdk']
82
- .attributes['targetSdkVersion']
83
- .to_i
84
- end
85
-
86
- def use_permissions
87
- manifest.use_permissions
88
- end
89
-
90
- def use_features
91
- manifest_values('/manifest/uses-feature')
92
- end
93
-
94
- def signs
95
- @apk.signs.each_with_object([]) do |(path, sign), obj|
96
- obj << Sign.new(path, sign)
97
- end
98
- end
99
-
100
- def certificates
101
- @apk.certificates.each_with_object([]) do |(path, certificate), obj|
102
- obj << Certificate.new(path, certificate)
103
- end
104
- end
105
-
106
- def activities
107
- components.select { |c| c.type == 'activity' }
108
- end
109
-
110
- def services
111
- components.select { |c| c.type == 'service' }
112
- end
113
-
114
- def components
115
- manifest.components
116
- end
117
-
118
- def manifest
119
- @apk.manifest
120
- end
121
-
122
- def resource
123
- @apk.resource
124
- end
125
-
126
- def dex
127
- @apk.dex
128
- end
129
-
130
- def icons
131
- unless @icons
132
- tmp_path = File.join(Dir.mktmpdir, "AppInfo-android-#{SecureRandom.hex}")
133
-
134
- @icons = @apk.icon.each_with_object([]) do |(path, data), obj|
135
- icon_name = File.basename(path)
136
- icon_path = File.join(tmp_path, File.path(path))
137
- icon_file = File.join(icon_path, icon_name)
138
- FileUtils.mkdir_p icon_path
139
- File.open(icon_file, 'w') do |f|
140
- f.write data
141
- end
142
-
143
- obj << {
144
- name: icon_name,
145
- file: icon_file,
146
- dimensions: ImageSize.path(icon_file).size
147
- }
148
- end
149
- end
150
-
151
- @icons
152
- end
153
-
154
- private
155
-
156
- def manifest_values(path, key = 'name')
157
- values = []
158
- manifest.doc.each_element(path) do |elem|
159
- values << elem.attributes[key]
160
- end
161
- values.uniq
162
- end
163
-
164
- # Android Certificate
165
- class Certificate
166
- attr_reader :path, :certificate
167
- def initialize(path, certificate)
168
- @path = path
169
- @certificate = certificate
170
- end
171
- end
172
-
173
- # Android Sign
174
- class Sign
175
- attr_reader :path, :sign
176
- def initialize(path, sign)
177
- @path = path
178
- @sign = sign
179
- end
180
- end
181
- end
182
- end
183
- end
@@ -1,126 +0,0 @@
1
- require 'zip'
2
- require 'macho'
3
- require 'app_info/core_ext/object/try'
4
-
5
- module AppInfo
6
- module Parser
7
- # DSYM parser
8
- class DSYM
9
- attr_reader :file
10
-
11
- def initialize(file)
12
- @file = file
13
- end
14
-
15
- def file_type
16
- Parser::Platform::DSYM
17
- end
18
-
19
- def machos
20
- @machos ||= case macho_type
21
- when ::MachO::MachOFile
22
- [MachO.new(macho_type, File.size(app_path))]
23
- else
24
- size = macho_type.fat_archs.each_with_object([]) do |arch, obj|
25
- obj << arch.size
26
- end
27
-
28
- machos = []
29
- macho_type.machos.each_with_index do |file, i|
30
- machos << MachO.new(file, size[i])
31
- end
32
- machos
33
- end
34
- end
35
-
36
- def macho_type
37
- @macho_type ||= ::MachO.open(app_path)
38
- end
39
-
40
- def object
41
- @object ||= File.basename(app_path)
42
- end
43
-
44
- def app_path
45
- unless @app_path
46
- path = File.join(contents, 'Contents', 'Resources', 'DWARF')
47
- name = Dir.entries(path).last
48
- @app_path = File.join(path, name)
49
- end
50
-
51
- @app_path
52
- end
53
-
54
- private
55
-
56
- def contents
57
- unless @contents
58
- if File.directory?(@file)
59
- @contents = @file
60
- else
61
- @contents = "#{Dir.mktmpdir}/AppInfo-dsym-#{SecureRandom.hex}"
62
- dsym_dir = nil
63
- Zip::File.open(@file) do |zip_file|
64
- zip_file.each do |f|
65
- dsym_dir ||= f.name
66
-
67
- f_path = File.join(@contents, f.name)
68
- zip_file.extract(f, f_path) unless File.exist?(f_path)
69
- end
70
- end
71
-
72
- @contents = File.join(@contents, dsym_dir)
73
- end
74
- end
75
-
76
- @contents
77
- end
78
-
79
- # DSYM Mach-O
80
- class MachO
81
- def initialize(file, size = 0)
82
- @file = file
83
- @size = size
84
- end
85
-
86
- def cpu_name
87
- @file.cpusubtype
88
- end
89
-
90
- def cpu_type
91
- @file.cputype
92
- end
93
-
94
- def type
95
- @file.filetype
96
- end
97
-
98
- def size(humanable = false)
99
- return Util.size_to_humanable(@size) if humanable
100
-
101
- @size
102
- end
103
-
104
- def uuid
105
- @file[:LC_UUID][0].uuid_string
106
- end
107
- alias debug_id uuid
108
-
109
- def header
110
- @header ||= @file.header
111
- end
112
-
113
- def to_h
114
- {
115
- uuid: uuid,
116
- type: type,
117
- cpu_name: cpu_name,
118
- cpu_type: cpu_type,
119
- size: size,
120
- humanable_size: size(true)
121
- }
122
- end
123
- end
124
- end
125
- end
126
- end
@@ -1,229 +0,0 @@
1
- require 'zip'
2
- require 'pngdefry'
3
- require 'fileutils'
4
- require 'securerandom'
5
- require 'cfpropertylist'
6
- require 'app_info/core_ext/object/try'
7
-
8
- module AppInfo
9
- module Parser
10
- # IPA parser
11
- class IPA
12
- attr_reader :file
13
-
14
- # iOS Export types
15
- module ExportType
16
- DEBUG = 'Debug'.freeze
17
- ADHOC = 'AdHoc'.freeze
18
- INHOUSE = 'inHouse'.freeze
19
- RELEASE = 'Release'.freeze
20
- UNKOWN = nil
21
- end
22
-
23
- def initialize(file)
24
- @file = file
25
- end
26
-
27
- def size(humanable = false)
28
- AppInfo::Parser::Util.file_size(@file, humanable)
29
- end
30
-
31
- def os
32
- Parser::Platform::IOS
33
- end
34
- alias file_type os
35
-
36
- def iphone?
37
- info.iphone?
38
- end
39
-
40
- def ipad?
41
- info.ipad?
42
- end
43
-
44
- def universal?
45
- info.universal?
46
- end
47
-
48
- def build_version
49
- info.build_version
50
- end
51
-
52
- def release_version
53
- info.release_version
54
- end
55
-
56
- def identifier
57
- info.identifier
58
- end
59
-
60
- def name
61
- display_name || bundle_name
62
- end
63
-
64
- def display_name
65
- info.display_name
66
- end
67
-
68
- def bundle_name
69
- info.bundle_name
70
- end
71
-
72
- def icons
73
- info.icons
74
- end
75
-
76
- #
77
- # Return the minimum OS version for the given application
78
- #
79
- def min_sdk_version
80
- info.min_sdk_version
81
- end
82
-
83
- def device_type
84
- info.device_type
85
- end
86
-
87
- def devices
88
- mobileprovision.devices
89
- end
90
-
91
- def team_name
92
- mobileprovision.team_name
93
- end
94
-
95
- def team_identifier
96
- mobileprovision.team_identifier
97
- end
98
-
99
- def profile_name
100
- mobileprovision.profile_name
101
- end
102
-
103
- def expired_date
104
- mobileprovision.expired_date
105
- end
106
-
107
- def distribution_name
108
- "#{profile_name} - #{team_name}" if profile_name && team_name
109
- end
110
-
111
- def release_type
112
- if stored?
113
- ExportType::RELEASE
114
- else
115
- build_type
116
- end
117
- end
118
-
119
- def build_type
120
- if mobileprovision?
121
- if devices
122
- ExportType::ADHOC
123
- else
124
- ExportType::INHOUSE
125
- end
126
- else
127
- ExportType::DEBUG
128
- end
129
- end
130
-
131
- def stored?
132
- metadata? ? true : false
133
- end
134
-
135
- def hide_developer_certificates
136
- mobileprovision.delete('DeveloperCertificates') if mobileprovision?
137
- end
138
-
139
- def mobileprovision
140
- return unless mobileprovision?
141
- return @mobileprovision if @mobileprovision
142
-
143
- @mobileprovision = MobileProvision.new(mobileprovision_path)
144
- end
145
-
146
- def mobileprovision?
147
- File.exist?mobileprovision_path
148
- end
149
-
150
- def mobileprovision_path
151
- filename = 'embedded.mobileprovision'
152
- @mobileprovision_path ||= File.join(@file, filename)
153
- unless File.exist?(@mobileprovision_path)
154
- @mobileprovision_path = File.join(app_path, filename)
155
- end
156
-
157
- @mobileprovision_path
158
- end
159
-
160
- def metadata
161
- return unless metadata?
162
-
163
- @metadata ||= CFPropertyList.native_types(CFPropertyList::List.new(file: metadata_path).value)
164
- end
165
-
166
- def metadata?
167
- File.exist?(metadata_path)
168
- end
169
-
170
- def metadata_path
171
- @metadata_path ||= File.join(contents, 'iTunesMetadata.plist')
172
- end
173
-
174
- def info
175
- @info ||= InfoPlist.new(app_path)
176
- end
177
-
178
- def app_path
179
- @app_path ||= Dir.glob(File.join(contents, 'Payload', '*.app')).first
180
- end
181
-
182
- def cleanup!
183
- return unless @contents
184
-
185
- FileUtils.rm_rf(@contents)
186
-
187
- @contents = nil
188
- @icons = nil
189
- @app_path = nil
190
- @metadata = nil
191
- @metadata_path = nil
192
- @info = nil
193
- end
194
-
195
- alias bundle_id identifier
196
-
197
- private
198
-
199
- def contents
200
- # source: https://github.com/soffes/lagunitas/blob/master/lib/lagunitas/ipa.rb
201
- unless @contents
202
- @contents = "#{Dir.mktmpdir}/AppInfo-ios-#{SecureRandom.hex}"
203
- Zip::File.open(@file) do |zip_file|
204
- zip_file.each do |f|
205
- f_path = File.join(@contents, f.name)
206
- zip_file.extract(f, f_path) unless File.exist?(f_path)
207
- end
208
- end
209
- end
210
-
211
- @contents
212
- end
213
-
214
- def icons_root_path
215
- iphone = 'CFBundleIcons'.freeze
216
- ipad = 'CFBundleIcons~ipad'.freeze
217
-
218
- case device_type
219
- when 'iPhone'
220
- [iphone]
221
- when 'iPad'
222
- [ipad]
223
- when 'Universal'
224
- [iphone, ipad]
225
- end
226
- end
227
- end
228
- end
229
- end