0

我有一个具有多个版本的应用程序模型版本模型有一个apk和一个icon字段(等等)。

我目前有一个表单,允许用户使用 carrierwave ( class VersionUploader < CarrierWave::Uploader::Base) 上传 .apk 文件。

上传 apk 文件后,我使用ruby​​_apk gem 来提取图标(从内部versions_uploader.rb)。

对于图标,ruby_apk gem 以以下格式返回哈希数组

{ "res/drawable-hdpi/ic_launcher.png" => "\x89PNG\x0D\x0A...", ... }

我想将图标保存到磁盘并以与 apk 文件相同的方式访问它(我的意思是能够在其上调用诸如 version.icon.identifier 之类的东西)

我已经坚持了一段时间了。任何有关如何完成或最好的方法的帮助将不胜感激。

提前致谢!

4

2 回答 2

1

如果您使用两个不同的上传器,并从模型层设置图标数据,这会变得容易得多。模型代码可能如下所示:

mount_uploader :apk, ApkUploader
mount_uploader :icon, IconUploader
before_save :assign_icon

def assign_icon
  if apk_changed?
    icon_data = Android::Apk.new(apk.path).icons.values.first
    self.icon = StringIO.new(icon_data)
  end
end

请注意,before_save必须在之后mount_uploader :apk,因为在事件上mount_uploader创建自己的回调before_save,并且您希望在它们之后触发。

于 2013-08-23T21:58:47.880 回答
0

I finally managed to get this working. Taavo's answer set me in the right direction but it didn't work as expected.

The main problem was that StringIO.new(icon_data) kept giving me a no implicit conversion of nil into string error. After quite some digging I found that I needed to add original_filename as an attribute to StringIO, but it has long since stopped accepting this without monkey patching the class. I found the solution to this problem from the Carrierwave wiki psge: How to: Upload from a string in Rails 3.

This now let me save the icon to the file-system but mysteriously, was not populating the Version.icon field with the reference (Version.apk was populated without any problems).

In the end, to get it working I had to get rid of the before_Save :assign_icon callback and moved my code into the ApkUploader file.

My code looks something like this:

1) Created a new initializer that inherits from StringIO

config/initializers/stringiohax.rb

class AppSpecificStringIO < StringIO
  attr_accessor :filepath

  def initialize(*args)
    super(*args[1..-1])
    @filepath = args[0]
  end

  def original_filename
    File.basename(filepath)
  end
end

2) Mount Uploaders

app/models/version.rb

class Version < ActiveRecord::Base
  mount_uploader :apk, ApkUploader
  mount_uploader :icon, IconUploader

3) Extract data from APK and save icon attribute

app/models/version.rb

class ApkUploader < CarrierWave::Uploader::Base
  include Sprockets::Rails::Helper
  include CarrierWave::MimeTypes
  require 'ruby_apk'

  ..
  ...

  process :extract_apk_info

  def store_dir
    app = App.find(model.app_id)
    studio_name = Studio.find(app.studio_id).slug
    "uploads/#{studio_name}/#{app.id}/version_#{model.version_code}"
  end

  def extract_apk_info
    apk = Android::Apk.new(model.apk.path.to_s)
    manifest  = apk.manifest
    icons     = apk.icon

    icon_name = icons.keys.last
    icon_data = icons.values.last

    model.package_name = manifest.package_name
    model.version_code = manifest.version_code
    model.version_name = manifest.version_name
    model.min_sdk_ver  = manifest.min_sdk_ver
    model.icon         = AppSpecificStringIO.new(icon_name, icon_data)
  end
于 2013-08-24T16:40:03.830 回答