lib/android/apk.rb in android_parser-2.6.0 vs lib/android/apk.rb in android_parser-2.7.0.beta1

- old
+ new

@@ -10,11 +10,10 @@ class NotApkFileError < StandardError; end class NotFoundError < StandardError; end # apk object class class Apk - # @return [String] apk file path attr_reader :path # @return [Android::Manifest] manifest instance # @return [nil] when parsing manifest is failed. attr_reader :manifest @@ -41,36 +40,34 @@ def initialize(filepath) Zip.warn_invalid_date = false @path = filepath raise NotFoundError, "'#{filepath}'" unless File.exist? @path - begin - @zip = Zip::File.open(@path) - rescue Zip::Error => e - raise NotApkFileError, e.message - end @bindata = File.open(@path, 'rb') {|f| f.read } @bindata.force_encoding(Encoding::ASCII_8BIT) - raise NotApkFileError, "manifest file is not found." if @zip.find_entry(MANIFEST).nil? + raise NotApkFileError, 'manifest file is not found.' if zip.find_entry(MANIFEST).nil? + begin @resource = Android::Resource.new(self.file(RESOURCE)) rescue => e - $stderr.puts "failed to parse resource: #{e}" - #$stderr.puts e.backtrace + logger.error "failed to parse resource: #{e} with backtrace" + logger.error e.backtrace end + begin @manifest = Android::Manifest.new(self.file(MANIFEST), @resource) rescue => e - $stderr.puts "failed to parse manifest:#{e}" - #$stderr.puts e.backtrace + logger.error "failed to parse manifest:#{e} with backtrace" + logger.error e.backtrace end + begin @dex = Android::Dex.new(self.file(DEX)) rescue => e - $stderr.puts "failed to parse dex:#{e}" - #$stderr.puts e.backtrace + logger.error "failed to parse dex:#{e} with backtrace" + logger.error e.backtrace end end # return apk file size # @return [Integer] bytes @@ -103,39 +100,39 @@ # @yield [name, data] # @yieldparam [String] name file name in apk # @yieldparam [String] data file data in apk def each_file - @zip.each do |entry| + zip.each do |entry| next unless entry.file? - yield entry.name, @zip.read(entry) + yield entry.name, zip.read(entry) end end # find and return binary data with name # @param [String] name file name in apk(fullpath) # @return [String] binary data # @raise [NotFoundError] when 'name' doesn't exist in the apk def file(name) # get data by entry name(path) - @zip.read(entry(name)) + zip.read(entry(name)) end # @yield [entry] # @yieldparam [Zip::Entry] entry zip entry def each_entry - @zip.each do |entry| + zip.each do |entry| next unless entry.file? yield entry end end # find and return zip entry with name # @param [String] name file name in apk(fullpath) # @return [Zip::Entry] zip entry object # @raise [NotFoundError] when 'name' doesn't exist in the apk def entry(name) - entry = @zip.find_entry(name) + entry = zip.find_entry(name) raise NotFoundError, "'#{name}'" if entry.nil? return entry end # find files which is matched with block condition @@ -221,10 +218,27 @@ # @since 0.7.0 def certificates @certificates ||= Hash[self.signs.map{|path, sign| [path, sign.certificates.first] }] end + # Return all architectures (all most for universal apk) + # @return [Array<String>] + # @since 2.7.0 + def archs + @archs ||= zip.glob('lib/**/*').each_with_object([]) do |entry, obj| + arch = entry.name.split('/')[1] + obj << arch unless obj.include?(arch) + end + end + + # detect if contains multi-platforms (native machine code) + # @return [Boolean] + # @since 2.7.0 + def universal? + archs.size > 1 + end + # detect if use kotlin language (may be third-party sdk or not) # @return [Boolean] # @since 2.6.0 def kotlin? @kotlin ||= kotlin_file? || kotlin_classes? @@ -255,8 +269,17 @@ 'META-INF/kotlinx_coroutines_android.version', 'META-INF/kotlinx_coroutines_core.version', 'META-INF/services/kotlinx.coroutines.CoroutineExceptionHandler', 'META-INF/services/kotlinx.coroutines.internal.MainDispatcherFactory' ].freeze + + def zip + @zip ||= Zip::File.open(@path) + rescue Zip::Error => e + raise NotApkFileError, e.message + end + + def logger + Android.logger + end end end -