IPhone UIWebView: loadData не работает с определенными типами (Excel, MSWord, PPT, RTF)

Моя задача - отобразить поддерживаемые типы документов на iPhone с ОС 3.x, такие как .pdf,.rtf,.doc,.ppt,.png,.tiff и т.д.

Теперь я сохранил эти файлы только зашифрованные на диске. Из соображений безопасности я хочу, чтобы они не сохраняли их на незашифрованном диске.

Следовательно, я предпочитаю использовать loadData:MIMEType:textEncodingName:baseURL: вместо loadRequest: для отображения документа, потому что loadData позволяет мне передавать содержимое в объекте NSData, то есть я могу расшифровать файл в памяти и не нужно хранить он на диске, как это было бы необходимо при использовании loadRequest.

Проблема заключается в том, что loadData не работает со всеми типами файлов:

Тестирование показывает, что все типы изображений работают нормально, а также PDF файлы, а более сложные типы - нет. Я получаю такие ошибки, как:

NSURLErrorDomain Code=100
NSURLErrorDomain Code=102

WebView, по-видимому, нуждается в действительно рабочем URL-адресе для доступа к документам в качестве файла, несмотря на то, что я уже предлагаю весь контент через объект NSData.

Здесь код, который я использую для отображения содержимого:

[webView loadData:data MIMEType:type textEncodingName:@"utf-8" baseURL:nil];

Тип mime правильно установлен, например. к "application/msword" для .doc файлов.

Кто-нибудь знает, как я мог бы loadData работать со всеми типами, которые поддерживает loadRequest? Или, альтернативно, есть ли какой-то способ, я могу сказать, какие типы действительно работают (то есть официально санкционировано Apple) с loadData? Тогда я могу работать в два раза, создавая временный незашифрованный файл только для тех случаев, которые loadData не понравится.

Обновление

Похоже, я не первый, кто работает в этом. См. Здесь:

http://osdir.com/ml/iPhoneSDKDevelopment/2010-03/msg00216.html

Итак, я думаю, что статус-кво, и я ничего не могу с этим поделать.

Кто-то предложил работу, которая может работать, хотя:

http://osdir.com/ml/iPhoneSDKDevelopment/2010-03/msg00219.html

В принципе, идея состоит в том, чтобы предоставить крошечный http-сервер, который обслуживает файл (из памяти в моем случае), а затем использовать loadRequest. Это, вероятно, немного более интенсивно для памяти, хотя, как и сервер, так и веб-просмотр, вероятно, будут содержать все содержимое в памяти в виде двух копий тогда, в отличие от использования loadData, где оба будут иметь общий доступ к одному и тому же объекту данных. (Имейте в виду, мне придется хранить дешифрованные данные в памяти, что весь смысл здесь).

Ответ 1

У меня возникла очень похожая проблема (я получил свои файлы с сервера) и увидел ваш пост и подумал, что это тупик, а затем просто случайно начал экспериментировать на устройстве (iPad в этом случае), и он работал, когда я дал baseURL как то, что я использовал для его получения с сервера, и он работал, но не работает на симуляторе. Я бы попробовал это, иначе я бы представил отчет об ошибке Apple.

Ответ 2

Вот решение через NSURLProtocol:

class CoreDataFileURLProtocol : NSURLProtocol {
    var connection: NSURLConnection!

    override class func canInitWithRequest(request: NSURLRequest) -> Bool {
        return (request.URL.scheme == "coredatafile")
    }

    override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
        return request
    }

    override func startLoading() {
        if let file_id = self.request.URL.absoluteString?.lastPathComponent {
            if let file = SAFile.MR_findFirstByAttribute("file_id", withValue: file_id) as? SAFile {
                let response = NSURLResponse(URL: request.URL, MIMEType: file.mime, expectedContentLength: Int(file.filesize), textEncodingName: "utf-8")
                client?.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .NotAllowed)
                client?.URLProtocol(self, didLoadData: file.data)
                client?.URLProtocolDidFinishLoading(self)
            }
        }
    }

    override func stopLoading() {
    }
}

Теперь вам нужно только зарегистрировать класс:

NSURLProtocol.registerClass(CoreDataFileURLProtocol.self)

И создайте запрос с помощью file_id:

let url = NSURL(scheme: "coredatafile", host: "myapp.com", path: "/\(file.file_id)")
webView.loadRequest(NSURLRequest(URL: url!))