How to insert header info into MPMoviePlayerController url?

匆匆过客 提交于 2019-11-29 02:45:07

It's true that Apple doesn't expose an easy way to inject headers into a MPMoviePlayerController's request. With a bit of effort, you can get this done using a custom NSURLProtocol. So, let's do it!

MyCustomURLProtocol.h:

@interface MyCustomURLProtocol : NSURLProtocol <NSURLConnectionDelegate, NSURLConnectionDataDelegate>

@property (nonatomic, strong) NSURLConnection* connection;

@end

MyCustomURLProtocol.m:

@implementation  MyCustomURLProtocol

// Define which protocols you want to handle
// In this case, I'm only handling "customProtocol" manually
// Everything else, (http, https, ftp, etc) is handled by the system
+ (BOOL) canInitWithRequest:(NSURLRequest *)request {
    NSURL* theURL = request.URL;
    NSString* scheme = theURL.scheme;
    if([scheme isEqualToString:@"customProtocol"]) {
        return YES;
    }
    return NO;
}

// You could modify the request here, but I'm doing my legwork in startLoading
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    return request;
}

// I'm not doing any custom cache work
+ (BOOL) requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
    return [super requestIsCacheEquivalent:a toRequest:b];
}

// This is where I inject my header
// I take the handled request, add a header, and turn it back into http
// Then I fire it off
- (void) startLoading {
    NSMutableURLRequest* mutableRequest = [self.request mutableCopy];
    [mutableRequest setValue:@"customHeaderValue" forHTTPHeaderField:@"customHeaderField"];

    NSURL* newUrl = [[NSURL alloc] initWithScheme:@"http" host:[mutableRequest.URL host] path:[mutableRequest.URL path]];
    [mutableRequest setURL:newUrl];

    self.connection = [NSURLConnection connectionWithRequest:mutableRequest delegate:self];
}

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

// Below are boilerplate delegate implementations
// They are responsible for letting our client (the MPMovePlayerController) what happened

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

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

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

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

@end

Before you can use your custom URL Protocol, you must register it. In your AppDelegate.m:

#import "MyCustomURLProtocol.h"

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // ... Your normal setup ...

    [NSURLProtocol registerClass:[MyCustomURLProtocol class]];

    return YES;
}

Finally, you need to user your custom URL Protocol with the MPMediaPlayerController.

NSString* theURLString = [NSString stringWithFormat:@"customProtocol://%@%@", [_url host],[_url path]];
_player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:theURLString]];

The MPMoviePlayerController will now attempt to make the request with customProtocol:// instead of normal http://. Using this setup, we then intercept that request, add our headers, turn it into http, and then fire everything off.

Go back and read the documentation for NSURLConnection, and the URL-loading system in general. -connection:didReceiveData: is likely called more than once, as each chunk of the file arrives. You need to handle that, rather than assuming only the complete data arrives all at once.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!