app-info 2.5.1 → 2.6.0
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 -2
- data/Gemfile +6 -0
- data/README.md +110 -50
- data/app_info.gemspec +6 -3
- data/exe/app-info +12 -0
- data/lib/app_info/apk.rb +17 -22
- 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} +8 -9
- data/lib/app_info/png_uncrush.rb +31 -26
- 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 +51 -12
- data/.travis.yml +0 -9
- data/lib/app_info/ipa/info_plist.rb +0 -161
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].freeze
|
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.0
|
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-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: CFPropertyList
|
@@ -54,16 +54,22 @@ dependencies:
|
|
54
54
|
name: ruby-macho
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
|
-
- - "
|
57
|
+
- - "<"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '3'
|
60
|
+
- - ">="
|
58
61
|
- !ruby/object:Gem::Version
|
59
|
-
version:
|
62
|
+
version: '1.4'
|
60
63
|
type: :runtime
|
61
64
|
prerelease: false
|
62
65
|
version_requirements: !ruby/object:Gem::Requirement
|
63
66
|
requirements:
|
64
|
-
- - "
|
67
|
+
- - "<"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3'
|
70
|
+
- - ">="
|
65
71
|
- !ruby/object:Gem::Version
|
66
|
-
version:
|
72
|
+
version: '1.4'
|
67
73
|
- !ruby/object:Gem::Dependency
|
68
74
|
name: ruby_android
|
69
75
|
requirement: !ruby/object:Gem::Requirement
|
@@ -118,6 +124,20 @@ dependencies:
|
|
118
124
|
- - "<"
|
119
125
|
- !ruby/object:Gem::Version
|
120
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
|
121
141
|
- !ruby/object:Gem::Dependency
|
122
142
|
name: bundler
|
123
143
|
requirement: !ruby/object:Gem::Requirement
|
@@ -160,18 +180,34 @@ dependencies:
|
|
160
180
|
- - "~>"
|
161
181
|
- !ruby/object:Gem::Version
|
162
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'
|
163
197
|
description: Teardown tool for ipa/apk files and dSYM file, even support for info.plist
|
164
198
|
and .mobileprovision files
|
165
199
|
email:
|
166
200
|
- icyleaf.cn@gmail.com
|
167
|
-
executables:
|
201
|
+
executables:
|
202
|
+
- app-info
|
168
203
|
extensions: []
|
169
204
|
extra_rdoc_files: []
|
170
205
|
files:
|
206
|
+
- ".github/dependabot.yml"
|
207
|
+
- ".github/workflows/ci.yml"
|
171
208
|
- ".gitignore"
|
172
209
|
- ".rspec"
|
173
210
|
- ".rubocop.yml"
|
174
|
-
- ".travis.yml"
|
175
211
|
- CHANGELOG.md
|
176
212
|
- CODE_OF_CONDUCT.md
|
177
213
|
- Gemfile
|
@@ -179,18 +215,21 @@ files:
|
|
179
215
|
- README.md
|
180
216
|
- Rakefile
|
181
217
|
- app_info.gemspec
|
218
|
+
- exe/app-info
|
182
219
|
- lib/app-info.rb
|
183
220
|
- lib/app_info.rb
|
184
221
|
- lib/app_info/apk.rb
|
185
222
|
- lib/app_info/core_ext/object/try.rb
|
186
223
|
- lib/app_info/dsym.rb
|
224
|
+
- lib/app_info/info_plist.rb
|
187
225
|
- lib/app_info/ipa.rb
|
188
226
|
- lib/app_info/ipa/framework.rb
|
189
|
-
- lib/app_info/ipa/info_plist.rb
|
190
|
-
- lib/app_info/ipa/mobile_provision.rb
|
191
227
|
- lib/app_info/ipa/plugin.rb
|
228
|
+
- lib/app_info/macos.rb
|
229
|
+
- lib/app_info/mobile_provision.rb
|
192
230
|
- lib/app_info/png_uncrush.rb
|
193
231
|
- lib/app_info/proguard.rb
|
232
|
+
- lib/app_info/shell.rb
|
194
233
|
- lib/app_info/util.rb
|
195
234
|
- lib/app_info/version.rb
|
196
235
|
homepage: http://github.com/icyleaf/app-info
|
@@ -205,7 +244,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
205
244
|
requirements:
|
206
245
|
- - ">="
|
207
246
|
- !ruby/object:Gem::Version
|
208
|
-
version: '2.
|
247
|
+
version: '2.5'
|
209
248
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
210
249
|
requirements:
|
211
250
|
- - ">="
|
data/.travis.yml
DELETED
@@ -1,161 +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
|
-
end
|
128
|
-
|
129
|
-
{
|
130
|
-
name: File.basename(file),
|
131
|
-
file: file,
|
132
|
-
uncrushed_file: uncrushed_file,
|
133
|
-
dimensions: PngUncrush.dimensions(file)
|
134
|
-
}
|
135
|
-
end
|
136
|
-
|
137
|
-
def info
|
138
|
-
return unless File.file?(info_path)
|
139
|
-
|
140
|
-
@info ||= CFPropertyList.native_types(CFPropertyList::List.new(file: info_path).value)
|
141
|
-
end
|
142
|
-
|
143
|
-
def info_path
|
144
|
-
File.join(@app_path, 'Info.plist')
|
145
|
-
end
|
146
|
-
|
147
|
-
IPHONE_KEY = 'CFBundleIcons'
|
148
|
-
IPAD_KEY = 'CFBundleIcons~ipad'
|
149
|
-
|
150
|
-
def icons_root_path
|
151
|
-
case device_type
|
152
|
-
when 'iPhone'
|
153
|
-
[IPHONE_KEY]
|
154
|
-
when 'iPad'
|
155
|
-
[IPAD_KEY]
|
156
|
-
when 'Universal'
|
157
|
-
[IPHONE_KEY, IPAD_KEY]
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|