app-info 2.7.0.beta1 → 2.8.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 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: