app-info 2.7.0.beta2 → 2.8.1

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: '09f29a3f5c7efa6e39d589cfc5d4a168d5267bb88ebf9434a377dbe1ba9d6326'
4
- data.tar.gz: 45bb2036a6777b043ab85b399d0559f92f144750d98097ea3ad6007ffed39c0d
3
+ metadata.gz: e3f9fde9fba3ff6b0653e7ebf7c122c2dc290aaa81be4ce52d6fd1853fc9963e
4
+ data.tar.gz: 3a18e33551bce9cb9155779e56f943c8df6f7528807410e66ec897d8f64a57c6
5
5
  SHA512:
6
- metadata.gz: 99af334d2500db7df891232986366e390943a11689b593f0b827edeabc68fdc3df38b0c2d675c09282941f4f3870ad8afa6ee46c95b18acf1d40c41990698b19
7
- data.tar.gz: 45c1da2efa47617b4dccd315fb868097df4814492e6e9e6371082c9f84171ed493eb9de8449483a8d640e8b0d2a830f0840eff199e4a786ff937f8662b102240
6
+ metadata.gz: 1ed9868f7cde0c52565cb9433f812c51645c5d01ea5501770d8f09be3ab4ed06ff0a09baf45c8e69d09c3e011a3376d2268de71988bcf89d363570d5c4e02872
7
+ data.tar.gz: aa2516f818a0e2452f960769c4ac344ab31ea87e6802e0126373f91cfe492cefa575051377cfbfaeeddcff988adf984a09d6c73cbe61a3c6a1ce6548f9bec460
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.1] (2021-12-20)
13
+
14
+ ### Fixed
15
+
16
+ - Fix no found intent filter in manifest error.
17
+
18
+ ## [2.8.0] (2021-12-16)
19
+
20
+ ### Added
21
+
22
+ - 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)
23
+
24
+ ## [2.7.0] (2021-10-15)
25
+
26
+ ### Added
27
+
28
+ - Android App Bundle (a.k.a) aab support!!! parts support [#36](https://github.com/icyleaf/app_info/pull/36)
29
+
30
+ ## [2.7.0.beta5] (2021-10-14)
31
+
32
+ ### Fixed
33
+
34
+ - Renamed methods of inflector (Conflicts with similar external methods, such like ActiveSupport Core Extensions)
35
+ - Keep same behavior methods between apk and aab
36
+
12
37
  ## [2.7.0.beta2] (2021-09-29)
13
38
 
14
39
  ### Fixed
@@ -197,7 +222,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
197
222
 
198
223
  - Updated dependency of CFPropertly list be a range between 2.3.4. (thanks @[cschroed](https://github.com/cschroed))
199
224
 
200
- [Unreleased]: https://github.com/icyleaf/app-info/compare/v2.7.0.beta2..HEAD
225
+ [Unreleased]: https://github.com/icyleaf/app-info/compare/v2.8.1..HEAD
226
+ [2.8.1]: https://github.com/icyleaf/app-info/compare/v2.8.0...v2.8.1
227
+ [2.8.0]: https://github.com/icyleaf/app-info/compare/v2.7.0...v2.8.0
228
+ [2.7.0]: https://github.com/icyleaf/app-info/compare/v2.6.5...v2.7.0
229
+ [2.7.0.beta5]: https://github.com/icyleaf/app-info/compare/v2.7.0.beta2...v2.7.0.beta5
201
230
  [2.7.0.beta2]: https://github.com/icyleaf/app-info/compare/v2.7.0.beta1...v2.7.0.beta2
202
231
  [2.7.0.beta1]: https://github.com/icyleaf/app-info/compare/v2.6.5...v2.7.0.beta1
203
232
  [2.6.5]: https://github.com/icyleaf/app-info/compare/v2.6.4...v2.6.5
data/README.md CHANGED
@@ -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')
@@ -153,56 +154,67 @@ profile.enabled_capabilities
153
154
 
154
155
  ### Android
155
156
 
157
+ Accept `.aab` and `.apk` Android file.
158
+
156
159
  ```ruby
157
- apk = AppInfo.parse('android.apk')
160
+ android = AppInfo.parse('android.apk_or_aab')
158
161
 
159
162
  # get app file size
160
- apk.size
163
+ android.size
161
164
  # => 3093823
162
165
 
163
166
  # get app file size in human reable.
164
- apk.size(human_size: true)
167
+ android.size(human_size: true)
165
168
  # => 29 MB
166
169
 
167
170
  # get app release version
168
- apk.release_version
171
+ android.release_version
169
172
  # => 1.0
170
173
 
171
174
  # get app package name
172
- apk.bundle_id
175
+ android.bundle_id
173
176
  # => com.icyleaf.AppInfoDemo
174
177
 
178
+ # detect app type (It's difficult to detect phone or tablet)
179
+ android.tv?
180
+ android.wear?
181
+ android.automotive?
182
+
175
183
  # get app icons
176
- apk.icons
184
+ android.icons
177
185
  # => [{:name=>"ic_launcher.png", :file=> "/temp/dir/app/ic_launcher.png", :dimensions=>[48, 48]}, ...]
178
186
 
179
187
  # get app support min sdk version
180
- apk.min_sdk_version
188
+ android.min_sdk_version
181
189
  # => 13
182
190
 
183
191
  # get use_permissions list
184
- apk.use_permissions
192
+ android.use_permissions
185
193
  # => [...]
186
194
 
187
195
  # get activitiy list
188
- apk.activities
196
+ android.activities
189
197
  # => [...]
190
198
 
191
199
  # get service list
192
- apk.services
200
+ android.services
193
201
  # => [...]
194
202
 
195
- # get certificate list
196
- apk.certificates
197
- # => [...]
203
+ # get deep links host
204
+ android.deep_links
205
+ # => ['a.com']
198
206
 
199
- # get sign list
200
- apk.signs
207
+ # get schemes without http or https
208
+ android.schemes
209
+ # => ['appinfo']
210
+
211
+ # get sign list (only v1 sign)
212
+ android.signs
201
213
  # => [...]
202
214
 
203
- # detect app type (It's difficult to detect phone or tablet)
204
- apk.tv?
205
- apk.wear?
215
+ # get certificate list (only v1 sign)
216
+ android.certificates
217
+ # => [...]
206
218
  ```
207
219
 
208
220
  ### macOS
@@ -296,9 +308,9 @@ It is possible to use this gem as a command line interface to parse mobile app:
296
308
  ```
297
309
  > app-info
298
310
 
299
- app-info (0.6.0)> p = AppInfo.parse('/path/to/app')
311
+ app-info (2.7.0)> p = AppInfo.parse('/path/to/app')
300
312
  => #<AppInfo::APK::......>
301
- app-info (0.6.0)> p.name
313
+ app-info (2.7.0)> p.name
302
314
  => "AppName"
303
315
  ```
304
316
 
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|
@@ -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,19 +129,98 @@ 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
142
 
143
+ def deep_links
144
+ intent_filters(search: :deep_links)
145
+ end
146
+
147
+ def schemes
148
+ intent_filters(search: :schemes)
149
+ end
150
+
151
+ private
152
+
153
+ def intent_filters(search: nil)
154
+ activities.each_with_object([]) do |activity, obj|
155
+ intent_filters = activity.intent_filter
156
+ next if intent_filters&.empty?
157
+
158
+ if search.nil? || search.empty?
159
+ obj << intent_filters
160
+ else
161
+ intent_filters.each do |filter|
162
+ exist_method = "#{search}?".to_sym
163
+ next if filter.respond_to?(exist_method) && !filter.send(exist_method)
164
+
165
+ obj << filter.send(search)
166
+ end
167
+ end
168
+ end.flatten.uniq
169
+ end
170
+
171
+ # :nodoc:
143
172
  # Workaround ruby always return true by called `Object.const_defined?(Data)`
144
173
  class Data < Node; end
174
+
175
+ class IntentFilter < Node
176
+ # filter types (action is required, category and data are optional)
177
+ TYPES = %w[action category data].freeze
178
+
179
+ DEEP_LINK_SCHEMES = %w[http https].freeze
180
+
181
+ # browsable of category
182
+ CATEGORY_BROWSABLE = 'android.intent.category.BROWSABLE'
183
+
184
+ def deep_links?
185
+ browsable? && data.any? { |d| DEEP_LINK_SCHEMES.include?(d.scheme) }
186
+ end
187
+
188
+ def deep_links
189
+ return unless deep_links?
190
+
191
+ data.reject { |d| d.host.nil? }
192
+ .map(&:host)
193
+ .uniq
194
+ end
195
+
196
+ def schemes
197
+ return unless schemes?
198
+
199
+ data.select { |d| !d.scheme.nil? && !DEEP_LINK_SCHEMES.include?(d.scheme) }
200
+ .map(&:scheme)
201
+ .uniq
202
+ end
203
+
204
+ def schemes?
205
+ browsable? && data.any? { |d| !DEEP_LINK_SCHEMES.include?(d.scheme) }
206
+ end
207
+
208
+ def browsable?
209
+ exist?(CATEGORY_BROWSABLE)
210
+ end
211
+
212
+ def exist?(name, type: nil)
213
+ if type.to_s.empty? && !name.start_with?('android.intent.')
214
+ raise 'Fill type or use correct name'
215
+ end
216
+
217
+ type ||= name.split('.')[2]
218
+ raise 'Not found type' unless TYPES.include?(type)
219
+
220
+ values = send(type.to_sym).select { |e| e.name == name }
221
+ values.empty? ? false : values
222
+ end
223
+ end
145
224
  end
146
225
  end
147
226
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppInfo
4
- VERSION = '2.7.0.beta2'
4
+ VERSION = '2.8.1'
5
5
  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.7.0.beta2
4
+ version: 2.8.1
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-29 00:00:00.000000000 Z
11
+ date: 2021-12-20 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: