app-info 2.0.0.beta3 → 2.0.0.beta4

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: 70d4913abdb1ced1404730f117fda0fb82ed91d19e291659749d6cb8c50da8e7
4
- data.tar.gz: 5a9f1b8d786a08e552ae334679639575c1d7fd462d0f2ad6f970b0988b70e028
3
+ metadata.gz: 5d706f0c25f15d80690f57b9315fd3e2e1a08f4288d591a300d5d0d5a8a134f4
4
+ data.tar.gz: 4259e76abf048e403f43ef99caa543b6f89ec4922f19188625b075d11786efa4
5
5
  SHA512:
6
- metadata.gz: 825bb3d01e2e05ac8dce27a343d4329673ee358bcd1dada568c72bf21b1469bfeb66d7cec31de3d2407634e64af1ad6bcc2b2d2bc5ddd314b17d61592e683380
7
- data.tar.gz: 12a2f90a839ee938b29832272ca1410e0071d852f381353bff3e14f753f2946a108b6e90c04070f89e8966fe5e0cf75b80e42aa44ba735816c8c79ce8c04e55e
6
+ metadata.gz: 9d67414e33f673066bfe14b277388a29eae8049b946c94a1e2a344e6ed5e992a7d05004140c7c58460074583e5811b3b064a1b8e37f6bb36c2ce8f6f04f02641
7
+ data.tar.gz: 0a052dfd02187fcd03930359b1ecfcf840e75d881eb8687f84d607c047e36b26d0c169f55992f4649ba09b86f56790f33679e3df8625acfb8713db284625533f
@@ -9,16 +9,17 @@ 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
- ### Added
13
-
14
- - Added .dSYM.zip format support
15
- - Added parse mobileprovision in Linux
16
- - Added `AppInfo.file_type` to detect file type
17
-
18
12
  ### Changed
19
13
 
14
+ - Remove `Parser` module to reduce namespace. #[13](https://github.com/icyleaf/app-info/issues/13)
20
15
  - Use parse Macho-O header and contents to detect file type instead of file extension name.
21
- - Dropped Ruby 2.2 and below versions support
16
+ - Dropped Ruby 2.2 and below versions support.
17
+
18
+ ### Added
19
+
20
+ - Added .dSYM.zip format support. #[8](https://github.com/icyleaf/app-info/issues/8)
21
+ - Added parse mobileprovision in Linux. #[10](https://github.com/icyleaf/app_info/pull/10)
22
+ - Added `AppInfo.file_type` to detect file type.
22
23
 
23
24
  ## [1.1.2] (2019-09-19)
24
25
 
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # app_info
2
2
 
3
+ [![Language](https://img.shields.io/badge/ruby-2.3+-701516.svg)](.travis.yml)
3
4
  [![Build Status](https://travis-ci.org/icyleaf/app_info.svg?branch=master)](https://travis-ci.org/icyleaf/app_info)
4
5
  [![Gem version](https://img.shields.io/gem/v/app-info.svg?style=flat)](https://rubygems.org/gems/app_info)
5
6
  [![License](https://img.shields.io/badge/license-MIT-red.svg?style=flat)](LICENSE)
@@ -45,16 +46,15 @@ require 'app-info'
45
46
  parser = AppInfo.parse('iphone.ipa')
46
47
  parser = AppInfo.parse('ipad.ipa')
47
48
  parser = AppInfo.parse('android.apk')
48
- parser = AppInfo.parse('App/Info.plist')
49
- parser = AppInfo.parse('provisioning_profile/uuid.mobileprovision')
49
+ parser = AppInfo.parse('u-u-i-d.mobileprovision')
50
50
  parser = AppInfo.parse('App.dSYm.zip')
51
51
 
52
52
  # If detect file type failed, you can parse in other way
53
- parser = AppInfo::Parser::IPA.new('iphone.ipa')
54
- parser = AppInfo::Parser::IPA.new('android.apk')
55
- parser = AppInfo::Parser::InfoPlist.new('App/Info.plist')
56
- parser = AppInfo::Parser::MobileProvision.new('provisioning_profile/uuid.mobileprovision')
57
- parser = AppInfo::Parser::DSYM.new('App.dSYm.zip')
53
+ parser = AppInfo::IPA.new('iphone.ipa')
54
+ parser = AppInfo::IPA.new('android.apk')
55
+ parser = AppInfo::InfoPlist.new('App/Info.plist')
56
+ parser = AppInfo::MobileProvision.new('provisioning_profile/uuid.mobileprovision')
57
+ parser = AppInfo::DSYM.new('App.dSYm.zip')
58
58
  ```
59
59
 
60
60
  ### iOS
@@ -1,23 +1,33 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  require 'app_info/version'
4
- require 'app_info/parser'
5
- require 'zip'
3
+ require 'app_info/ipa'
4
+ require 'app_info/ipa/info_plist'
5
+ require 'app_info/ipa/mobile_provision'
6
+ require 'app_info/apk'
7
+ require 'app_info/dsym'
6
8
 
7
9
  # AppInfo Module
8
10
  module AppInfo
9
- class NotFoundError < StandardError; end
10
- class UnkownFileTypeError < StandardError; end
11
+ class Error < StandardError; end
12
+ class NotFoundError < Error; end
13
+ class UnkownFileTypeError < Error; end
14
+
15
+ # App Platform
16
+ module Platform
17
+ IOS = 'iOS'
18
+ ANDROID = 'Android'
19
+ DSYM = 'dSYM'
20
+ end
11
21
 
12
22
  # Get a new parser for automatic
13
23
  def self.parse(file)
14
24
  raise NotFoundError, file unless File.exist?(file)
15
25
 
16
26
  case file_type(file)
17
- when :ipa then Parser::IPA.new(file)
18
- when :apk then Parser::APK.new(file)
19
- when :mobileprovision then Parser::MobileProvision.new(file)
20
- when :dsym then Parser::DSYM.new(file)
27
+ when :ipa then IPA.new(file)
28
+ when :apk then APK.new(file)
29
+ when :mobileprovision then MobileProvision.new(file)
30
+ when :dsym then DSYM.new(file)
21
31
  else
22
32
  raise UnkownFileTypeError, "Sorry, AppInfo can not detect file type: #{file}"
23
33
  end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby_apk'
4
+ require 'image_size'
5
+ require 'app_info/util'
6
+
7
+ module AppInfo
8
+ # Parse APK file
9
+ class APK
10
+ attr_reader :file, :apk
11
+
12
+ # APK Devices
13
+ module Device
14
+ PHONE = 'Phone'
15
+ TABLET = 'Tablet'
16
+ WATCH = 'Watch'
17
+ TV = 'Television'
18
+ end
19
+
20
+ def initialize(file)
21
+ @file = file
22
+
23
+ Zip.warn_invalid_date = false # fix invaild date format warnings
24
+ @apk = ::Android::Apk.new(file)
25
+ end
26
+
27
+ def size(humanable = false)
28
+ AppInfo::Util.file_size(@file, humanable)
29
+ end
30
+
31
+ def os
32
+ AppInfo::Platform::ANDROID
33
+ end
34
+ alias file_type os
35
+
36
+ def build_version
37
+ manifest.version_code.to_s
38
+ end
39
+
40
+ def release_version
41
+ manifest.version_name
42
+ end
43
+
44
+ def name
45
+ resource.find('@string/app_name')
46
+ end
47
+
48
+ def bundle_id
49
+ manifest.package_name
50
+ end
51
+ alias identifier bundle_id
52
+ alias package_name bundle_id
53
+
54
+ def device_type
55
+ if wear?
56
+ Device::WATCH
57
+ elsif tv?
58
+ Device::TV
59
+ else
60
+ Device::PHONE
61
+ end
62
+ end
63
+
64
+ # TODO: find a way to detect
65
+ # def tablet?
66
+ # resource
67
+ # end
68
+
69
+ def wear?
70
+ use_features.include?('android.hardware.type.watch')
71
+ end
72
+
73
+ def tv?
74
+ use_features.include?('android.software.leanback')
75
+ end
76
+
77
+ def min_sdk_version
78
+ manifest.min_sdk_ver
79
+ end
80
+
81
+ def target_sdk_version
82
+ manifest.doc
83
+ .elements['/manifest/uses-sdk']
84
+ .attributes['targetSdkVersion']
85
+ .to_i
86
+ end
87
+
88
+ def use_permissions
89
+ manifest.use_permissions
90
+ end
91
+
92
+ def use_features
93
+ manifest_values('/manifest/uses-feature')
94
+ end
95
+
96
+ def signs
97
+ @apk.signs.each_with_object([]) do |(path, sign), obj|
98
+ obj << Sign.new(path, sign)
99
+ end
100
+ end
101
+
102
+ def certificates
103
+ @apk.certificates.each_with_object([]) do |(path, certificate), obj|
104
+ obj << Certificate.new(path, certificate)
105
+ end
106
+ end
107
+
108
+ def activities
109
+ components.select { |c| c.type == 'activity' }
110
+ end
111
+
112
+ def services
113
+ components.select { |c| c.type == 'service' }
114
+ end
115
+
116
+ def components
117
+ manifest.components
118
+ end
119
+
120
+ def manifest
121
+ @apk.manifest
122
+ end
123
+
124
+ def resource
125
+ @apk.resource
126
+ end
127
+
128
+ def dex
129
+ @apk.dex
130
+ end
131
+
132
+ def icons
133
+ unless @icons
134
+ tmp_path = File.join(Dir.mktmpdir, "AppInfo-android-#{SecureRandom.hex}")
135
+
136
+ @icons = @apk.icon.each_with_object([]) do |(path, data), obj|
137
+ icon_name = File.basename(path)
138
+ icon_path = File.join(tmp_path, File.path(path))
139
+ icon_file = File.join(icon_path, icon_name)
140
+ FileUtils.mkdir_p icon_path
141
+ File.open(icon_file, 'w') do |f|
142
+ f.write data
143
+ end
144
+
145
+ obj << {
146
+ name: icon_name,
147
+ file: icon_file,
148
+ dimensions: ImageSize.path(icon_file).size
149
+ }
150
+ end
151
+ end
152
+
153
+ @icons
154
+ end
155
+
156
+ private
157
+
158
+ def manifest_values(path, key = 'name')
159
+ values = []
160
+ manifest.doc.each_element(path) do |elem|
161
+ values << elem.attributes[key]
162
+ end
163
+ values.uniq
164
+ end
165
+
166
+ # Android Certificate
167
+ class Certificate
168
+ attr_reader :path, :certificate
169
+ def initialize(path, certificate)
170
+ @path = path
171
+ @certificate = certificate
172
+ end
173
+ end
174
+
175
+ # Android Sign
176
+ class Sign
177
+ attr_reader :path, :sign
178
+ def initialize(path, sign)
179
+ @path = path
180
+ @sign = sign
181
+ end
182
+ end
183
+ end
184
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AppInfo
2
4
  # Monkey Patch for Object
3
5
  module Tryable
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true`
2
+
3
+ require 'zip'
4
+ require 'macho'
5
+ require 'app_info/core_ext/object/try'
6
+
7
+ module AppInfo
8
+ # DSYM parser
9
+ class DSYM
10
+ attr_reader :file
11
+
12
+ def initialize(file)
13
+ @file = file
14
+ end
15
+
16
+ def file_type
17
+ AppInfo::Platform::DSYM
18
+ end
19
+
20
+ def object
21
+ @object ||= File.basename(app_path)
22
+ end
23
+
24
+ def macho_type
25
+ @macho_type ||= ::MachO.open(app_path)
26
+ end
27
+
28
+ def machos
29
+ @machos ||= case macho_type
30
+ when ::MachO::MachOFile
31
+ [MachO.new(macho_type, File.size(app_path))]
32
+ else
33
+ size = macho_type.fat_archs.each_with_object([]) do |arch, obj|
34
+ obj << arch.size
35
+ end
36
+
37
+ machos = []
38
+ macho_type.machos.each_with_index do |file, i|
39
+ machos << MachO.new(file, size[i])
40
+ end
41
+ machos
42
+ end
43
+ end
44
+
45
+ def release_version
46
+ info.try(:[], 'CFBundleShortVersionString')
47
+ end
48
+
49
+ def build_version
50
+ info.try(:[], 'CFBundleVersion')
51
+ end
52
+
53
+ def identifier
54
+ info.try(:[], 'CFBundleIdentifier').sub('com.apple.xcode.dsym.', '')
55
+ end
56
+ alias bundle_id identifier
57
+
58
+ def info
59
+ return nil unless File.exist?(info_path)
60
+
61
+ @info ||= CFPropertyList.native_types(CFPropertyList::List.new(file: info_path).value)
62
+ end
63
+
64
+ def info_path
65
+ @info_path ||= File.join(contents, 'Contents', 'Info.plist')
66
+ end
67
+
68
+ def app_path
69
+ unless @app_path
70
+ path = File.join(contents, 'Contents', 'Resources', 'DWARF')
71
+ name = Dir.entries(path).last
72
+ @app_path = File.join(path, name)
73
+ end
74
+
75
+ @app_path
76
+ end
77
+
78
+ private
79
+
80
+ def contents
81
+ unless @contents
82
+ if File.directory?(@file)
83
+ @contents = @file
84
+ else
85
+ @contents = "#{Dir.mktmpdir}/AppInfo-dsym-#{SecureRandom.hex}"
86
+ dsym_dir = nil
87
+ Zip::File.open(@file) do |zip_file|
88
+ zip_file.each do |f|
89
+ dsym_dir ||= f.name
90
+
91
+ f_path = File.join(@contents, f.name)
92
+ zip_file.extract(f, f_path) unless File.exist?(f_path)
93
+ end
94
+ end
95
+
96
+ @contents = File.join(@contents, dsym_dir)
97
+ end
98
+ end
99
+
100
+ @contents
101
+ end
102
+
103
+ # DSYM Mach-O
104
+ class MachO
105
+ def initialize(file, size = 0)
106
+ @file = file
107
+ @size = size
108
+ end
109
+
110
+ def cpu_name
111
+ @file.cpusubtype
112
+ end
113
+
114
+ def cpu_type
115
+ @file.cputype
116
+ end
117
+
118
+ def type
119
+ @file.filetype
120
+ end
121
+
122
+ def size(humanable = false)
123
+ return Util.size_to_humanable(@size) if humanable
124
+
125
+ @size
126
+ end
127
+
128
+ def uuid
129
+ @file[:LC_UUID][0].uuid_string
130
+ end
131
+ alias debug_id uuid
132
+
133
+ def header
134
+ @header ||= @file.header
135
+ end
136
+
137
+ def to_h
138
+ {
139
+ uuid: uuid,
140
+ type: type,
141
+ cpu_name: cpu_name,
142
+ cpu_type: cpu_type,
143
+ size: size,
144
+ humanable_size: size(true)
145
+ }
146
+ end
147
+ end
148
+ end
149
+ end