app-info 3.1.4 → 3.2.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: 678ea8ec8c58efc66f4937194709f72b81221613ba7da6c4db367e8e619b4fa9
4
- data.tar.gz: c8dffdd539e078ebc81de5f7335f9858a28a6373b3603cb47301174de69feb30
3
+ metadata.gz: 114f4899c399d6a4b8091b798a6089538b157eccba40c428ae36e445f79191d6
4
+ data.tar.gz: 872061f173786d61f2dbad70a25405b71fc2b054ea023fb375394aed52febeeb
5
5
  SHA512:
6
- metadata.gz: d270d7c5fb948109da2aca484479cfaf6d4acc629598dc9199b794286a600235dba5bcbb5205c52671dbecabe8ee0b9917f8dbf1389903ff9951baf673836ec3
7
- data.tar.gz: b91a9932a126c6af47db8310df78c0c3d1f9c4ff3224c4764b54e1b29cd59b4286fe2533c03499bf814227cd528b0b00ffdc739282f4605829bf23d71029e27e
6
+ metadata.gz: 435e4ce4855c42b94a5ef6a9bd12e208765691ad4d2ba1f0da92eb251e6fe12ed9f9aaa95ec8ba5fd3f53b1b4ff664fb8e8a1764b32992c5c0be220e51344ce1
7
+ data.tar.gz: 376b5e7ac14d0fa8a95d0bd0a6d2861532e937317ed3c6a1cea07bc3ebc7a4ac2b84b8648180a9ae298768e3b7e90335a055bf344a2a2f933a2106b2f853bb31
@@ -8,15 +8,35 @@ on:
8
8
  pull_request:
9
9
 
10
10
  jobs:
11
+ linting:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Setup Ruby 3.x
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: 3
21
+ bundler-cache: true
22
+
23
+ - name: Rubocop
24
+ run: bundle exec rubocop --format progress
25
+
11
26
  test:
27
+ needs: [ linting ]
28
+ name: test ${{ matrix.ruby }}
29
+ runs-on: ubuntu-latest
12
30
  strategy:
13
31
  fail-fast: false
14
32
  matrix:
15
33
  ruby: [ ruby-3.1, ruby-3.2, ruby-3.3 ]
16
- os: [ ubuntu-latest ]
17
-
18
- runs-on: ${{ matrix.os }}
19
-
34
+ experimental: [false]
35
+ include:
36
+ - ruby: head
37
+ experimental: true
38
+ - ruby: truffleruby-head
39
+ experimental: true
20
40
  steps:
21
41
  - uses: actions/checkout@v4
22
42
 
@@ -25,5 +45,6 @@ jobs:
25
45
  ruby-version: ${{ matrix.ruby }}
26
46
  bundler-cache: true
27
47
 
28
- - name: bundle exec rake
29
- run: bundle exec rake
48
+ - name: RSpec
49
+ continue-on-error: ${{ matrix.experimental }}
50
+ run: bundle exec rspec
data/CHANGELOG.md CHANGED
@@ -9,6 +9,12 @@ 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
+ ## [3.2.0] (2024-09-09)
13
+
14
+ ### Added
15
+
16
+ - Add HarmonyOS app support (basic). #[76](https://github.com/icyleaf/app-info/pull/76) Many thanks to @[InjoyDeng](https://github.com/InjoyDeng)
17
+
12
18
  ## [3.1.4] (2024-06-27)
13
19
 
14
20
  ### Added
@@ -355,7 +361,8 @@ Dropped Ruby 2.5 ~ 3.0 support (no changes required.).
355
361
 
356
362
  - Updated dependency of CFPropertly list be a range between 2.3.4. (thanks @[cschroed](https://github.com/cschroed))
357
363
 
358
- [Unreleased]: https://github.com/icyleaf/app-info/compare/v3.1.4..HEAD
364
+ [Unreleased]: https://github.com/icyleaf/app-info/compare/v3.2.0..HEAD
365
+ [3.2.0]: https://github.com/icyleaf/app-info/compare/v3.1.4...v3.2.0
359
366
  [3.1.4]: https://github.com/icyleaf/app-info/compare/v3.1.2...v3.1.4
360
367
  [3.1.2]: https://github.com/icyleaf/app-info/compare/v3.1.0...v3.1.2
361
368
  [3.1.0]: https://github.com/icyleaf/app-info/compare/v3.0.0...v3.1.0
data/README.md CHANGED
@@ -5,7 +5,8 @@
5
5
  [![Build Status](https://img.shields.io/github/actions/workflow/status/icyleaf/app_info/ci.yml)](https://github.com/icyleaf/app_info/actions/workflows/ci.yml)
6
6
  [![License](https://img.shields.io/github/license/icyleaf/app-info)](LICENSE)
7
7
 
8
- Teardown tool for mobile app (ipa, apk and aab file), macOS app, dSYM.zip file and Windows PE file.
8
+ Teardown tool for mobile app (iOS: ipa, Android: apk/aab, HarmonyOS: .hap/.app file), macOS app, dSYM.zip file and Windows PE file.
9
+
9
10
  Analysis metedata like version, name, icon etc.
10
11
 
11
12
  ## Support
@@ -17,6 +18,9 @@ Analysis metedata like version, name, icon etc.
17
18
  - `.ipa`
18
19
  - `Info.plist` file
19
20
  - `.mobileprovision`/`.provisionprofile` file
21
+ - HarmonyOS file (basic)
22
+ - `.hap`
23
+ - `.app`
20
24
  - macOS App file (archived by starnd pkzip format)
21
25
  - `.app.zip`
22
26
  - dSYMs file (archived by starnd pkzip format)
@@ -246,6 +250,30 @@ android.signatures
246
250
  # => [...]
247
251
  ```
248
252
 
253
+ ### HarmonyOS
254
+
255
+ Accept `.hap` and `.app` HarmonyOS file. Only metabase, except resources mapping.
256
+
257
+ ```ruby
258
+ hap = AppInfo.parse('app.hap')
259
+
260
+ # get app file size
261
+ android.size
262
+ # => 2013213
263
+
264
+ # get app file size in human reable.
265
+ android.size(human_size: true)
266
+ # => 21 MB
267
+
268
+ # get app release version
269
+ android.release_version
270
+ # => 1.0
271
+
272
+ # get app package name
273
+ android.bundle_id
274
+ # => com.icyleaf.AppInfoDemo
275
+ ```
276
+
249
277
  ### macOS
250
278
 
251
279
  Only accept zipped macOS file.
data/app_info.gemspec CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
10
10
  spec.authors = ['icyleaf']
11
11
  spec.email = ['icyleaf.cn@gmail.com']
12
12
 
13
- spec.summary = 'Teardown tool for mobile app(ipa/apk) and dSYM file, analysis metedata like version, name, icon'
14
- spec.description = 'Teardown tool for ipa/apk files and dSYM file, even support for info.plist and .mobileprovision files'
13
+ spec.summary = 'Teardown tool for all most app, analysis metedata like version, name, icon'
14
+ spec.description = 'Teardown tool for ipa, apk, aab, hap mobile files and Windows, macOS and dSYM file, even support for info.plist and .mobileprovision files'
15
15
  spec.homepage = 'http://github.com/icyleaf/app-info'
16
16
  spec.license = 'MIT'
17
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
@@ -34,14 +34,4 @@ Gem::Specification.new do |spec|
34
34
 
35
35
  spec.add_development_dependency 'bundler', '>= 1.12'
36
36
  spec.add_development_dependency 'rake', '>= 10.0'
37
-
38
- spec.post_install_message = <<~ENDBANNER
39
- AppInfo 3.0 was out!
40
- **********************
41
- The public API of some AppInfo classes has been changed.
42
-
43
- Please ensure that your Gemfiles and .gemspecs are suitably restrictive
44
- to avoid an unexpected breakage when 3.0 is released (e.g. ~> 2.8.5).
45
- See https://github.com/icyleaf/app_info for details.
46
- ENDBANNER
47
37
  end
@@ -36,15 +36,15 @@ module AppInfo
36
36
  # @return [Symbol] {Device}
37
37
  def device
38
38
  if watch?
39
- Device::WATCH
39
+ Device::Google::WATCH
40
40
  elsif television?
41
- Device::TELEVISION
41
+ Device::Google::TELEVISION
42
42
  elsif automotive?
43
- Device::AUTOMOTIVE
43
+ Device::Google::AUTOMOTIVE
44
44
  elsif tablet?
45
- Device::TABLET
45
+ Device::Google::TABLET
46
46
  else
47
- Device::PHONE
47
+ Device::Google::PHONE
48
48
  end
49
49
  end
50
50
 
@@ -23,6 +23,11 @@ module AppInfo
23
23
  AAB = :aab
24
24
  PROGUARD = :proguard
25
25
 
26
+ # HarmonyOS
27
+
28
+ HAP = :hap
29
+ HAPP = :app
30
+
26
31
  # Windows
27
32
 
28
33
  PE = :pe
@@ -35,6 +40,7 @@ module AppInfo
35
40
  APPLE = :apple
36
41
  GOOGLE = :google
37
42
  MICROSOFT = :microsoft
43
+ HUAWEI = :huawei
38
44
  end
39
45
 
40
46
  # Platform
@@ -44,36 +50,110 @@ module AppInfo
44
50
  ANDROID = :android
45
51
  APPLETV = :appletv
46
52
  WINDOWS = :windows
53
+ HARMONYOS = :harmonyos
47
54
  end
48
55
 
49
- # Apple Device Type
56
+ # Device Type
50
57
  module Device
58
+ module Apple
59
+ # macOS
60
+ MACOS = :macos
61
+
62
+ # Apple iPhone
63
+ IPHONE = :iphone
64
+ # Apple iPad
65
+ IPAD = :ipad
66
+ # Apple Universal (iPhone and iPad)
67
+ UNIVERSAL = :universal
68
+ # Apple TV
69
+ APPLETV = :appletv
70
+ # Apple Watch (TODO: not implemented yet)
71
+ IWATCH = :iwatch
72
+ end
73
+
74
+ module Google
75
+ # Android Phone
76
+ PHONE = :phone
77
+ # Android Tablet (TODO: not implemented yet)
78
+ TABLET = :tablet
79
+ # Android Watch
80
+ WATCH = :watch
81
+ # Android TV
82
+ TELEVISION = :television
83
+ # Android Car Automotive
84
+ AUTOMOTIVE = :automotive
85
+ end
86
+
87
+ module Huawei
88
+ # HarmonyOS Default
89
+ DEFAULT = :default
90
+ # HarmonyOS Phone
91
+ PHONE = :phone
92
+ # HarmonyOS Tablet
93
+ TABLET = :tablet
94
+ # HarmonyOS TV
95
+ TV = :tv
96
+ # HarmonyOS wearable
97
+ WEARABLE = :wearable
98
+ # HarmonyOS Car
99
+ CAR = :car
100
+ # HarmonyOS 2-in-1 tablet and laptop
101
+ TWO_IN_ONE = :two_in_one
102
+ end
103
+
104
+ module Microsoft
105
+ # Windows
106
+ WINDOWS = :windows
107
+ end
108
+
109
+ # legacy consts
110
+
51
111
  # macOS
112
+ # @deprecated Use {Device::Apple#MACOS} instead, this method will remove in 3.3.0.
52
113
  MACOS = :macos
53
114
 
54
115
  # Apple iPhone
116
+ # @deprecated Use {Device::Apple#IPHONE} instead, this method will remove in 3.3.0.
55
117
  IPHONE = :iphone
118
+
56
119
  # Apple iPad
120
+ # @deprecated Use {Device::Apple#IPAD} instead, this method will remove in 3.3.0.
57
121
  IPAD = :ipad
122
+
58
123
  # Apple Universal (iPhone and iPad)
124
+ # @deprecated Use {Device::Apple#UNIVERSAL} instead, this method will remove in 3.3.0.
59
125
  UNIVERSAL = :universal
126
+
60
127
  # Apple TV
128
+ # @deprecated Use {Device::Apple#APPLETV} instead, this method will remove in 3.3.0.
61
129
  APPLETV = :appletv
130
+
62
131
  # Apple Watch (TODO: not implemented yet)
132
+ # @deprecated Use {Device::Apple#IWATCH} instead, this method will remove in 3.3.0.
63
133
  IWATCH = :iwatch
64
134
 
65
135
  # Android Phone
136
+ # @deprecated Use {Device::Google#PHONE} instead, this method will remove in 3.3.0.
66
137
  PHONE = :phone
138
+
67
139
  # Android Tablet (TODO: not implemented yet)
140
+ # @deprecated Use {Device::Google#TABLET} instead, this method will remove in 3.3.0.
68
141
  TABLET = :tablet
142
+
69
143
  # Android Watch
144
+ # @deprecated Use {Device::Google#WATCH} instead, this method will remove in 3.3.0.
70
145
  WATCH = :watch
146
+
71
147
  # Android TV
148
+ # @deprecated Use {Device::Google#TELEVISION} instead, this method will remove in 3.3.0.
72
149
  TELEVISION = :television
150
+
73
151
  # Android Car Automotive
152
+ # @deprecated Use {Device::Google#AUTOMOTIVE} instead, this method will remove in 3.3.0.
74
153
  AUTOMOTIVE = :automotive
75
154
 
76
155
  # Windows
156
+ # @deprecated Use {Device::Microsoft#WINDOWS} instead, this method will remove in 3.3.0.
77
157
  WINDOWS = :windows
78
158
  end
79
159
  end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppInfo
4
+ # Parse HAP file parser
5
+ class HAP < HarmonyOS
6
+ # Full icons metadata
7
+ # @example
8
+ # ipa.icons
9
+ # # => [
10
+ # # {
11
+ # # name: 'icon.png',
12
+ # # file: '/path/to/icon.png',
13
+ # # uncrushed_file: '/path/to/uncrushed_icon.png',
14
+ # # dimensions: [64, 64]
15
+ # # },
16
+ # # {
17
+ # # name: 'icon1.png',
18
+ # # file: '/path/to/icon1.png',
19
+ # # uncrushed_file: '/path/to/uncrushed_icon1.png',
20
+ # # dimensions: [120, 120]
21
+ # # }
22
+ # # ]
23
+ # @return [Array<Hash{Symbol => String, Array<Integer>}>] icons paths of icons
24
+ def icons
25
+ @icons ||= icons_path.each_with_object([]) do |file, obj|
26
+ obj << {
27
+ name: ::File.basename(file),
28
+ file: file,
29
+ uncrushed_file: file,
30
+ dimensions: ImageSize.path(file).size
31
+ }
32
+ end
33
+ end
34
+
35
+ # @return [Array<String>]
36
+ def icons_path
37
+ @icons_path ||= [::File.join(contents, 'resources', 'base', 'media', 'app_icon.png')]
38
+ end
39
+
40
+ # @return [JSON]
41
+ def module_info
42
+ @module_info ||= JSON.parse(::File.read(module_info_path))
43
+ end
44
+
45
+ # @return [String]
46
+ def module_info_path
47
+ @module_info_path ||= ::File.join(contents, 'module.json')
48
+ end
49
+
50
+ # @return [String]
51
+ def name
52
+ # TODO: The application display name should be determined by looking up
53
+ # the value of the variable named in the "label" field of the "module.json"
54
+ # file within the "resources.index" file.
55
+ pack_info.bundle_name
56
+ end
57
+
58
+ def clear!
59
+ return unless @contents
60
+
61
+ FileUtils.rm_rf(@contents)
62
+
63
+ @pack_info = nil
64
+ @info_path = nil
65
+ @contents = nil
66
+
67
+ @module_info_path = nil
68
+ @module_info = nil
69
+ @icons_path = nil
70
+ @icons = nil
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppInfo
4
+ # parser for HarmonyOS .APP file
5
+ class HAPP < HarmonyOS
6
+ def_delegators :default_entry, :icons
7
+ # @return [HAP]
8
+ def default_entry
9
+ hap_path = ::File.join(contents, "#{default_entry_name}.hap")
10
+ @default_entry ||= HAP.new(hap_path)
11
+ end
12
+
13
+ # @return [String]
14
+ def default_entry_name
15
+ return @default_entry_name if @default_entry_name
16
+
17
+ pack_info.packages.each do |package|
18
+ if package['moduleType'] == 'entry' && package['deliveryWithInstall']
19
+ @default_entry_name ||= package['name']
20
+ break
21
+ end
22
+ end
23
+ @default_entry_name
24
+ end
25
+
26
+ # @return [String]
27
+ def name
28
+ default_entry.name
29
+ end
30
+
31
+ def clear!
32
+ return unless @contents
33
+
34
+ FileUtils.rm_rf(@contents)
35
+
36
+ @pack_info = nil
37
+ @info_path = nil
38
+ @contents = nil
39
+
40
+ @default_entry_name = nil
41
+ @default_entry&.clear!
42
+
43
+ @default_entry = nil
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppInfo
4
+ # HarmonyOS base parser for hap and app file
5
+ class HarmonyOS < File
6
+ extend Forwardable
7
+ include Helper::HumanFileSize
8
+ include Helper::Archive
9
+
10
+ def_delegators :pack_info, :build_version, :release_version, :bundle_id
11
+
12
+ # return file size
13
+ # @example Read file size in integer
14
+ # aab.size # => 3618865
15
+ #
16
+ # @example Read file size in human readabale
17
+ # aab.size(human_size: true) # => '3.45 MB'
18
+ #
19
+ # @param [Boolean] human_size Convert integer value to human readable.
20
+ # @return [Integer, String]
21
+ def size(human_size: false)
22
+ file_to_human_size(@file, human_size: human_size)
23
+ end
24
+
25
+ # @return [Symbol] {Manufacturer}
26
+ def manufacturer
27
+ Manufacturer::HUAWEI
28
+ end
29
+
30
+ # @return [Symbol] {Platform}
31
+ def platform
32
+ Platform::HARMONYOS
33
+ end
34
+
35
+ # @return [Symbol] {Device}
36
+ def device
37
+ Device::Huawei::DEFAULT
38
+ end
39
+
40
+ # @return [PackInfo]
41
+ def pack_info
42
+ @pack_info ||= PackInfo.new(info_path)
43
+ end
44
+
45
+ # @return [String]
46
+ def info_path
47
+ @info_path ||= ::File.join(contents, 'pack.info')
48
+ end
49
+
50
+ # @return [String] unzipped file path
51
+ def contents
52
+ @contents ||= unarchive(@file, prefix: format.to_s)
53
+ end
54
+
55
+ # @abstract Subclass and override {#name} to implement.
56
+ def name
57
+ not_implemented_error!(__method__)
58
+ end
59
+
60
+ # @abstract Subclass and override {#clear!} to implement.
61
+ def clear!
62
+ not_implemented_error!(__method__)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppInfo::Helper
4
+ module FileTypeDetection
5
+ # Detect file type by reading file header
6
+ #
7
+ # TODO: This can be better solution, if anyone knows, tell me please.
8
+ def file_type(file)
9
+ header_hex = ::File.read(file, 100)
10
+ case header_hex
11
+ when ZIP_RETGEX
12
+ detect_zip_file(file)
13
+ when PE_REGEX
14
+ AppInfo::Format::PE
15
+ when PLIST_REGEX, BPLIST_REGEX
16
+ AppInfo::Format::MOBILEPROVISION
17
+ else
18
+ AppInfo::Format::UNKNOWN
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ # Detect file type for zip files
25
+ def detect_zip_file(file)
26
+ Zip.warn_invalid_date = false
27
+ zip_file = Zip::File.open(file)
28
+
29
+ return AppInfo::Format::PROGUARD if proguard_clues?(zip_file)
30
+ return AppInfo::Format::APK if apk_clues?(zip_file)
31
+ return AppInfo::Format::AAB if aab_clues?(zip_file)
32
+ return AppInfo::Format::MACOS if macos_clues?(zip_file)
33
+ return AppInfo::Format::PE if pe_clues?(zip_file)
34
+ return AppInfo::Format::HAP if hap_clues?(zip_file)
35
+ return AppInfo::Format::HAPP if happ_clues?(zip_file)
36
+ return AppInfo::Format::UNKNOWN unless clue = other_clues?(zip_file)
37
+
38
+ clue
39
+ ensure
40
+ zip_file.close
41
+ end
42
+
43
+ # Check for Proguard clues in zip file
44
+ def proguard_clues?(zip_file)
45
+ !zip_file.glob('*mapping*.txt').empty?
46
+ end
47
+
48
+ # Check for APK clues in zip file
49
+ def apk_clues?(zip_file)
50
+ !zip_file.find_entry('AndroidManifest.xml').nil? &&
51
+ !zip_file.find_entry('classes.dex').nil?
52
+ end
53
+
54
+ # Check for AAB clues in zip file
55
+ def aab_clues?(zip_file)
56
+ !zip_file.find_entry('base/manifest/AndroidManifest.xml').nil? &&
57
+ !zip_file.find_entry('BundleConfig.pb').nil?
58
+ end
59
+
60
+ # Check for macOS clues in zip file
61
+ def macos_clues?(zip_file)
62
+ !zip_file.glob('*/Contents/MacOS/*').empty? &&
63
+ !zip_file.glob('*/Contents/Info.plist').empty?
64
+ end
65
+
66
+ # Check for PE clues in zip file
67
+ def pe_clues?(zip_file)
68
+ !zip_file.glob('*.exe').empty?
69
+ end
70
+
71
+ # Check for HAP clues in zip file
72
+ def hap_clues?(zip_file)
73
+ !zip_file.find_entry('pack.info').nil? && !zip_file.find_entry('module.json').nil?
74
+ end
75
+
76
+ # Check for HAPP clues in zip file
77
+ def happ_clues?(zip_file)
78
+ pack_info_count = 0
79
+ hap_count = 0
80
+
81
+ zip_file.each do |f|
82
+ path = f.name
83
+
84
+ if path == 'pack.info'
85
+ pack_info_count += 1
86
+ elsif path.end_with?('.hap')
87
+ hap_count += 1
88
+ else
89
+ return false
90
+ end
91
+ end
92
+
93
+ pack_info_count == 1 && hap_count >= 1
94
+ end
95
+
96
+ # Check for other clues in zip file
97
+ def other_clues?(zip_file)
98
+ zip_file.each do |f|
99
+ path = f.name
100
+
101
+ return AppInfo::Format::IPA if path.include?('Payload/') && path.end_with?('Info.plist')
102
+ return AppInfo::Format::DSYM if path.include?('Contents/Resources/DWARF/')
103
+ end
104
+ end
105
+
106
+ ZIP_RETGEX = /^\x50\x4b\x03\x04/.freeze
107
+ PE_REGEX = /^MZ/.freeze
108
+ PLIST_REGEX = /\x3C\x3F\x78\x6D\x6C/.freeze
109
+ BPLIST_REGEX = /^\x62\x70\x6C\x69\x73\x74/.freeze
110
+ end
111
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'app_info/helper/file_type_detection'
3
4
  require 'app_info/helper/archive'
4
5
  require 'app_info/helper/file_size'
5
6
  require 'app_info/helper/generate_class'
@@ -11,10 +11,10 @@ module AppInfo
11
11
 
12
12
  # Icon Key
13
13
  ICON_KEYS = {
14
- Device::IPHONE => ['CFBundleIcons'],
15
- Device::IPAD => ['CFBundleIcons~ipad'],
16
- Device::UNIVERSAL => ['CFBundleIcons', 'CFBundleIcons~ipad'],
17
- Device::MACOS => %w[CFBundleIconFile CFBundleIconName]
14
+ Device::Apple::IPHONE => ['CFBundleIcons'],
15
+ Device::Apple::IPAD => ['CFBundleIcons~ipad'],
16
+ Device::Apple::UNIVERSAL => ['CFBundleIcons', 'CFBundleIcons~ipad'],
17
+ Device::Apple::MACOS => %w[CFBundleIconFile CFBundleIconName]
18
18
  }.freeze
19
19
 
20
20
  # @return [Symbol] {Manufacturer}
@@ -25,11 +25,11 @@ module AppInfo
25
25
  # @return [Symbol] {Platform}
26
26
  def platform
27
27
  case device
28
- when Device::MACOS
28
+ when Device::Apple::MACOS
29
29
  Platform::MACOS
30
- when Device::IPHONE, Device::IPAD, Device::UNIVERSAL
30
+ when Device::Apple::IPHONE, Device::Apple::IPAD, Device::Apple::UNIVERSAL
31
31
  Platform::IOS
32
- when Device::APPLETV
32
+ when Device::Apple::APPLETV
33
33
  Platform::APPLETV
34
34
  end
35
35
  end
@@ -37,17 +37,17 @@ module AppInfo
37
37
  # @return [Symbol] {Device}
38
38
  def device
39
39
  if device_family == [1]
40
- Device::IPHONE
40
+ Device::Apple::IPHONE
41
41
  elsif device_family == [2]
42
- Device::IPAD
42
+ Device::Apple::IPAD
43
43
  elsif device_family == [1, 2]
44
- Device::UNIVERSAL
44
+ Device::Apple::UNIVERSAL
45
45
  elsif device_family == [3]
46
- Device::APPLETV
46
+ Device::Apple::APPLETV
47
47
  elsif device_family == [6]
48
- Device::APPMACOSLETV
48
+ Device::Apple::APPMACOSLETV
49
49
  elsif !info.try(:[], 'DTSDKName').nil? || !info.try(:[], 'DTManufacturerName').nil?
50
- Device::MACOS
50
+ Device::Apple::MACOS
51
51
  else
52
52
  raise NotImplementedError, "Unkonwn device: #{device_family}"
53
53
  end
@@ -113,27 +113,27 @@ module AppInfo
113
113
 
114
114
  # @return [Boolean]
115
115
  def iphone?
116
- device == Device::IPHONE
116
+ device == Device::Apple::IPHONE
117
117
  end
118
118
 
119
119
  # @return [Boolean]
120
120
  def ipad?
121
- device == Device::IPAD
121
+ device == Device::Apple::IPAD
122
122
  end
123
123
 
124
124
  # @return [Boolean]
125
125
  def universal?
126
- device == Device::UNIVERSAL
126
+ device == Device::Apple::UNIVERSAL
127
127
  end
128
128
 
129
129
  # @return [Boolean]
130
130
  def macos?
131
- device == Device::MACOS
131
+ device == Device::Apple::MACOS
132
132
  end
133
133
 
134
134
  # @return [Boolean]
135
135
  def appletv?
136
- device == Device::APPLETV
136
+ device == Device::Apple::APPLETV
137
137
  end
138
138
 
139
139
  # @return [Array<String>]
@@ -212,7 +212,7 @@ module AppInfo
212
212
 
213
213
  def app_path
214
214
  @app_path ||= case device
215
- when Device::MACOS
215
+ when Device::Apple::MACOS
216
216
  ::File.dirname(@file)
217
217
  else
218
218
  ::File.expand_path('../', @file)
data/lib/app_info/ipa.rb CHANGED
@@ -149,11 +149,11 @@ module AppInfo
149
149
 
150
150
  def icon_keys
151
151
  @icon_keys ||= case device
152
- when Device::IPHONE, Device::APPLETV
152
+ when Device::Apple::IPHONE, Device::Apple::APPLETV
153
153
  [IPHONE_KEY]
154
- when Device::IPAD
154
+ when Device::Apple::IPAD
155
155
  [IPAD_KEY]
156
- when Device::UNIVERSAL
156
+ when Device::Apple::UNIVERSAL
157
157
  [IPHONE_KEY, IPAD_KEY]
158
158
  end
159
159
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module AppInfo
6
+ # HarmonyOS pack.info parser
7
+ class PackInfo < File
8
+ # @return [String]
9
+ def version_code
10
+ app['version']['code']
11
+ end
12
+ alias build_version version_code
13
+
14
+ # @return [String]
15
+ def version_name
16
+ app['version']['name']
17
+ end
18
+ alias release_version version_name
19
+
20
+ # @return [String]
21
+ def bundle_name
22
+ app['bundleName']
23
+ end
24
+ alias bundle_id bundle_name
25
+
26
+ # @return [JSON]
27
+ def app
28
+ @app ||= summary['app']
29
+ end
30
+
31
+ # @return [Array<JSON>]
32
+ def modules
33
+ @modules ||= summary['modules']
34
+ end
35
+
36
+ # @return [JSON]
37
+ def summary
38
+ @summary ||= content['summary']
39
+ end
40
+
41
+ # @return [Array<JSON>]
42
+ def packages
43
+ @packages ||= content['packages']
44
+ end
45
+
46
+ # @return [JSON]
47
+ def content
48
+ JSON.parse(::File.read(@file))
49
+ end
50
+ end
51
+ end
data/lib/app_info/pe.rb CHANGED
@@ -36,7 +36,7 @@ module AppInfo
36
36
 
37
37
  # @return [Symbol] {Device}
38
38
  def device
39
- Device::WINDOWS
39
+ Device::Microsoft::WINDOWS
40
40
  end
41
41
 
42
42
  # return file size
@@ -189,7 +189,7 @@ module AppInfo
189
189
  def binary_file
190
190
  @binary_file ||= lambda {
191
191
  file_io = ::File.open(@file, 'rb')
192
- return @file unless file_io.read(100) =~ AppInfo::ZIP_RETGEX
192
+ return @file unless file_io.read(100) =~ Helper::FileTypeDetection::ZIP_RETGEX
193
193
 
194
194
  zip_file = Zip::File.open(@file)
195
195
  zip_entry = zip_file.glob('*.exe').first
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppInfo
4
- VERSION = '3.1.4'
4
+ VERSION = '3.2.0'
5
5
  end
data/lib/app_info.rb CHANGED
@@ -10,6 +10,7 @@ require 'app_info/error'
10
10
  require 'app_info/file'
11
11
  require 'app_info/info_plist'
12
12
  require 'app_info/mobile_provision'
13
+ require 'app_info/pack_info'
13
14
 
14
15
  require 'app_info/apple'
15
16
  require 'app_info/macos'
@@ -21,16 +22,22 @@ require 'app_info/android'
21
22
  require 'app_info/apk'
22
23
  require 'app_info/aab'
23
24
 
25
+ require 'app_info/harmonyos'
26
+ require 'app_info/happ'
27
+ require 'app_info/hap'
28
+
24
29
  require 'app_info/proguard'
25
30
  require 'app_info/dsym'
26
31
 
27
32
  require 'app_info/pe'
28
33
 
29
- # fix invaild date format warnings
34
+ # fix invalid date format warnings
30
35
  Zip.warn_invalid_date = false
31
36
 
32
37
  # AppInfo Module
33
38
  module AppInfo
39
+ extend Helper::FileTypeDetection
40
+
34
41
  class << self
35
42
  # Get a new parser for automatic
36
43
  def parse(file)
@@ -40,6 +47,8 @@ module AppInfo
40
47
  when Format::IPA then IPA.new(file)
41
48
  when Format::APK then APK.new(file)
42
49
  when Format::AAB then AAB.new(file)
50
+ when Format::HAP then HAP.new(file)
51
+ when Format::HAPP then HAPP.new(file)
43
52
  when Format::MOBILEPROVISION then MobileProvision.new(file)
44
53
  when Format::DSYM then DSYM.new(file)
45
54
  when Format::PROGUARD then Proguard.new(file)
@@ -61,89 +70,10 @@ module AppInfo
61
70
  file_type(file) != Format::UNKNOWN
62
71
  end
63
72
 
64
- # Detect file type by read file header
65
- #
66
- # TODO: This can be better solution, if anyone knows, tell me please.
67
- def file_type(file)
68
- header_hex = ::File.read(file, 100)
69
- case header_hex
70
- when ZIP_RETGEX
71
- detect_zip_file(file)
72
- when PE_REGEX
73
- Format::PE
74
- when PLIST_REGEX, BPLIST_REGEX
75
- Format::MOBILEPROVISION
76
- else
77
- Format::UNKNOWN
78
- end
79
- end
80
-
81
73
  def logger
82
74
  @logger ||= Logger.new($stdout, level: :warn)
83
75
  end
84
76
 
85
77
  attr_writer :logger
86
-
87
- private
88
-
89
- # :nodoc:
90
- def detect_zip_file(file)
91
- Zip.warn_invalid_date = false
92
- zip_file = Zip::File.open(file)
93
-
94
- return Format::PROGUARD if proguard_clues?(zip_file)
95
- return Format::APK if apk_clues?(zip_file)
96
- return Format::AAB if aab_clues?(zip_file)
97
- return Format::MACOS if macos_clues?(zip_file)
98
- return Format::PE if pe_clues?(zip_file)
99
- return Format::UNKNOWN unless clue = other_clues?(zip_file)
100
-
101
- clue
102
- ensure
103
- zip_file.close
104
- end
105
-
106
- # :nodoc:
107
- def proguard_clues?(zip_file)
108
- !zip_file.glob('*mapping*.txt').empty?
109
- end
110
-
111
- # :nodoc:
112
- def apk_clues?(zip_file)
113
- !zip_file.find_entry('AndroidManifest.xml').nil? &&
114
- !zip_file.find_entry('classes.dex').nil?
115
- end
116
-
117
- # :nodoc:
118
- def aab_clues?(zip_file)
119
- !zip_file.find_entry('base/manifest/AndroidManifest.xml').nil? &&
120
- !zip_file.find_entry('BundleConfig.pb').nil?
121
- end
122
-
123
- # :nodoc:
124
- def macos_clues?(zip_file)
125
- !zip_file.glob('*/Contents/MacOS/*').empty? &&
126
- !zip_file.glob('*/Contents/Info.plist').empty?
127
- end
128
-
129
- # :nodoc:
130
- def pe_clues?(zip_file)
131
- !zip_file.glob('*.exe').empty?
132
- end
133
-
134
- # :nodoc:
135
- def other_clues?(zip_file)
136
- zip_file.each do |f|
137
- path = f.name
138
-
139
- return Format::IPA if path.include?('Payload/') && path.end_with?('Info.plist')
140
- return Format::DSYM if path.include?('Contents/Resources/DWARF/')
141
- end
142
- end
143
78
  end
144
-
145
- ZIP_RETGEX = /^\x50\x4b\x03\x04/.freeze
146
- PE_REGEX = /^MZ/.freeze
147
- PLIST_REGEX = /\x3C\x3F\x78\x6D\x6C/.freeze
148
- BPLIST_REGEX = /^\x62\x70\x6C\x69\x73\x74/.freeze
149
79
  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: 3.1.4
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - icyleaf
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-28 00:00:00.000000000 Z
11
+ date: 2024-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: CFPropertyList
@@ -234,8 +234,8 @@ dependencies:
234
234
  - - ">="
235
235
  - !ruby/object:Gem::Version
236
236
  version: '10.0'
237
- description: Teardown tool for ipa/apk files and dSYM file, even support for info.plist
238
- and .mobileprovision files
237
+ description: Teardown tool for ipa, apk, aab, hap mobile files and Windows, macOS
238
+ and dSYM file, even support for info.plist and .mobileprovision files
239
239
  email:
240
240
  - icyleaf.cn@gmail.com
241
241
  executables:
@@ -280,9 +280,13 @@ files:
280
280
  - lib/app_info/dsym/macho.rb
281
281
  - lib/app_info/error.rb
282
282
  - lib/app_info/file.rb
283
+ - lib/app_info/hap.rb
284
+ - lib/app_info/happ.rb
285
+ - lib/app_info/harmonyos.rb
283
286
  - lib/app_info/helper.rb
284
287
  - lib/app_info/helper/archive.rb
285
288
  - lib/app_info/helper/file_size.rb
289
+ - lib/app_info/helper/file_type_detection.rb
286
290
  - lib/app_info/helper/generate_class.rb
287
291
  - lib/app_info/helper/protobuf.rb
288
292
  - lib/app_info/helper/signatures.rb
@@ -292,6 +296,7 @@ files:
292
296
  - lib/app_info/ipa/plugin.rb
293
297
  - lib/app_info/macos.rb
294
298
  - lib/app_info/mobile_provision.rb
299
+ - lib/app_info/pack_info.rb
295
300
  - lib/app_info/pe.rb
296
301
  - lib/app_info/png_uncrush.rb
297
302
  - lib/app_info/proguard.rb
@@ -308,14 +313,7 @@ homepage: http://github.com/icyleaf/app-info
308
313
  licenses:
309
314
  - MIT
310
315
  metadata: {}
311
- post_install_message: |
312
- AppInfo 3.0 was out!
313
- **********************
314
- The public API of some AppInfo classes has been changed.
315
-
316
- Please ensure that your Gemfiles and .gemspecs are suitably restrictive
317
- to avoid an unexpected breakage when 3.0 is released (e.g. ~> 2.8.5).
318
- See https://github.com/icyleaf/app_info for details.
316
+ post_install_message:
319
317
  rdoc_options: []
320
318
  require_paths:
321
319
  - lib
@@ -333,6 +331,5 @@ requirements: []
333
331
  rubygems_version: 3.5.9
334
332
  signing_key:
335
333
  specification_version: 4
336
- summary: Teardown tool for mobile app(ipa/apk) and dSYM file, analysis metedata like
337
- version, name, icon
334
+ summary: Teardown tool for all most app, analysis metedata like version, name, icon
338
335
  test_files: []