Cordova внешнее приложение + локальное видео

у нас есть приложение iOS, построенное с PhoneGap / Cordova 4.3.0. Это приложение напрямую загружает внешний веб-сайт с помощью <content src="http://example.com/foo" /> на . Все функции содержатся на этом веб-сайте, поэтому мы фактически не используем локальные HTML или JS-файлы.

в рамках функциональности приложения, мы должны играть некоторые видео. Поскольку приложение предназначено для работы в автономном режиме, мы хотим кэшировать эти видео локально. Поэтому мы загружаем их на устройство с помощью Плагин FileTransfer, наряду с другими ресурсами, такими как изображения или PDF. После загрузки файлов мы получаем URL-адреса с помощью file:// протокол. У нас также есть возможность использовать cdvfile:// протокол. Когда мы используем cdvfile:// URLs для отображения изображений, изображения отображаются правильно. Однако видео не воспроизводятся вообще.

для воспроизведения видео мы используем стандартные видео Теги HTML5:

<video width="auto" height="100%" controls="controls" autoplay="true">
    <source src="..." type="video/mp4" />
</video>

сами видео работают, и они будут правильно воспроизводиться с внешнего источник (например, они будут играть, если мы обращаемся к ним с сервера вместо локальной файловой системы). Я понимаю, что проблема связана с веб-концепциями, такими как политика того же происхождения и ограничение доступа к локальной файловой системе. Однако в то же время я должен задаться вопросом, почему изображения работают нормально при тех же ограничениях.

то, что я пробовал до сих пор:

  1. используя file:// и cdvfile:// URLs как src видео. Это не производит никакого визуального эффекта. Экран просто черный.
  2. С помощью iframe С src установите URL видео. При использовании file://, экран по-прежнему черный. Однако, при использовании cdvfile://, появляется интерфейс видеоплеера iOS с кнопкой воспроизведения и полноэкранной кнопкой, но видео не воспроизводится, и нет временной шкалы.
  3. добавление локального файла в cordova под названием video.html который принимает URL как параметр и отображает video тег с этим URL как src. План состоял в том, чтобы включить этот файл в качестве iframe, но, по-видимому, я не могу сделать iframe в локальный файл. Я пробовал различные URL-адреса, которые могут указывать на этот конкретный (хотя, по правде говоря, я не уверен, что это возможно). Среди тех, что я пробовал, были:--19-->, http://localhost/www/video.html, cdvfile://localhost/www/video.html.
  4. я искал плагин cordova, который будет воспроизводить видео, но мне не удалось найти его для iOS. Большинство плагинов, похоже, ориентированы на Андроид.

теперь, возможно, я иду по этому неправильному пути. Как я вижу, "стандартный вариант использования" для cordova заключается в том, что вы храните свои файлы HTML/JS/CSS локально. Внешний контент, подобный тому, который я использую, вероятно, немного необычен. Я объясню требования к этому приложению, которые привели меня к использованию этой функции.

  • приложение должно быть построено для нескольких платформ (хотя мы начинаем с iOS). Поэтому мы используем PhoneGap.
  • он должен быть доступен как онлайн, так и офлайн, хотя весь контент поступает с сервера (контент не создается локально). Вот почему мы загружаем контент и сохраняем его локально.
  • он также должен автоматически обновлять любую часть себя на лету, не требуя обновления из App Store. Вот почему мы используем внешнюю страницу-потому что у нее есть cache.manifest это позволяет нам контролировать обновления в интернете код приложения, в то же время позволяя кэшировать его локально. Это, вероятно, самое важное, что нужно учитывать, потому что если бы мы хотели сохранить некоторые файлы локально в Cordova, нам пришлось бы повторно реализовать эту функциональность кэша в Javascript (используя как можно более тонкий слой).

в любом случае, моя главная забота-как заставить эти видео работать. Я готов попробовать hackiest обходные пути! Если это действительно невозможно с текущей разработкой решения, тогда, возможно, вы могли бы дать мне несколько советов о том, как я должен структурировать приложение, чтобы заставить его работать и по-прежнему выполнять мои требования.

большое спасибо!

2 ответов


у меня был подобный проект около года назад. Но я не помню, как столкнулся с этой проблемой, потому что мы связывали наши HTML/JS/css активы с приложением.

проблема в том, что вы пытаетесь загрузить файл:/// url протокола из html-файла, обслуживаемого из HTTP://в/ протокол, который не является чем-то, что родной UIWebView удобен.

вы можете обойти это, используя пользовательскую схему URL, такую как video://, но вам нужно написать собственный код который перехватывает эти запросы и передает фактическое видео обратно в систему Загрузки URL.

в итоге:

The end result

вот как я это сделал, используя Cordova 4.3.0 & немного ObjectiveC

  1. создайте новый класс Objective C с именем VideoURLProtocol, который расширяет NSURLProtocol:

VideoURLProtocol.h:

#import <Foundation/Foundation.h>

@interface VideoURLProtocol : NSURLProtocol <NSURLConnectionDelegate>

@property (strong, nonatomic) NSURLConnection *connection;

@end

VideoURLProtocol.м:

#import "VideoURLProtocol.h"

@implementation VideoURLProtocol

@synthesize connection;

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    return [[[request URL] absoluteString] rangeOfString:@"video://"].location != NSNotFound;
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    return request;
}

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
    return [super requestIsCacheEquivalent:a toRequest:b];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.client URLProtocol:self didLoadData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [self.client URLProtocolDidFinishLoading:self];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [self.client URLProtocol:self didFailWithError:error];
}

- (void)startLoading {
    NSString *currentURL = [[self.request URL] absoluteString];
    NSString *newURL = [currentURL stringByReplacingOccurrencesOfString:@"video://" withString:@"file:///"];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:newURL]];
    self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
}

- (void)stopLoading {
    [self.connection cancel];
    self.connection = nil;
}

@end
  1. добавить следующие строка к методу didFinishLaunchingWithOptions AppDelegate.м

    .
    .
    // These lines should already be there
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    
    // This line
    [NSURLProtocol registerClass:[VideoURLProtocol class]];
    .
    .    
    
  2. и вот код javascript, который использует эту новую схему URL

    document.addEventListener('deviceready', function(){    
        window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem){        
            var caches = fileSystem.root.nativeURL.replace("Documents", "Library/Caches"), 
                videoPath = caches + "video.mp4";
            new FileTransfer().download("http://clips.vorwaerts-gmbh.de/VfE_html5.mp4", videoPath, function(entry){            
                document.getElementsByTagName("video")[0].src = caches.replace("file:///", "video://") + "video.mp4"
            }, function(error){
                alert("unable to download file: " + error);
            });
        });
    }, false);
    

некоторые дополнительные моменты стоит отметить:

уведомление в моем коде javascript я загружаю файл в"/Library/Caches "вместо каталога" / Documents "(расположение по умолчанию) это потому, что каталог "/ Documents " получает резервную копию в iCloud & Apple отклоняет приложения, которые пытаются создать резервную копию более ~100 МБ. Это то, что я нашел трудный путь после того, как мое приложение было отклонено. Вы можете ознакомиться с Приложение в: Настройки > iCloud > "Хранилище" > "хранилище" > {{ваше имя iPhone}} " > " показать все приложения

вы можете автоматически воспроизводить видео, добавив следующую строку в свою конфигурацию.в XML

<preference name="MediaPlaybackRequiresUserAction" value="false" />    

вы также можете воспроизводить видео inline, добавив следующую строку в свою конфигурацию.XML в дополнение к этому также нужно добавить webkit-playsinline=атрибут"true" для вашего видео:

<preference name="AllowInlineMediaPlayback" value="true" />

<video controls="controls" autoplay="true" webkit-playsinline="true" preload="auto">
</video>

вот действительно интересный учебник Рэя, который объясняет NSURLProtocol в деталях:http://www.raywenderlich.com/59982/nsurlprotocol-tutorial


по моему опыту использования file:// протокол был проблематичным на iOS, потому что протокол начинается в корне файловой системы устройства.

Я не считаю, что здесь возникают какие-либо проблемы с перекрестным происхождением, потому что Cordova не реализует запросы перекрестного происхождения, а скорее рассматривает все запросы как исходящие от источника, к которому они запрашивают. посмотреть этот ответ.

мое теоретическое решение-это использовать относительные URL-адрес вместо того, чтобы пытаться использовать какой-либо протокол вообще. Однако способ реализации этого может зависеть от того, когда файл был успешно загружен.

<video width="auto" height="100%" controls="controls" autoplay="true">
    <source src="/localhost/www/video.mp4" type="video/mp4" />
</video>

здесь cdvfile://localhost/www/ путь, установленные для target аргумент, когда ты позвонил fileTransfer.download() ссылка здесь.

может потребоваться либо создать элемент видео, либо установить видео src в javascript один раз successCallback был уволен. Опять же, вы бы установили src в качестве родственника URL-АДРЕС.

обратите внимание, что видео не будет автозапуск на мобильном

из библиотеки разработчиков Safari

в Safari на iOS (для всех устройств, включая iPad), где пользователь может находиться в сотовой сети и взимать плату за единицу данных, предварительная загрузка и автозапуск отключены.