Ios MPMoviePlayerController和基于身份验证的HLS后端服务器

Ios MPMoviePlayerController和基于身份验证的HLS后端服务器,ios,mpmovieplayercontroller,http-live-streaming,Ios,Mpmovieplayercontroller,Http Live Streaming,我目前正在使用MPMoviePlayerController在iOS应用程序中提供视频。文件从需要身份验证的后端服务器流式传输。它是授权HTTP头中基于密钥的身份验证集 它过去可以完美地处理单个视频文件。现在我们正试图实现HLS自适应流媒体,我们面临着一堵墙。我目前正在使用一个自定义的NSURLProtocol子类来捕获对后端服务器的请求,并注入适当的授权头。对于HLS来说,它根本不起作用 当我们查看服务器日志时,我们清楚地看到对m3u8文件的第一个请求工作正常。然后,禁止所有后续调用(其他m3

我目前正在使用
MPMoviePlayerController
在iOS应用程序中提供视频。文件从需要身份验证的后端服务器流式传输。它是授权HTTP头中基于密钥的身份验证集

它过去可以完美地处理单个视频文件。现在我们正试图实现HLS自适应流媒体,我们面临着一堵墙。我目前正在使用一个自定义的
NSURLProtocol
子类来捕获对后端服务器的请求,并注入适当的授权头。对于HLS来说,它根本不起作用

当我们查看服务器日志时,我们清楚地看到对m3u8文件的第一个请求工作正常。然后,禁止所有后续调用(其他m3u8文件和ts)。似乎
MPMoviePlayerController
没有对其他文件使用
nsurprotocol
。(旁注:它确实在模拟器思想上起作用,但在物理设备上不起作用,这让我觉得两者的实现方式不同)

MPMoviePlayerController实例化 URL协议拦截
任何想法、建议和解决方法?

通过使用NSURL协议,您可以拦截MPMoviePlayerController和流式请求之间的通信。在此过程中注入cookies,或者可能保存流脱机视频。为此,您应该创建一个扩展NSURLProtocol的新类:

希望这对您有所帮助:

GAURLProtocol.h

#import <Foundation/Foundation.h>

@interface GAURLProtocol : NSURLProtocol
+ (void) register;
+ (void) injectURL:(NSString*) urlString cookie:(NSString*)cookie;
@end
用法

[GAURLProtocol injectURL:@"http://example.com/video.mp4" cookie:@"cookie=f23r3121"];
MPMoviePlayerController * moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:@"http://example.com/video.mp4"];
[moviePlayer play];

在与苹果开发者技术支持部门核实后,我认为我想要实现的目标是不可能的(而且不受支持)

以下是回复中的引述:

您看到的NSURLProtocol等的问题是,电影播放子系统没有在您的进程中运行其HTTP请求。相反,这些请求是在单独的系统进程mediaserverd中运行的。因此,您影响播放行为的所有努力都是徒劳的


@Marc Alexandre Bérubé我可以想到以下解决方法:
在应用程序中运行代理服务器以代理所有视频URL。通过向请求中注入必要的auth头下载所有视频内容,并通过代理服务器将内容中继回媒体播放器进行渲染。这种方法可能不适用于大型视频,因为视频渲染只有在下载完整个视频后才会开始。

它看起来与我所做的非常接近。。但它是在模拟器上工作,而不是在设备上(运行iOS9.2)。您能否确认它在iOS 8及以上版本的设备上以及在HLS视频上对您有效?(这与单个流文件不同)就记录而言,它与我们最终所做的非常接近。我们的服务器代理m3u8文件并注入完整的签名url以替换段条目。签名URL已过期。
#import <Foundation/Foundation.h>

@interface GAURLProtocol : NSURLProtocol
+ (void) register;
+ (void) injectURL:(NSString*) urlString cookie:(NSString*)cookie;
@end
#import "GAURLProtocol.h"

@interface GAURLProtocol() <NSURLConnectionDelegate> {
    NSMutableURLRequest* myRequest;
    NSURLConnection * connection;
}
@end

static NSString* injectedURL = nil;
static NSString* myCookie = nil;

@implementation GAURLProtocol

+ (void) register
{
    [NSURLProtocol registerClass:[self class]];
}

// public static function to call when injecting a cookie
+ (void) injectURL:(NSString*) urlString cookie:(NSString*)cookie
{
    injectedURL = urlString;
    myCookie = cookie;
}

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    if([[[request allHTTPHeaderFields] objectForKey:@"Heeehey"] isEqualToString:@"Huuu"])
    {
        return NO;
    }
    return [[[request URL] absoluteString] isEqualToString:injectedURL];
}

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

// intercept the request and handle it yourself
- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client {

    if (self = [super initWithRequest:request cachedResponse:cachedResponse client:client]) {
        myRequest = request.mutableCopy;
        [myRequest setValue:@"Huuu" forHTTPHeaderField:@"Heeehey"]; // add your own signature to the request
    }
    return self;
}

// load the request
- (void)startLoading {
    //  inject your cookie
    [myRequest setValue:myCookie forHTTPHeaderField:@"Cookie"];
    connection = [[NSURLConnection alloc] initWithRequest:myRequest delegate:self];
}

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

// overload didReceiveResponse
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response {
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:[myRequest cachePolicy]];
}

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

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

// handle load cancelation
- (void)stopLoading {
    [connection cancel];
}

@end
// register protocol
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [NSURLProtocol registerClass:[GAURLProtocol class]];
    return YES;
}
[GAURLProtocol injectURL:@"http://example.com/video.mp4" cookie:@"cookie=f23r3121"];
MPMoviePlayerController * moviePlayer = [[MPMoviePlayerController alloc]initWithContentURL:@"http://example.com/video.mp4"];
[moviePlayer play];