app-info 2.5.4 → 2.6.3
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.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +9 -0
- data/.github/workflows/ci.yml +41 -0
- data/.rubocop.yml +26 -7
- data/CHANGELOG.md +43 -1
- data/Gemfile +5 -3
- data/README.md +110 -50
- data/app_info.gemspec +4 -1
- data/exe/app-info +12 -0
- data/lib/app_info/apk.rb +17 -21
- data/lib/app_info/core_ext/object/try.rb +77 -79
- data/lib/app_info/dsym.rb +3 -4
- data/lib/app_info/info_plist.rb +143 -0
- data/lib/app_info/ipa/framework.rb +3 -3
- data/lib/app_info/ipa.rb +72 -22
- data/lib/app_info/macos.rb +188 -0
- data/lib/app_info/{ipa/mobile_provision.rb → mobile_provision.rb} +9 -10
- data/lib/app_info/png_uncrush.rb +30 -31
- data/lib/app_info/proguard.rb +0 -1
- data/lib/app_info/shell.rb +34 -0
- data/lib/app_info/util.rb +46 -6
- data/lib/app_info/version.rb +1 -1
- data/lib/app_info.rb +21 -25
- metadata +41 -8
- data/.travis.yml +0 -9
- data/lib/app_info/ipa/info_plist.rb +0 -162
data/lib/app_info/proguard.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'irb'
|
4
|
+
|
5
|
+
module AppInfo
|
6
|
+
class Shell
|
7
|
+
PREFIX = "app-info (#{AppInfo::VERSION})"
|
8
|
+
|
9
|
+
PROMPT = {
|
10
|
+
PROMPT_I: "#{PREFIX}> ",
|
11
|
+
PROMPT_S: "#{PREFIX}> ",
|
12
|
+
PROMPT_C: "#{PREFIX}> ",
|
13
|
+
PROMPT_N: "#{PREFIX}> ",
|
14
|
+
RETURN: "=> %s\n"
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def run
|
19
|
+
setup
|
20
|
+
|
21
|
+
irb = IRB::Irb.new
|
22
|
+
irb.run
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup
|
26
|
+
IRB.setup nil
|
27
|
+
|
28
|
+
IRB.conf[:PROMPT][:APPINFO] = PROMPT
|
29
|
+
IRB.conf[:PROMPT_MODE] = :APPINFO
|
30
|
+
IRB.conf[:AUTO_INDENT] = true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/app_info/util.rb
CHANGED
@@ -5,23 +5,54 @@ require 'fileutils'
|
|
5
5
|
require 'securerandom'
|
6
6
|
|
7
7
|
module AppInfo
|
8
|
+
class Error < StandardError; end
|
9
|
+
|
10
|
+
class NotFoundError < Error; end
|
11
|
+
|
12
|
+
class UnkownFileTypeError < Error; end
|
13
|
+
|
14
|
+
# App Platform
|
15
|
+
module Platform
|
16
|
+
MACOS = 'macOS'
|
17
|
+
IOS = 'iOS'
|
18
|
+
ANDROID = 'Android'
|
19
|
+
DSYM = 'dSYM'
|
20
|
+
PROGUARD = 'Proguard'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Device Type
|
24
|
+
module Device
|
25
|
+
MACOS = 'macOS'
|
26
|
+
IPHONE = 'iPhone'
|
27
|
+
IPAD = 'iPad'
|
28
|
+
UNIVERSAL = 'Universal'
|
29
|
+
end
|
30
|
+
|
31
|
+
# Icon Key
|
32
|
+
ICON_KEYS = {
|
33
|
+
AppInfo::Device::IPHONE => ['CFBundleIcons'],
|
34
|
+
AppInfo::Device::IPAD => ['CFBundleIcons~ipad'],
|
35
|
+
AppInfo::Device::UNIVERSAL => ['CFBundleIcons', 'CFBundleIcons~ipad'],
|
36
|
+
AppInfo::Device::MACOS => %w[CFBundleIconFile CFBundleIconName]
|
37
|
+
}.freeze
|
38
|
+
|
39
|
+
FILE_SIZE_UNITS = %w[B KB MB GB TB].freeze
|
40
|
+
|
8
41
|
# AppInfo Util
|
9
42
|
module Util
|
10
|
-
FILE_SIZE_UNITS = %w[B KB MB GB TB]
|
11
|
-
|
12
43
|
def self.format_key(key)
|
13
44
|
key = key.to_s
|
14
45
|
return key unless key.include?('_')
|
15
46
|
|
16
|
-
key.split('_').map(&:capitalize).join
|
47
|
+
key.split('_').map(&:capitalize).join
|
17
48
|
end
|
18
49
|
|
19
|
-
def self.file_size(file,
|
50
|
+
def self.file_size(file, human_size)
|
20
51
|
file_size = File.size(file)
|
21
|
-
|
52
|
+
human_size ? size_to_human_size(file_size) : file_size
|
22
53
|
end
|
23
54
|
|
24
|
-
def self.
|
55
|
+
def self.size_to_human_size(number)
|
25
56
|
if number.to_i < 1024
|
26
57
|
exponent = 0
|
27
58
|
else
|
@@ -54,5 +85,14 @@ module AppInfo
|
|
54
85
|
|
55
86
|
root_path
|
56
87
|
end
|
88
|
+
|
89
|
+
def self.tempdir(file, prefix:)
|
90
|
+
dest_path ||= File.join(File.dirname(file), prefix)
|
91
|
+
dest_file = File.join(dest_path, File.basename(file))
|
92
|
+
|
93
|
+
Dir.mkdir(dest_path, 0_700) unless Dir.exist?(dest_path)
|
94
|
+
|
95
|
+
dest_file
|
96
|
+
end
|
57
97
|
end
|
58
98
|
end
|
data/lib/app_info/version.rb
CHANGED
data/lib/app_info.rb
CHANGED
@@ -1,30 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'app_info/util'
|
3
4
|
require 'app_info/core_ext/object/try'
|
4
5
|
require 'app_info/version'
|
6
|
+
require 'app_info/info_plist'
|
7
|
+
require 'app_info/mobile_provision'
|
5
8
|
require 'app_info/ipa'
|
6
|
-
require 'app_info/ipa/info_plist'
|
7
|
-
require 'app_info/ipa/mobile_provision'
|
8
9
|
require 'app_info/ipa/plugin'
|
9
10
|
require 'app_info/ipa/framework'
|
10
11
|
require 'app_info/apk'
|
11
|
-
require 'app_info/dsym'
|
12
12
|
require 'app_info/proguard'
|
13
|
+
require 'app_info/dsym'
|
14
|
+
require 'app_info/macos'
|
15
|
+
|
16
|
+
# fix invaild date format warnings
|
17
|
+
Zip.warn_invalid_date = false
|
13
18
|
|
14
19
|
# AppInfo Module
|
15
20
|
module AppInfo
|
16
|
-
class Error < StandardError; end
|
17
|
-
class NotFoundError < Error; end
|
18
|
-
class UnkownFileTypeError < Error; end
|
19
|
-
|
20
|
-
# App Platform
|
21
|
-
module Platform
|
22
|
-
IOS = 'iOS'
|
23
|
-
ANDROID = 'Android'
|
24
|
-
DSYM = 'dSYM'
|
25
|
-
PROGUARD = 'Proguard'
|
26
|
-
end
|
27
|
-
|
28
21
|
# Get a new parser for automatic
|
29
22
|
def self.parse(file)
|
30
23
|
raise NotFoundError, file unless File.exist?(file)
|
@@ -35,6 +28,7 @@ module AppInfo
|
|
35
28
|
when :mobileprovision then MobileProvision.new(file)
|
36
29
|
when :dsym then DSYM.new(file)
|
37
30
|
when :proguard then Proguard.new(file)
|
31
|
+
when :macos then Macos.new(file)
|
38
32
|
else
|
39
33
|
raise UnkownFileTypeError, "Sorry, AppInfo can not detect file type: #{file}"
|
40
34
|
end
|
@@ -61,8 +55,11 @@ module AppInfo
|
|
61
55
|
zip_file = Zip::File.open(file)
|
62
56
|
|
63
57
|
return :proguard unless zip_file.glob('*mapping*.txt').empty?
|
64
|
-
return :apk
|
65
|
-
|
58
|
+
return :apk if !zip_file.find_entry('AndroidManifest.xml').nil? &&
|
59
|
+
!zip_file.find_entry('classes.dex').nil?
|
60
|
+
|
61
|
+
return :macos if !zip_file.glob('*/Contents/MacOS/*').empty? &&
|
62
|
+
!zip_file.glob('*/Contents/Info.plist').empty?
|
66
63
|
|
67
64
|
zip_file.each do |f|
|
68
65
|
path = f.name
|
@@ -70,19 +67,18 @@ module AppInfo
|
|
70
67
|
return :ipa if path.include?('Payload/') && path.end_with?('Info.plist')
|
71
68
|
return :dsym if path.include?('Contents/Resources/DWARF/')
|
72
69
|
end
|
70
|
+
ensure
|
71
|
+
zip_file.close
|
73
72
|
end
|
74
73
|
private_class_method :detect_zip_file
|
75
74
|
|
75
|
+
PLIST_REGEX = /\x3C\x3F\x78\x6D\x6C/.freeze
|
76
|
+
BPLIST_REGEX = /^\x62\x70\x6C\x69\x73\x74/.freeze
|
77
|
+
|
76
78
|
# :nodoc:
|
77
79
|
def self.detect_mobileprovision(hex)
|
78
|
-
|
79
|
-
|
80
|
-
:mobileprovision
|
81
|
-
elsif hex =~ /^\x62\x70\x6C\x69\x73\x74/
|
82
|
-
# bplist
|
83
|
-
:mobileprovision
|
84
|
-
elsif hex =~ /\x3C\x3F\x78\x6D\x6C/
|
85
|
-
# signed plist
|
80
|
+
case hex
|
81
|
+
when PLIST_REGEX, BPLIST_REGEX
|
86
82
|
:mobileprovision
|
87
83
|
end
|
88
84
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: app-info
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- icyleaf
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: CFPropertyList
|
@@ -124,6 +124,20 @@ dependencies:
|
|
124
124
|
- - "<"
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: 2.3.0
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: icns
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.2.0
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - "~>"
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: 0.2.0
|
127
141
|
- !ruby/object:Gem::Dependency
|
128
142
|
name: bundler
|
129
143
|
requirement: !ruby/object:Gem::Requirement
|
@@ -166,18 +180,34 @@ dependencies:
|
|
166
180
|
- - "~>"
|
167
181
|
- !ruby/object:Gem::Version
|
168
182
|
version: '3.0'
|
183
|
+
- !ruby/object:Gem::Dependency
|
184
|
+
name: rubocop
|
185
|
+
requirement: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - "~>"
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '1.19'
|
190
|
+
type: :development
|
191
|
+
prerelease: false
|
192
|
+
version_requirements: !ruby/object:Gem::Requirement
|
193
|
+
requirements:
|
194
|
+
- - "~>"
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
version: '1.19'
|
169
197
|
description: Teardown tool for ipa/apk files and dSYM file, even support for info.plist
|
170
198
|
and .mobileprovision files
|
171
199
|
email:
|
172
200
|
- icyleaf.cn@gmail.com
|
173
|
-
executables:
|
201
|
+
executables:
|
202
|
+
- app-info
|
174
203
|
extensions: []
|
175
204
|
extra_rdoc_files: []
|
176
205
|
files:
|
206
|
+
- ".github/dependabot.yml"
|
207
|
+
- ".github/workflows/ci.yml"
|
177
208
|
- ".gitignore"
|
178
209
|
- ".rspec"
|
179
210
|
- ".rubocop.yml"
|
180
|
-
- ".travis.yml"
|
181
211
|
- CHANGELOG.md
|
182
212
|
- CODE_OF_CONDUCT.md
|
183
213
|
- Gemfile
|
@@ -185,18 +215,21 @@ files:
|
|
185
215
|
- README.md
|
186
216
|
- Rakefile
|
187
217
|
- app_info.gemspec
|
218
|
+
- exe/app-info
|
188
219
|
- lib/app-info.rb
|
189
220
|
- lib/app_info.rb
|
190
221
|
- lib/app_info/apk.rb
|
191
222
|
- lib/app_info/core_ext/object/try.rb
|
192
223
|
- lib/app_info/dsym.rb
|
224
|
+
- lib/app_info/info_plist.rb
|
193
225
|
- lib/app_info/ipa.rb
|
194
226
|
- lib/app_info/ipa/framework.rb
|
195
|
-
- lib/app_info/ipa/info_plist.rb
|
196
|
-
- lib/app_info/ipa/mobile_provision.rb
|
197
227
|
- lib/app_info/ipa/plugin.rb
|
228
|
+
- lib/app_info/macos.rb
|
229
|
+
- lib/app_info/mobile_provision.rb
|
198
230
|
- lib/app_info/png_uncrush.rb
|
199
231
|
- lib/app_info/proguard.rb
|
232
|
+
- lib/app_info/shell.rb
|
200
233
|
- lib/app_info/util.rb
|
201
234
|
- lib/app_info/version.rb
|
202
235
|
homepage: http://github.com/icyleaf/app-info
|
@@ -211,7 +244,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
211
244
|
requirements:
|
212
245
|
- - ">="
|
213
246
|
- !ruby/object:Gem::Version
|
214
|
-
version: '2.
|
247
|
+
version: '2.5'
|
215
248
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
216
249
|
requirements:
|
217
250
|
- - ">="
|
data/.travis.yml
DELETED
@@ -1,162 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'cfpropertylist'
|
4
|
-
require 'app_info/png_uncrush'
|
5
|
-
require 'app_info/util'
|
6
|
-
|
7
|
-
module AppInfo
|
8
|
-
# iOS Info.plist parser
|
9
|
-
class InfoPlist
|
10
|
-
def initialize(app_path)
|
11
|
-
@app_path = app_path
|
12
|
-
end
|
13
|
-
|
14
|
-
def build_version
|
15
|
-
info.try(:[], 'CFBundleVersion')
|
16
|
-
end
|
17
|
-
|
18
|
-
def release_version
|
19
|
-
info.try(:[], 'CFBundleShortVersionString')
|
20
|
-
end
|
21
|
-
|
22
|
-
def identifier
|
23
|
-
info.try(:[], 'CFBundleIdentifier')
|
24
|
-
end
|
25
|
-
alias bundle_id identifier
|
26
|
-
|
27
|
-
def name
|
28
|
-
display_name || bundle_name
|
29
|
-
end
|
30
|
-
|
31
|
-
def display_name
|
32
|
-
info.try(:[], 'CFBundleDisplayName')
|
33
|
-
end
|
34
|
-
|
35
|
-
def bundle_name
|
36
|
-
info.try(:[], 'CFBundleName')
|
37
|
-
end
|
38
|
-
|
39
|
-
#
|
40
|
-
# Extract the Minimum OS Version from the Info.plist
|
41
|
-
#
|
42
|
-
def min_sdk_version
|
43
|
-
info.try(:[], 'MinimumOSVersion')
|
44
|
-
end
|
45
|
-
|
46
|
-
def icons(uncrush = true)
|
47
|
-
return @icons if @icons
|
48
|
-
|
49
|
-
@icons = []
|
50
|
-
icons_root_path.each do |name|
|
51
|
-
icon_array = info.try(:[], name)
|
52
|
-
.try(:[], 'CFBundlePrimaryIcon')
|
53
|
-
.try(:[], 'CFBundleIconFiles')
|
54
|
-
|
55
|
-
next if icon_array.nil? || icon_array.empty?
|
56
|
-
|
57
|
-
icon_array.each do |items|
|
58
|
-
Dir.glob(File.join(@app_path, "#{items}*")).find_all.each do |file|
|
59
|
-
@icons << icon_info(file, uncrush)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
@icons
|
65
|
-
end
|
66
|
-
|
67
|
-
def device_type
|
68
|
-
device_family = info.try(:[], 'UIDeviceFamily')
|
69
|
-
if device_family.length == 1
|
70
|
-
case device_family
|
71
|
-
when [1]
|
72
|
-
'iPhone'
|
73
|
-
when [2]
|
74
|
-
'iPad'
|
75
|
-
end
|
76
|
-
elsif device_family.length == 2 && device_family == [1, 2]
|
77
|
-
'Universal'
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def iphone?
|
82
|
-
device_type == 'iPhone'
|
83
|
-
end
|
84
|
-
|
85
|
-
def ipad?
|
86
|
-
device_type == 'iPad'
|
87
|
-
end
|
88
|
-
|
89
|
-
def universal?
|
90
|
-
device_type == 'Universal'
|
91
|
-
end
|
92
|
-
|
93
|
-
def release_type
|
94
|
-
if stored?
|
95
|
-
'Store'
|
96
|
-
else
|
97
|
-
build_type
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def [](key)
|
102
|
-
info.try(:[], key.to_s)
|
103
|
-
end
|
104
|
-
|
105
|
-
def method_missing(method_name, *args, &block)
|
106
|
-
info.try(:[], Util.format_key(method_name)) ||
|
107
|
-
info.send(method_name) ||
|
108
|
-
super
|
109
|
-
end
|
110
|
-
|
111
|
-
def respond_to_missing?(method_name, *args)
|
112
|
-
info.key?(Util.format_key(method_name)) ||
|
113
|
-
info.respond_to?(method_name) ||
|
114
|
-
super
|
115
|
-
end
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
def icon_info(file, uncrush = true)
|
120
|
-
uncrushed_file = nil
|
121
|
-
if uncrush
|
122
|
-
path = File.join(File.dirname(file), 'uncrushed')
|
123
|
-
Dir.mkdir(path, 0700) unless Dir.exist?(path)
|
124
|
-
|
125
|
-
uncrushed_file = File.join(path, File.basename(file))
|
126
|
-
PngUncrush.decompress(file, uncrushed_file)
|
127
|
-
uncrushed_file = nil unless File.exists?(uncrushed_file)
|
128
|
-
end
|
129
|
-
|
130
|
-
{
|
131
|
-
name: File.basename(file),
|
132
|
-
file: file,
|
133
|
-
uncrushed_file: uncrushed_file,
|
134
|
-
dimensions: PngUncrush.dimensions(file)
|
135
|
-
}
|
136
|
-
end
|
137
|
-
|
138
|
-
def info
|
139
|
-
return unless File.file?(info_path)
|
140
|
-
|
141
|
-
@info ||= CFPropertyList.native_types(CFPropertyList::List.new(file: info_path).value)
|
142
|
-
end
|
143
|
-
|
144
|
-
def info_path
|
145
|
-
File.join(@app_path, 'Info.plist')
|
146
|
-
end
|
147
|
-
|
148
|
-
IPHONE_KEY = 'CFBundleIcons'
|
149
|
-
IPAD_KEY = 'CFBundleIcons~ipad'
|
150
|
-
|
151
|
-
def icons_root_path
|
152
|
-
case device_type
|
153
|
-
when 'iPhone'
|
154
|
-
[IPHONE_KEY]
|
155
|
-
when 'iPad'
|
156
|
-
[IPAD_KEY]
|
157
|
-
when 'Universal'
|
158
|
-
[IPHONE_KEY, IPAD_KEY]
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|