Cordova外部应用+本地视频 [英] Cordova external app + local video

查看:200
本文介绍了Cordova外部应用+本地视频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个使用PhoneGap / Cordova 4.3.0构建的iOS应用程序。此应用在配置中使用< content src =http://example.com/foo/> 直接加载外部网站.xml 文件。所有功能都包含在本网站中,因此我们实际上并没有使用任何本地HTML或JS文件。



作为应用功能的一部分,我们必须播放一些视频。由于该应用程序也设计为脱机工作,因此我们希望在本地缓存这些视频。因此,我们使用FileTransfer插件将其下载到设备,以及其他资源,如图像或PDF。下载文件后,我们将获得带有 file:// 协议的URL。我们还可以选择使用 cdvfile:// 协议。当我们使用 cdvfile:// URL来显示图像时,图像会正确显示。但是,视频根本无法播放。



要播放视频,我们使用的是标准HTML5视频标记:

 < video width =autoheight =100%controls =controlsautoplay =true> 
< source src =...type =video / mp4/>
< / video>

视频本身正在运行,它们将从外部来源正确播放(如同,它们将会如果我们从服务器而不是本地文件系统访问它们,则播放)。我意识到问题与Web相关的概念有关,例如同源策略和访问本地文件系统的限制。然而,与此同时,我必须想知道为什么图像在这些相同的约束条件下工作正常。



到目前为止我尝试过:


  1. 使用 file:// cdvfile:// 视频的 src 的网址。这不会产生任何视觉效果。屏幕显示为黑色。

  2. 使用 iframe 并使用 src 设置到视频网址。使用 file:// 时,屏幕仍为黑色。但是,当使用 cdvfile:// 时,会出现iOS视频播放器界面,带有播放按钮和全屏按钮,但视频无法播放且没有播放时间线要么。

  3. 将一个本地文件添加到cordova,名为 video.html ,它将URL作为参数并呈现视频将该网址标记为 src 。计划是将此文件包含为 iframe ,但显然我无法将 iframe 包含到本地文件中。我尝试了各种可能指向特定 video.html 文件的URL(虽然实际上我不确定这是否可行)。我试过的是: cordova.file.applicationDirectory +'www / video.html' http:// localhost / www / video。 html cdvfile://localhost/www/video.html

  4. 我找了一些cordova将播放视频的插件,但我找不到适合iOS的插件。大多数插件似乎都是针对Android的。

现在,我可能会以错误的方式解决这个问题。正如我所看到的,cordova的标准用例是您在本地存储HTML / JS / CSS文件。像我正在使用的外部内容可能有点不寻常。我将解释这个应用程序的要求,它让我使用了这个功能。




  • 该应用程序应该是为多个平台构建的(虽然我们从iOS开始)。因此我们正在使用PhoneGap。

  • 它应该可以在线和离线访问,但所有内容都来自服务器(没有内容在本地生成)。这就是我们下载内容并在本地保存的原因。

  • 它还应该动态自动更新自身的任何部分,而无需从App Store进行更新。这就是我们使用外部页面的原因 - 因为它有一个 cache.manifest ,它允许我们控制对Web应用程序代码的更新,同时允许它在本地缓存。这可能是最重要的考虑因素,因为如果我们想在Cordova中本地保存一些文件,我们必须在Javascript中重新实现这个缓存功能(尽可能使用尽可能薄的层)。



无论如何,我主要担心的是如何让这些视频正常运行。我愿意尝试最骇客的解决方法!如果当前的开发决策真的不可能,那么也许你可以给我一些关于如何构建应用程序的提示,以使其工作并仍然满足我的要求。



非常感谢!

解决方案

一年前我有一个类似的项目。但我不记得遇到这个问题因为我们将html / js / css资产与应用程序捆绑在一起。



问题是你正在尝试加载文件:来自


We have an iOS app built with PhoneGap / Cordova 4.3.0. This app directly loads an external website by using <content src="http://example.com/foo" /> in the config.xml file. All the functionality is contained within this website, so we are not actually using any local HTML or JS files.

As part of the app functionality, we must play some videos. Because the app is designed to work offline as well, we want to cache these videos locally. Therefore we are downloading them to the device using the FileTransfer plugin, along with other resources such as images or PDFs. After downloading the files we are getting URLs with the file:// protocol. We also have the option of using the cdvfile:// protocol. When we use cdvfile:// URLs to show images, the images show up correctly. However, videos do not play at all.

To play videos we are using standard HTML5 video tags:

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

The videos themselves are working, and they will play correctly from an external source (as in, they will play if we are accessing them from the server instead of the local filesystem). I realize that the problem has something to do with web-related concepts such as the same-origin policy and with the restriction to access the local filesystem. However, at the same time I must wonder why it is that images are working fine under these same constraints.

What I have tried so far:

  1. Using file:// and cdvfile:// URLs as the src of the video. This does not produce any sort of visual effect. The screen is simply black.
  2. Using an iframe with the src set to the video URL. When using file://, the screen is still black. However, when using cdvfile://, the iOS video player interface appears, with a play button and a full-screen button, but the video does not play and there is no timeline either.
  3. Adding a local file to cordova called video.html which takes a URL as parameter and renders a video tag with that URL as src. The plan was to include this file as an iframe, but apparently I can't make an iframe to a local file. I have tried various URLs that might point to that particular video.html file (though in truth I'm not sure this is possible). Among the ones I tried were: cordova.file.applicationDirectory + 'www/video.html', http://localhost/www/video.html, cdvfile://localhost/www/video.html.
  4. I looked for some cordova plugin that will play videos, but I have been unsuccessful in finding one for iOS. Most plugins seem to be targeted towards Android.

Now, it's possible that I'm going about this in a wrong way. As I see it, the "standard use case" for cordova is that you store your HTML/JS/CSS files locally. External content like the one I'm using is probably a bit unusual. I will explain the requirements for this app that have brought me to use this functionality.

  • The app is supposed to be built for multiple platforms (though we're starting with iOS). Therefore we are using PhoneGap.
  • It is supposed to be accessible both online and offline, though all the content comes from the server (no content is produced locally). This is why we are downloading content and saving it locally.
  • It is also supposed to auto-update any part of itself on the fly, without requiring an update from the App Store. This is why we are using an external page - because it has a cache.manifest that allows us to control updates to the web app code, while at the same time allowing it to be cached locally. This is probably the most important thing to consider, because if we wanted to keep some files locally within Cordova, we would have to re-implement this cache functionality within Javascript (using as thin a layer as possible).

In any case, my main concern is how to get these videos working. I am willing to try the hackiest workarounds! If it's really not possible with the current development decisions, then maybe you could give me some hints as to how I should structure the app in order to make it work and still fulfill my requirements.

Thank you very much!

解决方案

I had a similar project about a year ago. But i don't remember running into this issue because we were bundling our html/js/css assets with the app.

The issue is that your are trying to load file:/// protocol url from an html file served from http:/// protocol, which is not something that the native UIWebView is comfortable with.

You can bypass this by using a custom URL scheme like video://, but you need to write some native code which intercepts this requests and pipes the actual video back to URL loading system.

The end result:

Here is how i did it using Cordova 4.3.0 & a bit of ObjectiveC

  1. Create a new Objective C class named VideoURLProtocol which extends NSURLProtocol:

VideoURLProtocol.h:

#import <Foundation/Foundation.h>

@interface VideoURLProtocol : NSURLProtocol <NSURLConnectionDelegate>

@property (strong, nonatomic) NSURLConnection *connection;

@end

VideoURLProtocol.m:

#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. Add the following line to the didFinishLaunchingWithOptions method of AppDelegate.m

    .
    .
    // These lines should already be there
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    
    // This line
    [NSURLProtocol registerClass:[VideoURLProtocol class]];
    .
    .    
    

  2. And here's the javascript code that utilises this new URL scheme

    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);
    

Some additional points worth mentioning:

Notice in my javascript code i am downloading the file to "/Library/Caches" instead of the "/Documents" directory (the default location) this is because the "/Documents" directory gets backed up to iCloud & Apple rejects apps that try to backup more than ~100 MB. This is something I found the hard way after getting my App rejected. You can see the space taken by your app under: Settings > iCloud > Storage > Manage Storage > {{Your iphone name}} > Show All Apps

You can autoplay videos by add the following line to your config.xml

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

You can also play videos inline by adding the following line to your config.xml in addition to this you also need to add webkit-playsinline="true" attribute to your video:

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

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

Here's a really interesting tutorial by Ray that explains NSURLProtocol in great detail: http://www.raywenderlich.com/59982/nsurlprotocol-tutorial

这篇关于Cordova外部应用+本地视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆