app-info 2.0.0.beta3 → 2.0.0.beta4

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: 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