class AndroidApk

Constants

NOT_ALLOW_DUPLICATE_TAG_NAMES

Attributes

filepath[RW]
icon[RW]
icons[RW]
label[RW]
labels[RW]
package_name[RW]
results[RW]
sdk_version[RW]
target_sdk_version[RW]
version_code[RW]
version_name[RW]

Public Class Methods

_parse_aapt(results) click to toggle source
# File lib/android_apk.rb, line 124
def self._parse_aapt(results)
  vars = Hash.new
  results.split("\n").each do |line|
    key, value = _parse_line(line)
    next if key.nil?
    if vars.key?(key) && allow_duplicate?(key)
      if (vars[key].is_a?(Hash) and value.is_a?(Hash))
        vars[key].merge(value)
      else
        vars[key] = [vars[key]] unless (vars[key].is_a?(Array))
        if (value.is_a?(Array))
          vars[key].concat(value)
        else
          vars[key].push(value)
        end
      end
    else
       vars[key] = value.nil? ? nil :
         (value.is_a?(Hash) ? value :
           (value.length > 1 ? value : value[0]))
    end
  end
  return vars
end
_parse_line(line) click to toggle source
# File lib/android_apk.rb, line 112
def self._parse_line(line)
  return nil if line.nil?
  info = line.split(":", 2)
  values =
      if info[0].start_with?('application-label')
        _parse_values_workaround info[1]
      else
        _parse_values info[1]
      end
  return info[0], values
end
_parse_values(str) click to toggle source
# File lib/android_apk.rb, line 99
def self._parse_values(str)
  return nil if str.nil?
  if str.index("='")
    # key-value hash
    vars = Hash[str.scan(/(\S+)='((?:\\'|[^'])*)'/)]
    vars.each_value {|v| v.gsub(/\\'/, "'")}
  else
    # values array
    vars = str.scan(/'((?:\\'|[^'])*)'/).map{|v| v[0].gsub(/\\'/, "'")}
  end
  return vars
end
_parse_values_workaround(str) click to toggle source

workaround for code.google.com/p/android/issues/detail?id=160847

# File lib/android_apk.rb, line 94
def self._parse_values_workaround(str)
  return nil if str.nil?
  str.scan(/^'(.+)'$/).map{|v| v[0].gsub(/\\'/, "'")}
end
allow_duplicate?(key) click to toggle source
# File lib/android_apk.rb, line 149
def self.allow_duplicate?(key)
  raise AndroidManifestValidateError, "Duplication of #{key} tag is not allowed" if NOT_ALLOW_DUPLICATE_TAG_NAMES.include?(key)
  true
end
analyze(filepath) click to toggle source
# File lib/android_apk.rb, line 12
def self.analyze(filepath)
  return nil unless File.exist?(filepath)
  apk = AndroidApk.new
  command = "aapt dump badging #{filepath.shellescape} 2>&1"
  results = `#{command}`
  if $?.exitstatus != 0 or results.index("ERROR: dump failed")
    return nil
  end
  apk.filepath = filepath
  apk.results = results
  vars = _parse_aapt(results)

  # application info
  apk.label = vars['application-label']
  apk.icon = vars['application']['icon']

  # package
  apk.package_name, apk.version_code, apk.version_name =
    vars['package'].values_at('name', 'versionCode', 'versionName')

  # platforms
  apk.sdk_version = vars['sdkVersion']
  apk.target_sdk_version = vars['targetSdkVersion']

  # icons and labels
  apk.icons = Hash.new
  apk.labels = Hash.new
  vars.each_key do |k|
    k =~ /^application-icon-(\d+)$/ && apk.icons[$1.to_i] = vars[k]
    k =~ /^application-label-(\S+)$/ && apk.labels[$1] = vars[k]
  end

  return apk
end

Public Instance Methods

dpi_str(dpi) click to toggle source
# File lib/android_apk.rb, line 65
def dpi_str(dpi)
  case dpi.to_i
    when 120
      'ldpi'
    when 160
      'mdpi'
    when 240
      'hdpi'
    when 320
      'xhdpi'
    when 480
      'xxhdpi'
    when 640
      'xxxhdpi'
    else
      'xxxhdpi'
  end
end
icon_file(dpi = nil, want_png = false) click to toggle source
# File lib/android_apk.rb, line 47
def icon_file(dpi = nil, want_png = false)
  icon = dpi ? self.icons[dpi.to_i] : self.icon
  return nil if icon.empty?

  if want_png && icon.end_with?('.xml')
    dpis = dpi_str(dpi)
    icon.gsub! %r{res/(drawable|mipmap)-anydpi-(?:v\d+)/([^/]+)\.xml}, "res/\\1-#{dpis}-v4/\\2.png"
  end

  Dir.mktmpdir do |dir|
    command = "unzip #{self.filepath.shellescape} #{icon.shellescape} -d #{dir.shellescape} 2>&1"
    results = `#{command}`
    path =  dir + "/" + icon 
    return nil unless File.exist?(path)
    return File.new(path,'r')
  end
end
signature() click to toggle source
# File lib/android_apk.rb, line 84
def signature
  command = "unzip -p #{self.filepath.shellescape} META-INF/*.RSA META-INF/*.DSA | keytool -printcert | grep SHA1:"
  output, _, status = Open3.capture3(command)
  return if status != 0 || output.nil? || !output.index('SHA1:')
  val = output.scan(/(?:[0-9A-Z]{2}:?){20}/)
  return nil if val.nil? || val.length != 1
  return val[0].gsub(/:/, "").downcase
end