Подтвердить что ты не робот

Отправить заголовки с запросом AVPlayer в iOS

Можно ли отправлять заголовки с помощью HTTP-запроса в аудиофайл при использовании AVPlayer? Мне нужно иметь возможность проверять содержимое заголовка при его получении сервером, чтобы ограничить доступ к запрашиваемому файлу.

4b9b3361

Ответ 1

Вам необходимо запросить данные самостоятельно через общий механизм подключения HTTP, например NSURLConnection. Если заголовки NSHTTPURLResponse передают ваш тест, вы должны сохранить его в NSCachesDirectory и передать URL-адрес этому ресурсу в AVPlayer следующим образом:

NSData *data = //your downloaded data.
NSString *filePath = //generate random path under NSCachesDirectory
[data writeToFile:filePath atomically:YES];

AVPlayer *player = [AVPlayer playerWithURL:[NSURL fileURLWithPath:filePath]];
//...

Ответ 2

Вы можете использовать AVURLAssetHTTPHeaderFieldsKey параметра AVURLAsset init для изменения заголовков запросов.

Например:

NSMutableDictionary * headers = [NSMutableDictionary dictionary];
[headers setObject:@"Your UA" forKey:@"User-Agent"];
AVURLAsset * asset = [AVURLAsset URLAssetWithURL:URL options:@{@"AVURLAssetHTTPHeaderFieldsKey" : headers}];
AVPlayerItem * item = [AVPlayerItem playerItemWithAsset:asset];
self.player = [[AVPlayer alloc] initWithPlayerItem:item];

Примечание. Я нашел этот ключ в источниках WebKit, но это ключ Частный, поэтому ваше приложение может отклонить AppStore, если вы его используете.

Ответ 3

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

Я сделал простой пример проекта (с большим количеством комментариев и документации) здесь: https://github.com/kevinjameshunt/AVPlayer-HTTP-Headers-Example

Ответ 4

Рассмотрим использование AVURLAsset. Для AVURLAsset вы можете настроить делегат resourceLoader. Внутри метода делегата вы можете запросить вручную вручную указать необходимые заголовки.

Преимущество этого подхода заключается в том, что вы полностью контролируете загрузку данных.

Вам нужно использовать настраиваемую схему URL-адресов, чтобы это решение работало (http и https не запускают метод делегата!):

-(void) play {
  NSURL * url = [URL URLWithString:@"mycustomscheme://tungsten.aaplimg.com/VOD/bipbop_adv_fmp4_example/master.m3u8"];
  AVURLAsset * asset = [AVURLAsset URLAssetWithURL: options:nil];
  [asset.resourceLoader setDelegate:self queue:dispatch_queue_create("TGLiveStreamController loader", nil)];
  AVPlayerItem * playerItem = [AVPlayerItem playerItemWithAsset:asset];
  // Use player item ...
  ...
}

#pragma mark - AVAssetResourceLoaderDelegate

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {
  dispatch_async(resourceLoader.delegateQueue, ^{
    NSURL * url = [URL URLWithString:@"https://tungsten.aaplimg.com/VOD/bipbop_adv_fmp4_example/master.m3u8"];
    NSMutableURLRequest *request = [loadingRequest.request mutableCopy];
    request.URL = url;

    // Add header
    [request setValue:@"Foo" forHTTPHeaderField:@"Bar"];

    NSURLResponse *response = nil;
    NSError *firstError = nil;

    // Issue request
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&firstError];

    [loadingRequest.dataRequest respondWithData:data];
    if (firstError) {
      [loadingRequest finishLoadingWithError:firstError];
    } else {
      [loadingRequest finishLoading];
    }
  });
  return YES;
}

Полный пример кода доступен в https://developer.apple.com/library/content/samplecode/sc1791/Introduction/Intro.html

Ответ 5

полный код может выглядеть так:

  #pragma Mark Sound Stuff

- (void)playSound:(NSString *)filePath
{
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:filePath]];
    [playerItem addObserver:self forKeyPath:@"status" options:0 context:0];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
    self.audioPlayer = [[AVPlayer alloc] initWithPlayerItem:playerItem];
    [self.audioPlayer play];
}

- (void)initSoundPrelisten
{
    //NSLog(@"begin: %s", __FUNCTION__);
    self.activityIndicator.hidden = NO;
    [self.activityIndicator startAnimating];

    // verification delegate : register
    dataProtocol = [[StoreConnection alloc] init];
    [dataProtocol setDelegate:self];
    [dataProtocol requestDataFromServer:[NSString stringWithFormat:@"sound/%@/audio/sample", [self.sound objectForKey:@"globalId"]]];
}

- (void)dataSuccessful:(BOOL)success successData:(NSMutableData *)data;
{
    NSLog(@"%s", __FUNCTION__);
    if (success) {
        //NSLog(@"sound data: %@", data);
        NSString *cacheDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        NSString *filePath = [cacheDirectory stringByAppendingPathComponent:@"sample.mp3"];
        //NSLog(@"filePath: %@", filePath);
        [data writeToFile:filePath atomically:YES];
        [self playSound:filePath];

    } else
    {
        UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Store Error" message:[NSString stringWithFormat:@"An Error occured while trying to download sound. Please try again"] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        alertView.tag = 1;
        [alertView show];
    }
}