app-info 2.7.0.beta1 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b37b084ef666db1fad604e2aa19698faad80d68d7d79a031c55d60e3f8b97f48
4
- data.tar.gz: 2a8da24c6adc6b9f003d8a8016569f2f20772f1c7524ea411a6b4946f32fd0a7
3
+ metadata.gz: f2c78a4901456e1d50dc468314d4fa12e9b66db13e3f4678f5a4f371dddda03e
4
+ data.tar.gz: 3493755f61ca80721c9fee684a06dc5922d0427695ce1ef1f1b1c44739686da5
5
5
  SHA512:
6
- metadata.gz: 9041485898807902ce753c4114b82037cf900c45fc4ce183fb2af0ec57c0fd05ebe96314a89016e3f423531daa528d48d6ea566445296be045d18dc6ab4da4cb
7
- data.tar.gz: fd22abedeea11ba62dd7f4575f19a08348d146cc6ffd3a6d69b54652a869b9dc095467d9922031a84d79336fbbc4e3dc485a428e8a96d66fc4bedc378d1e962f
6
+ metadata.gz: 67bca698f1e7dd6cde75a3d57776a0d2cd95ab6cf5c156d101f76b333535f763dfc55051d1f975fec499e09a0a66b7b0f6c6855877bdad4100be243f9e2be001
7
+ data.tar.gz: d07d95a0d1481ba711a953f09bfcf966f7827e9c0b0d010fbf16bfc7c16a39ef05950b9fa9c5a2e34a0b117a995d9182b56d2f19fd9b98f40eea6e4d084734bb
data/CHANGELOG.md CHANGED
@@ -9,6 +9,31 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
9
9
 
10
10
  > List all changes before release a new version.
11
11
 
12
+ ## [2.8.0] (2021-12-16)
13
+
14
+ ### Added
15
+
16
+ - New methods added to `apk` and `aab` [3adfa223](https://github.com/icyleaf/app_info/tree/3adfa223479caa672fce5d3a119b6db098463699) [939a6506](https://github.com/icyleaf/app_info/tree/939a6506f3ac1cb7ad1ed46128df41de6ee3b0d0)
17
+
18
+ ## [2.7.0] (2021-10-15)
19
+
20
+ ### Added
21
+
22
+ - Android App Bundle (a.k.a) aab support!!! parts support [#36](https://github.com/icyleaf/app_info/pull/36)
23
+
24
+ ## [2.7.0.beta5] (2021-10-14)
25
+
26
+ ### Fixed
27
+
28
+ - Renamed methods of inflector (Conflicts with similar external methods, such like ActiveSupport Core Extensions)
29
+ - Keep same behavior methods between apk and aab
30
+
31
+ ## [2.7.0.beta2] (2021-09-29)
32
+
33
+ ### Fixed
34
+
35
+ - Fix allocator undefined data class [#38](https://github.com/icyleaf/app_info/pull/38)
36
+
12
37
  ## [2.7.0.beta1] (2021-09-27)
13
38
 
14
39
  ### Added
@@ -191,7 +216,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
191
216
 
192
217
  - Updated dependency of CFPropertly list be a range between 2.3.4. (thanks @[cschroed](https://github.com/cschroed))
193
218
 
194
- [Unreleased]: https://github.com/icyleaf/app-info/compare/v2.7.0.beta1..HEAD
219
+ [Unreleased]: https://github.com/icyleaf/app-info/compare/v2.6.5..HEAD
220
+ [2.7.0]: https://github.com/icyleaf/app-info/compare/v2.6.5...v2.7.0
221
+ [2.7.0.beta5]: https://github.com/icyleaf/app-info/compare/v2.7.0.beta2...v2.7.0.beta5
222
+ [2.7.0.beta2]: https://github.com/icyleaf/app-info/compare/v2.7.0.beta1...v2.7.0.beta2
195
223
  [2.7.0.beta1]: https://github.com/icyleaf/app-info/compare/v2.6.5...v2.7.0.beta1
196
224
  [2.6.5]: https://github.com/icyleaf/app-info/compare/v2.6.4...v2.6.5
197
225
  [2.6.4]: https://github.com/icyleaf/app-info/compare/v2.6.3...v2.6.4
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![Gem version](https://img.shields.io/gem/v/app-info.svg?style=flat)](https://rubygems.org/gems/app_info)
6
6
  [![License](https://img.shields.io/badge/license-MIT-red.svg?style=flat)](LICENSE)
7
7
 
8
- Teardown tool for mobile(ipa/apk) app, macOS app and dSYM.zip file, analysis metedata like version, name, icon etc.
8
+ Teardown tool for mobile app (ipa, apk and aab file), macOS app and dSYM.zip file, analysis metedata like version, name, icon etc.
9
9
 
10
10
  ## Support
11
11
 
@@ -49,6 +49,7 @@ require 'app-info'
49
49
  parser = AppInfo.parse('iphone.ipa')
50
50
  parser = AppInfo.parse('ipad.ipa')
51
51
  parser = AppInfo.parse('android.apk')
52
+ parser = AppInfo.parse('android.aab')
52
53
  parser = AppInfo.parse('u-u-i-d.mobileprovision')
53
54
  parser = AppInfo.parse('macOS.App.zip')
54
55
  parser = AppInfo.parse('App.dSYm.zip')
@@ -296,9 +297,9 @@ It is possible to use this gem as a command line interface to parse mobile app:
296
297
  ```
297
298
  > app-info
298
299
 
299
- app-info (0.6.0)> p = AppInfo.parse('/path/to/app')
300
+ app-info (2.7.0)> p = AppInfo.parse('/path/to/app')
300
301
  => #<AppInfo::APK::......>
301
- app-info (0.6.0)> p.name
302
+ app-info (2.7.0)> p.name
302
303
  => "AppName"
303
304
  ```
304
305
 
data/Rakefile CHANGED
@@ -4,6 +4,7 @@ $LOAD_PATH.unshift File.expand_path('lib', __dir__)
4
4
  require 'app_info'
5
5
  require 'bundler/gem_tasks'
6
6
  require 'rspec/core/rake_task'
7
+ require 'rubocop/rake_task'
7
8
 
8
9
  RSpec::Core::RakeTask.new(:spec)
9
10
 
data/app_info.gemspec CHANGED
@@ -21,9 +21,9 @@ Gem::Specification.new do |spec|
21
21
  spec.required_ruby_version = '>= 2.5'
22
22
 
23
23
  spec.add_dependency 'CFPropertyList', '< 3.1.0', '>= 2.3.4'
24
- spec.add_dependency 'image_size', '>= 1.5', '< 2.2'
24
+ spec.add_dependency 'image_size', '>= 1.5', '< 3.1'
25
25
  spec.add_dependency 'ruby-macho', '< 3', '>= 1.4'
26
- spec.add_dependency 'android_parser', '~> 2.4.1'
26
+ spec.add_dependency 'android_parser', '~> 2.5.0'
27
27
  spec.add_dependency 'rubyzip', '>= 1.2', '< 3.0'
28
28
  spec.add_dependency 'uuidtools', '>= 2.1.5', '< 2.3.0'
29
29
  spec.add_dependency 'icns', '~> 0.2.0'
data/lib/app_info/aab.rb CHANGED
@@ -14,10 +14,11 @@ module AppInfo
14
14
 
15
15
  # APK Devices
16
16
  module Device
17
- PHONE = 'Phone'
18
- TABLET = 'Tablet'
19
- WATCH = 'Watch'
20
- TV = 'Television'
17
+ PHONE = 'Phone'
18
+ TABLET = 'Tablet'
19
+ WATCH = 'Watch'
20
+ TV = 'Television'
21
+ AUTOMOTIVE = 'Automotive'
21
22
  end
22
23
 
23
24
  BASE_PATH = 'base'
@@ -37,7 +38,7 @@ module AppInfo
37
38
  end
38
39
  alias file_type os
39
40
 
40
- def_delegators :manifest, :version_name
41
+ def_delegators :manifest, :version_name, :deep_links, :schemes
41
42
 
42
43
  alias release_version version_name
43
44
 
@@ -61,6 +62,8 @@ module AppInfo
61
62
  Device::WATCH
62
63
  elsif tv?
63
64
  Device::TV
65
+ elsif automotive?
66
+ Device::AUTOMOTIVE
64
67
  else
65
68
  Device::PHONE
66
69
  end
@@ -83,6 +86,10 @@ module AppInfo
83
86
  use_features.include?('android.software.leanback')
84
87
  end
85
88
 
89
+ def automotive?
90
+ use_features.include?('android.hardware.type.automotive')
91
+ end
92
+
86
93
  def min_sdk_version
87
94
  manifest.uses_sdk.min_sdk_version
88
95
  end
@@ -101,17 +108,27 @@ module AppInfo
101
108
  end
102
109
 
103
110
  def activities
104
- @activities ||= manifest.activities.map(&:name)
111
+ @activities ||= manifest.activities
105
112
  end
106
113
 
107
114
  def services
108
- @services ||= manifest.services.map(&:name)
115
+ @services ||= manifest.services
109
116
  end
110
117
 
111
118
  def components
112
- @components ||= manifest.components.transform_values do |child|
113
- child.map(&:name)
114
- end
119
+ @components ||= manifest.components.transform_values
120
+ end
121
+
122
+ def sign_version
123
+ return 'v1' unless signs.empty?
124
+
125
+ # when ?
126
+ # https://source.android.com/security/apksigning/v2?hl=zh-cn
127
+ # 'v2'
128
+ # when ?
129
+ # https://source.android.com/security/apksigning/v3?hl=zh-cn
130
+ # 'v3'
131
+ 'unknown'
115
132
  end
116
133
 
117
134
  def signs
data/lib/app_info/apk.rb CHANGED
@@ -14,10 +14,11 @@ module AppInfo
14
14
 
15
15
  # APK Devices
16
16
  module Device
17
- PHONE = 'Phone'
18
- TABLET = 'Tablet'
19
- WATCH = 'Watch'
20
- TV = 'Television'
17
+ PHONE = 'Phone'
18
+ TABLET = 'Tablet'
19
+ WATCH = 'Watch'
20
+ TV = 'Television'
21
+ AUTOMOTIVE = 'Automotive'
21
22
  end
22
23
 
23
24
  def initialize(file)
@@ -35,8 +36,9 @@ module AppInfo
35
36
 
36
37
  def_delegators :apk, :manifest, :resource, :dex
37
38
 
38
- def_delegators :manifest, :version_name, :package_name,
39
- :use_permissions, :components
39
+ def_delegators :manifest, :version_name, :package_name, :target_sdk_version,
40
+ :components, :services, :use_permissions, :use_features,
41
+ :deep_links, :schemes
40
42
 
41
43
  alias release_version version_name
42
44
  alias identifier package_name
@@ -56,14 +58,15 @@ module AppInfo
56
58
  Device::WATCH
57
59
  elsif tv?
58
60
  Device::TV
61
+ elsif automotive?
62
+ Device::AUTOMOTIVE
59
63
  else
60
64
  Device::PHONE
61
65
  end
62
66
  end
63
67
 
64
- # TODO: find a way to detect
68
+ # TODO: find a way to detect, no way!
65
69
  # def tablet?
66
- # resource
67
70
  # end
68
71
 
69
72
  def wear?
@@ -74,20 +77,25 @@ module AppInfo
74
77
  use_features.include?('android.software.leanback')
75
78
  end
76
79
 
80
+ def automotive?
81
+ use_features.include?('android.hardware.type.automotive')
82
+ end
83
+
77
84
  def min_sdk_version
78
85
  manifest.min_sdk_ver
79
86
  end
80
87
  alias min_os_version min_sdk_version
81
88
 
82
- def target_sdk_version
83
- manifest.doc
84
- .elements['/manifest/uses-sdk']
85
- .attributes['targetSdkVersion']
86
- .to_i
87
- end
89
+ def sign_version
90
+ return 'v1' unless signs.empty?
88
91
 
89
- def use_features
90
- manifest_values('/manifest/uses-feature')
92
+ # when ?
93
+ # https://source.android.com/security/apksigning/v2?hl=zh-cn
94
+ # 'v2'
95
+ # when ?
96
+ # https://source.android.com/security/apksigning/v3?hl=zh-cn
97
+ # 'v3'
98
+ 'unknown'
91
99
  end
92
100
 
93
101
  def signs
@@ -106,10 +114,6 @@ module AppInfo
106
114
  components.select { |c| c.type == 'activity' }
107
115
  end
108
116
 
109
- def services
110
- components.select { |c| c.type == 'service' }
111
- end
112
-
113
117
  def apk
114
118
  @apk ||= ::Android::Apk.new(@file)
115
119
  end
@@ -146,16 +150,6 @@ module AppInfo
146
150
  @contents ||= File.join(Dir.mktmpdir, "AppInfo-android-#{SecureRandom.hex}")
147
151
  end
148
152
 
149
- private
150
-
151
- def manifest_values(path, key = 'name')
152
- values = []
153
- manifest.doc.each_element(path) do |elem|
154
- values << elem.attributes[key]
155
- end
156
- values.uniq
157
- end
158
-
159
153
  # Android Certificate
160
154
  class Certificate
161
155
  attr_reader :path, :certificate
@@ -2,7 +2,7 @@
2
2
 
3
3
  module AppInfo
4
4
  module Inflector
5
- def snakecase
5
+ def ai_snakecase
6
6
  gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
7
7
  .gsub(/([a-z\d])([A-Z])/, '\1_\2')
8
8
  .tr('-', '_')
@@ -11,7 +11,7 @@ module AppInfo
11
11
  .downcase
12
12
  end
13
13
 
14
- def camelcase(first_letter: :upper, separators: ['-', '_', '\s'])
14
+ def ai_camelcase(first_letter: :upper, separators: ['-', '_', '\s'])
15
15
  str = dup
16
16
 
17
17
  separators.each do |s|
@@ -99,7 +99,9 @@ module AppInfo
99
99
  end
100
100
 
101
101
  name = namespace.to_s.empty? ? klass_name : "#{namespace}::#{klass_name}"
102
- if Object.const_defined?(name)
102
+ if Object.const_get(namespace).const_defined?(klass_name)
103
+ Object.const_get(namespace).const_get(klass_name)
104
+ elsif Object.const_defined?(name)
103
105
  Object.const_get(name)
104
106
  else
105
107
  Object.const_get(namespace).const_set(klass_name, klass)
@@ -112,13 +112,13 @@ module AppInfo
112
112
  def_delegators :info, :to_h
113
113
 
114
114
  def method_missing(method_name, *args, &block)
115
- info.try(:[], method_name.to_s.camelcase) ||
115
+ info.try(:[], method_name.to_s.ai_camelcase) ||
116
116
  info.send(method_name) ||
117
117
  super
118
118
  end
119
119
 
120
120
  def respond_to_missing?(method_name, *args)
121
- info.key?(method_name.to_s.camelcase) ||
121
+ info.key?(method_name.to_s.ai_camelcase) ||
122
122
  info.respond_to?(method_name) ||
123
123
  super
124
124
  end
@@ -212,13 +212,13 @@ module AppInfo
212
212
  end
213
213
 
214
214
  def method_missing(method_name, *args, &block)
215
- mobileprovision.try(:[], method_name.to_s.camelcase) ||
215
+ mobileprovision.try(:[], method_name.to_s.ai_camelcase) ||
216
216
  mobileprovision.send(method_name) ||
217
217
  super
218
218
  end
219
219
 
220
220
  def respond_to_missing?(method_name, *args)
221
- mobileprovision.key?(method_name.to_s.camelcase) ||
221
+ mobileprovision.key?(method_name.to_s.ai_camelcase) ||
222
222
  mobileprovision.respond_to?(method_name) ||
223
223
  super
224
224
  end
@@ -72,7 +72,7 @@ module AppInfo
72
72
  @attributes = element.attribute.each_with_object({}).each do |item, obj|
73
73
  node = Attribute.new(item)
74
74
 
75
- method_name = node.name.snakecase
75
+ method_name = node.name.ai_snakecase
76
76
  obj[method_name] = node
77
77
  define_instance_method(method_name, node.value)
78
78
  end
@@ -87,11 +87,11 @@ module AppInfo
87
87
  @children = element.child.each_with_object({}) do |item, obj|
88
88
  next unless item_element = item.element
89
89
 
90
- class_name = item_element.name.camelcase
90
+ class_name = item_element.name.ai_camelcase
91
91
  klass = create_class(class_name, Protobuf::Node, namespace: 'AppInfo::Protobuf::Manifest')
92
92
  node = klass.new(item)
93
93
 
94
- method_name = item_element.name.snakecase
94
+ method_name = item_element.name.ai_snakecase
95
95
  if UNIQUE_KEY.include?(method_name)
96
96
  obj[method_name] = node
97
97
  else
@@ -129,16 +129,96 @@ module AppInfo
129
129
  end
130
130
 
131
131
  def activities
132
- application.activity
132
+ application.respond_to?(:activity) ? application.activity : []
133
133
  end
134
134
 
135
135
  def services
136
- application.service
136
+ application.respond_to?(:service) ? application.service : []
137
137
  end
138
138
 
139
139
  def icons
140
140
  @resources.find(application.icon)
141
141
  end
142
+
143
+ def deep_links
144
+ activities.each_with_object([]) do |activity, obj|
145
+ intent_filters = activity.intent_filter
146
+ next if intent_filters.empty?
147
+
148
+ intent_filters.each do |filter|
149
+ next unless filter.deep_links?
150
+
151
+ obj << filter.deep_links
152
+ end
153
+ end.flatten.uniq
154
+ end
155
+
156
+ def schemes
157
+ activities.each_with_object([]) do |activity, obj|
158
+ intent_filters = activity.intent_filter
159
+ next if intent_filters.empty?
160
+
161
+ intent_filters.each do |filter|
162
+ next unless filter.schemes?
163
+
164
+ obj << filter.schemes
165
+ end
166
+ end.flatten.uniq
167
+ end
168
+
169
+ # :nodoc:
170
+ # Workaround ruby always return true by called `Object.const_defined?(Data)`
171
+ class Data < Node; end
172
+
173
+ class IntentFilter < Node
174
+ # filter types (action is required, category and data are optional)
175
+ TYPES = %w[action category data].freeze
176
+
177
+ DEEP_LINK_SCHEMES = %w[http https].freeze
178
+
179
+ # browsable of category
180
+ CATEGORY_BROWSABLE = 'android.intent.category.BROWSABLE'
181
+
182
+ def deep_links?
183
+ browsable? && data.any? { |d| DEEP_LINK_SCHEMES.include?(d.scheme) }
184
+ end
185
+
186
+ def deep_links
187
+ return unless deep_links?
188
+
189
+ data.reject { |d| d.host.nil? }
190
+ .map(&:host)
191
+ .uniq
192
+ end
193
+
194
+ def schemes
195
+ return unless schemes?
196
+
197
+ data.select { |d| !d.scheme.nil? && !DEEP_LINK_SCHEMES.include?(d.scheme) }
198
+ .map(&:scheme)
199
+ .uniq
200
+ end
201
+
202
+ def schemes?
203
+ browsable? && data.any? { |d| !DEEP_LINK_SCHEMES.include?(d.scheme) }
204
+ end
205
+
206
+ def browsable?
207
+ exist?(CATEGORY_BROWSABLE)
208
+ end
209
+
210
+ def exist?(name, type: nil)
211
+ if type.to_s.empty? && !name.start_with?('android.intent.')
212
+ raise 'Fill type or use correct name'
213
+ end
214
+
215
+ type ||= name.split('.')[2]
216
+ raise 'Not found type' unless TYPES.include?(type)
217
+
218
+ values = send(type.to_sym).select { |e| e.name == name }
219
+ values.empty? ? false : values
220
+ end
221
+ end
142
222
  end
143
223
  end
144
224
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppInfo
4
- VERSION = '2.7.0.beta1'
4
+ VERSION = '2.8.0'
5
5
  end
data/lib/app_info.rb CHANGED
@@ -48,7 +48,7 @@ module AppInfo
48
48
  #
49
49
  # TODO: This can be better solution, if anyone knows, tell me please.
50
50
  def file_type(file)
51
- header_hex = IO.read(file, 100)
51
+ header_hex = File.read(file, 100)
52
52
  type = if header_hex =~ /^\x50\x4b\x03\x04/
53
53
  detect_zip_file(file)
54
54
  else
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.7.0.beta1
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - icyleaf
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-27 00:00:00.000000000 Z
11
+ date: 2021-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: CFPropertyList
@@ -39,7 +39,7 @@ dependencies:
39
39
  version: '1.5'
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: '2.2'
42
+ version: '3.1'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -49,7 +49,7 @@ dependencies:
49
49
  version: '1.5'
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: '2.2'
52
+ version: '3.1'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: ruby-macho
55
55
  requirement: !ruby/object:Gem::Requirement
@@ -76,14 +76,14 @@ dependencies:
76
76
  requirements:
77
77
  - - "~>"
78
78
  - !ruby/object:Gem::Version
79
- version: 2.4.1
79
+ version: 2.5.0
80
80
  type: :runtime
81
81
  prerelease: false
82
82
  version_requirements: !ruby/object:Gem::Requirement
83
83
  requirements:
84
84
  - - "~>"
85
85
  - !ruby/object:Gem::Version
86
- version: 2.4.1
86
+ version: 2.5.0
87
87
  - !ruby/object:Gem::Dependency
88
88
  name: rubyzip
89
89
  requirement: !ruby/object:Gem::Requirement
@@ -272,9 +272,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
272
272
  version: '2.5'
273
273
  required_rubygems_version: !ruby/object:Gem::Requirement
274
274
  requirements:
275
- - - ">"
275
+ - - ">="
276
276
  - !ruby/object:Gem::Version
277
- version: 1.3.1
277
+ version: '0'
278
278
  requirements: []
279
279
  rubygems_version: 3.1.4
280
280
  signing_key: