Проблема с безопасностью транспорта приложений, когда AVAudioPlayer загружает локальный файл target-C, XCode 9

У меня есть приложение, которое загружает связанный аудиофайл m4a в качестве локального ресурса, и оно хорошо работает уже много лет. Я обновляю приложение до iOS 11.3/XCode 9.3, и теперь оно не работает на iPad (работает на iPhone), когда я нажимаю кнопку воспроизведения:

2018-05-13 20:45:24.437626-0700 my app[6175:218735] App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
2018-05-13 20:45:24.437791-0700 my app[6175:218735] Cannot start load of Task <117E064E-ABB3-45F2-8D64-76397B140092>.<0> since it does not conform to ATS policy
2018-05-13 20:45:24.437948-0700 my app[6175:218732] NSURLConnection finished with error - code -1022

Мой код:

NSURL *medURL   = [[NSBundle mainBundle] URLForResource: @"MyFile"
                                          withExtension: @"m4a"];
NSError *playerError = nil;
AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: medURL error: &playerError];
self.appSoundPlayer = newPlayer;

// "Preparing to play" attaches to the audio hardware and ensures that playback
//      starts quickly when the user taps Play
[appSoundPlayer prepareToPlay];

Это не удается на prepareToPlay.

Читая другие ответы, я нашел много информации об ошибке ATS, поэтому я добавил это в свой файл plist для приложения, очистил, перестроил и запустил его, но я все еще получаю сообщение об ошибке:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsLocalNetworking</key>
    <true/>
    <key>NSAllowsArbitraryLoadsForMedia</key>
    <true/>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <true/>
    <key>NSExceptionAllowsInsecureHTTPLoads</key>
    <true/> </dict>

Я не могу использовать ключ NSExceptionDomain, потому что это локальный ресурс, домена нет. Как я могу это исправить?

Примечание: для ясности, этот файл входит в состав приложения и никогда не загружался. Это не URL-адрес «http», это URL-адрес «file:».

Обновление: просматривая CFNetworkLog, я понял, что в сети произошло NSURLConnection непосредственно перед подготовкой звука в AppDelegate. Когда я удалил этот звонок, все заработало. Поскольку оба работают независимо, мне кажется, что в NSURLConnection происходит какой-то конфликт - возможно, ошибка в API? Было бы неплохо узнать, каков правильный обходной путь для этого, я заставил его работать достаточно хорошо, удалив вышеприведенный вызов prepareToPlay - это не идеально, так как требуется больше времени, когда пользователь переходит к воспроизведению аудиофайла.

Еще одно обновление: сегодня приложение заработало без видимых причин, я ничего не менял с тех пор, как последний раз пробовал. К сожалению, я не могу определить, работают ли исправления на данный момент! Чтобы быть уверенным, похоже, что мои ключи plist работают в моем симуляторе iOS 11.3.


person Alan Moore    schedule 14.05.2018    source источник
comment
Есть ли в вашем приложении какой-либо API/сетевой вызов? Я думаю, что вы загружаете песню и сохраняете ее локально, но из-за ATS файл песни не может быть сохранен в вашей локальной сети, так как HTTP-вызов не работает, поправьте меня, если я ошибаюсь.   -  person Abhishek Thapliyal    schedule 14.05.2018
comment
@AbhishekThapliyal - вы ошибаетесь, этот файл встроен в приложение, он не загружается.   -  person Alan Moore    schedule 14.05.2018
comment
Есть ли в вашем приложении какой-либо другой вызов API?   -  person Abhishek Thapliyal    schedule 14.05.2018
comment
Есть много вызовов API, но именно здесь отладчик прерывает исключение, поэтому я предполагаю, что это означает, что именно это вызвало исключение. Это плохое предположение?   -  person Alan Moore    schedule 14.05.2018
comment
Я также должен упомянуть, что исключение не возникает во время других вызовов API, оно возникает, когда я нажимаю кнопку воспроизведения, и это код, который выполняется в Play — в этом обработчике нет сетевых вызовов API.   -  person Alan Moore    schedule 14.05.2018
comment
Нет плохого предположения, просто для теста просто можете добавить ...... ‹key›NSAppTransportSecurity‹/key› ‹dict› ‹key›NSAllowsArbitraryLoads‹/key› ‹true/› ‹/dict›   -  person Abhishek Thapliyal    schedule 14.05.2018
comment
Давайте продолжим это обсуждение в чате.   -  person Abhishek Thapliyal    schedule 14.05.2018
comment
Вы добавили награду, но не предоставили подробности в чате. Пожалуйста, попробуйте вещи в чате. ATS не должен блокировать ничего, на что есть ссылки в локальной файловой системе. Я думаю, что здесь происходит что-то еще. В частности, включение ведения журнала CFNetwork, чтобы вы могли видеть URL-адрес, который он пытается загрузить. Может быть еще одна проблема, связанная с работой метода prepareToPlay.   -  person wottle    schedule 20.05.2018
comment
Пробовали ли вы с разными аудиофайлами? Другой m4a? мп3? Кроме того, вы пытались добавить ключ NSAllowsArbitraryLoadsForMedia? Вместо того, чтобы набирать все ATS, только для медиа (я знаю, что вам не нужно, но это, по крайней мере, менее опасное решение).   -  person wottle    schedule 22.05.2018
comment
Я нашел обходной путь — просто не вызывайте PrepareToPlay. Я пробовал все в чате. @wottle Я пробовал NSAllowsArbitraryLoadsForMedia, но это не сработало. Аудиофайл отлично работает на iPhone, поэтому я не думаю, что с ним что-то не так.   -  person Alan Moore    schedule 24.05.2018
comment
Re: Я не могу использовать ключ NSExceptionDomain, потому что это локальный ресурс, домена нет. Как я могу это исправить? На самом деле есть домен, localhost, возможно, попробуйте использовать его. Вот простой пример. И да, без PrepareToPlay пользователи со старыми устройствами могут столкнуться с такой большой задержкой, что они скорее выйдут, чем будут играть...   -  person l'L'l    schedule 24.05.2018
comment
Кроме того, используя NSAllowsArbitraryLoadsInWebContent, NSAllowsLocalNetworking, NSAllowsArbitraryLoadsForMedia, вы переопределяете NSAllowsArbitraryLoads. Я рекомендую прочитать первичные ключи словаря App Transport Security, чтобы понять, какие ключи следует включать. Включение конфликтующих ключей бессмысленно; вы просто получите такое же нежелательное поведение.   -  person l'L'l    schedule 24.05.2018
comment
Да @l'L'l, но важно отметить, что упомянутое вами переопределение применяется только в iOS10 и более поздних версиях. В iOS 9 включение обоих дает вам то преимущество, что оно будет работать в iOS9, где NSAllowsArbitraryLoadsForMedia еще не поддерживался, по-прежнему соблюдая общее «NSAllowsArbitraryLoads». Так что я бы не стал заявлять, что что-то бессмысленно, если это особая стратегия Apple, позволяющая обеспечить обратную совместимость. И это, конечно, не приводит к одинаковому поведению на разных версиях iOS. Я бы рекомендовал полностью понять ключи, прежде чем комментировать ложную информацию.   -  person wottle    schedule 24.05.2018
comment
@wottle: я могу предложить прочитать второе предложение вопроса ОП, я обновляю приложение до iOS 11.3.   -  person l'L'l    schedule 24.05.2018
comment
Если вам нужно узнать подробности, они находятся в ссылке, на которую вы ссылаетесь: в iOS 10 и более поздних версиях и macOS 10.12 и более поздних версиях значение этого ключа (NSAllowsArbitraryLoads) игнорируется, что приводит к эффективному значению для этого ключа его значение по умолчанию NO — если любой из следующих ключей присутствует в файле Info.plist вашего приложения: NSAllowsArbitraryLoadsForMedia NSAllowsArbitraryLoadsInWebContent NSAllowsLocalNetworking   -  person wottle    schedule 24.05.2018
comment
Независимо от вопроса, ваш комментарий неверен. Если бы вы уточнили свой комментарий, если бы вы могли гарантировать, что все ваши пользователи используют iOS 10 и более поздние версии..., это было бы, по крайней мере, ближе к правильному. Но ОП не сказал, что его приложение будет работать только на iOS 11.3. У него просто проблема на устройствах с iOS 11.3. Это не означает, что он хочет, чтобы у пользователей iOS9 возникала проблема, если он внесет плохое исправление.   -  person wottle    schedule 24.05.2018
comment
@wottle: Судя по заданному вопросу, предполагается, что приложение предназначено для работы на iOS 11.3. Наличие трех ключей, упомянутых вместе с NSAllowsArbitraryLoads, не принесет им абсолютно никакой пользы; какую часть этого вы не понимаете? Что не предполагается, так это то, что OP хочет или когда-либо упоминал, что для приложения требуется iOS 9. Почему именно установка правильных ключей может привести к плохому исправлению? Это нелепо.   -  person l'L'l    schedule 24.05.2018
comment
ты пробовал использовать pathForResource:ofType:   -  person Bimawa    schedule 24.05.2018
comment
Это устаревшее приложение, я хочу, чтобы оно продолжало работать на более старых версиях iOS. Когда я удалил другой NSURLConnection, я обнаружил, что мои ключи NSAllows* работают правильно, поэтому я не думаю, что это проблема.   -  person Alan Moore    schedule 25.05.2018
comment
@l'L'l Вы сделали общее заявление о том, что дополнительные ключи конфликтуют. Они не. В разных версиях iOS клавиши можно комбинировать так, чтобы они были полезны. Противоположность бессмысленному. Если бы вы сделали свое заявление с уточнением, что ключи переопределяют друг друга в более новых версиях iOS, по крайней мере, вы были бы ближе к истине. Дело в том, что вы пытались назвать что-то неправильным, когда это было не так.   -  person wottle    schedule 25.05.2018
comment
@AlanMoore Я согласен, что ключи, скорее всего, не твоя проблема. Меня беспокоит то, что если вы поместите «NSAllowsArbitraryLoads», это теоретически сделает так, что ATS не должен блокировать какие-либо соединения. Технически ATS не должен ничего блокировать для URL-адреса локального файла. Я до сих пор не уверен, почему это так, но мне было интересно, есть ли что-то в .mp4, которое пытается загрузить некоторые метаданные об аудиофайле. Когда вы включили ведение журнала CFNetwork, он должен был предоставить вам точный URL-адрес, который блокировался ATS, а не общее сообщение. Ты это видел?   -  person wottle    schedule 25.05.2018
comment
URL-адрес выглядит так: /Library/Cookies/com.mydomain.med.myappname.binarycookies -- но CFNetworkLogging не сообщает об ошибке? Как ни странно, он начал работать только сейчас. Возможно, это состояние гонки, которое у меня могут возникнуть проблемы с воспроизведением!   -  person Alan Moore    schedule 25.05.2018
comment
Да, вам действительно нужно включить CFNetwork Logging, когда вы получаете сообщение о том, что URL-адрес был заблокирован ATS. Я думаю, что это могло быть вызвано другим звонком.   -  person wottle    schedule 26.05.2018
comment
Возможно, но я никогда не видел этого в журнале, когда он терпел неудачу.   -  person Alan Moore    schedule 26.05.2018


Ответы (1)


В моем проекте используется AVAudioPlayer для воспроизведения звука и мой исходный код:

NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"MyFile"  ofType:@"m4a"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
AVAudioPlayer* audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
audioPlayer.numberOfLoops = -1; //Infinite
[audioPlayer setVolume:1];
[audioPlayer play];
person chaunv    schedule 25.05.2018
comment
Боюсь, проблема исчезла, ваше предложение действительно работает, но, к сожалению, я не могу сказать, устраняет ли оно ошибку, которую я видел до сегодняшнего дня! - person Alan Moore; 25.05.2018