audio_service
audio_service copied to clipboard
fix: entitlement requirement issue on iOS devices
There is an iOS Release builds where the audio won't play due to the error below:
[NowPlaying] [MRNowPlaying] Ignoring setPlaybackState because application does not contain entitlement com.apple.mediaremote.set-playback-state for platform
Closed issue that this PR fixes.
Pre-launch Checklist
- [x] I read the [CONTRIBUTING.md] and followed the process outlined there for submitting PRs.
- [x] My change is not breaking and lands in
minor
branch OR my change is breaking and lands inmajor
branch. - [x] If I'm the first to contribute to the next version, I incremented the version number in
pubspec.yaml
according to the [pub versioning philosophy]. - [x] I updated CHANGELOG.md to add a description of the change (format:
* DESCRIPTION OF YOUR CHANGE (@your-git-username)
). - [x] I updated/added relevant documentation (doc comments with
///
). - [x] I ran
dart analyze
. - [x] I ran
dart format
. - [x] I ran
flutter test
and all tests are passing.
Thanks @pedromassango . I'd like to test this against a minimal reproduction project, but I actually never saw a valid issue submitted for this and was unclear whether it was a build error or a runtime error. How can I test/reproduce this?
I will let you know once I have a reproducible code
I see the same issue for iOS in my app - it is not a critical error and everything seems to be working well, but I see numerous of such messages in the log:
[NowPlaying] [MRNowPlaying] Ignoring setPlaybackState because application does not contain entitlement com.apple.mediaremote.set-playback-state for platform
Yes, since the message says "Ignoring setPlaybackState", I would have expected it to be harmless, so it's surprising it turns out this can be critical and prevent audio from playing.
Yes, but I agree that
center.playbackState = playing ? MPNowPlayingPlaybackStatePlaying : MPNowPlayingPlaybackStatePaused;
should be executed on MacOS only. As the docs say: https://developer.apple.com/documentation/mediaplayer/mpnowplayinginfocenter/2588243-playbackstate?language=objc
This property only applies to macOS. You must set this property every time the app begins or halts playback, otherwise remote control functionality may not work as expected.
Yep I definitely agree with that. I think I have a habit of only looking in the sidebar of the documentation which says it is available on these specific versions of iOS and macOS, although the body clearly overrides that information.
I guess I would just like to be able to reproduce this myself before merging, and I'm not sure exactly what the observed behaviour is or how to reproduce it yet.
I have the same problem, but my audio works. I don't know if problems with the remoteControlFunctionality can result. When can we get this fix in the stable release of the plugin? Thanks
Just waiting for @pedromassango to provide instructions on how to reproduce the problem of audio not playing.
@csacchetti can you maybe test this PR and confirm whether it solves your issue?
After testing this PR I'm getting:
/Volumes/Samsung_T5/projects/audio_service/audio_service/darwin/Classes
/AudioServicePlugin.m:291:9: error: implicit declaration of function 'os'
is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (os(macOS)) {
Looks like this is a Swift construct, and for Objective-C you need to use one of the TARGET_OS_*
tests:
https://epir.at/2019/10/30/api-availability-and-target-conditionals/
@ryanheise Here is a link to a tutorial using audio_service 0.18 a Just audio that gives this problem.
[NowPlaying] [MRNowPlaying] Ignoring setPlaybackState because application does not contain entitlement com.apple.mediaremote.set-playback-state for platform
Here is the link to the tutorial: https://suragch.medium.com/background-audio-in-flutter-with-audio-service-and-just-audio-3cce17b4a7d
You can download repository here: https://github.com/suragch/flutter_audio_service_demo
Did you test the pr?
I think this PR needs to use #if TARGET_OS_OSX
instead of if (os(macOS))
and it should also still keep the @available
checks since it is still only available on specific versions.
Before I can merge this, I think we should also ensure that the change works on both macOS and iOS (i.e. the controls appear in the control center in both cases correctly after play/pause).
Edit: from my tests, this seems to make iOS stop working, in that the controls no longer appear on the lock screen while playing. Can anyone confirm?
Some more insight on the original issue: The problem even exists on the example app in audio_service (I am using an old iPhone SE as a real test device).
I tried to use the version by @pedromassango, but upon compiling I got the following errors:
Failed to build iOS app
Error output from Xcode build:
↳
2022-02-26 02:00:32.241 xcodebuild[14740:278522] DVTAssertions: Warning in
/Library/Caches/com.apple.xbs/Sources/DVTiOSFrameworks/DVTiOSFrameworks-19527/DTDeviceKitBase/DTDKRemoteDeviceData.m:373
Details: (null) deviceType from 8ee3fe031ab04f598ab8fc9e5011f2c91ca27d4f was NULL when -platform called.
Object: <DTDKMobileDeviceToken: 0x7fb1e8550eb0>
Method: -platform
Thread: <NSThread: 0x7fb1e8427fe0>{number = 7, name = (null)}
Please file a bug at https://feedbackassistant.apple.com with this warning message and any useful information you can provide.
2022-02-26 02:00:33.277 xcodebuild[14740:278555] CFURLRequestSetHTTPCookieStorageAcceptPolicy_block_invoke: no longer implemented and should not be called
** BUILD FAILED **
Xcode's output:
↳
Writing result bundle at path:
/var/folders/40/r2px4_ms1k56lqv5lm07c0yc0000gn/T/flutter_tools.b4B02o/flutter_ios_build_temp_dir7s9Fsr/temporary_xcresult_bundle
Command CompileSwiftSources failed with a nonzero exit code
/Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:291:9: error: implicit declaration of function 'os' is invalid in C99
[-Werror,-Wimplicit-function-declaration]
if (os(macOS)) {
^
/Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:291:12: error: use of undeclared identifier 'macOS'
if (os(macOS)) {
^
/Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:292:42: warning: 'MPNowPlayingPlaybackStatePlaying' is only available on iOS 11.0 or newer
[-Wunguarded-availability-new]
center.playbackState = playing ? MPNowPlayingPlaybackStatePlaying : MPNowPlayingPlaybackStatePaused;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In module 'MediaPlayer' imported from /Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:3:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/System/Library/Frameworks/MediaPlayer.framework/Headers/MPNowPlayingInfoCenter.h:
44:29: note: 'MPNowPlayingPlaybackState' has been marked as being introduced in iOS 11.0 here, but the deployment target is iOS 9.0.0
typedef NS_ENUM(NSUInteger, MPNowPlayingPlaybackState) {
^
/Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:292:42: note: enclose 'MPNowPlayingPlaybackStatePlaying' in an @available check to silence
this warning
center.playbackState = playing ? MPNowPlayingPlaybackStatePlaying : MPNowPlayingPlaybackStatePaused;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:292:77: warning: 'MPNowPlayingPlaybackStatePaused' is only available on iOS 11.0 or newer
[-Wunguarded-availability-new]
center.playbackState = playing ? MPNowPlayingPlaybackStatePlaying : MPNowPlayingPlaybackStatePaused;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In module 'MediaPlayer' imported from /Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:3:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/System/Library/Frameworks/MediaPlayer.framework/Headers/MPNowPlayingInfoCenter.h:
44:29: note: 'MPNowPlayingPlaybackState' has been marked as being introduced in iOS 11.0 here, but the deployment target is iOS 9.0.0
typedef NS_ENUM(NSUInteger, MPNowPlayingPlaybackState) {
^
/Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:292:77: note: enclose 'MPNowPlayingPlaybackStatePaused' in an @available check to silence this
warning
center.playbackState = playing ? MPNowPlayingPlaybackStatePlaying : MPNowPlayingPlaybackStatePaused;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:292:16: warning: 'setPlaybackState:' is only available on iOS 13.0 or newer
[-Wunguarded-availability-new]
center.playbackState = playing ? MPNowPlayingPlaybackStatePlaying : MPNowPlayingPlaybackStatePaused;
^~~~~~~~~~~~~
In module 'MediaPlayer' imported from /Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:3:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/System/Library/Frameworks/MediaPlayer.framework/Headers/MPNowPlayingInfoCenter.h:
70:49: note: 'setPlaybackState:' has been marked as being introduced in iOS 13.0 here, but the deployment target is iOS 9.0.0
@property (nonatomic) MPNowPlayingPlaybackState playbackState MP_API(macos(10.12.2), ios(13.0), macCatalyst(13.0));
^
/Users/daniel/development/audio_service/audio_service/darwin/Classes/AudioServicePlugin.m:292:16: note: enclose 'setPlaybackState:' in an @available check to silence this warning
center.playbackState = playing ? MPNowPlayingPlaybackStatePlaying : MPNowPlayingPlaybackStatePaused;
^~~~~~~~~~~~~
3 warnings and 2 errors generated.
note: Using new build system
note: Planning
note: Build preparation complete
note: Building targets in dependency order
/Users/daniel/development/audio_service/audio_service/example/ios/Pods/Pods.xcodeproj: warning: The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of
supported deployment target versions is 9.0 to 15.2.99. (in target 'FMDB' from project 'Pods')
Result bundle written to path:
/var/folders/40/r2px4_ms1k56lqv5lm07c0yc0000gn/T/flutter_tools.b4B02o/flutter_ios_build_temp_dir7s9Fsr/temporary_xcresult_bundle
Output of flutter doctor:
[✓] Flutter (Channel stable, 2.10.2, on macOS 11.6.4 20G417 darwin-x64, locale en-GB)
• Flutter version 2.10.2 at /Users/daniel/development/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 097d3313d8 (7 days ago), 2022-02-18 19:33:08 -0600
• Engine revision a83ed0e5e3
• Dart version 2.16.1
• DevTools version 2.9.2
[✗] Android toolchain - develop for Android devices
✗ Unable to locate Android SDK.
Install Android Studio from: https://developer.android.com/studio/index.html
On first launch it will assist you in installing the Android SDK components.
(or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
If the Android SDK has been installed to a custom location, please use
`flutter config --android-sdk` to update to that location.
[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• CocoaPods version 1.10.0.beta.2
[✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome)
! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[!] Android Studio (not installed)
• Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
[✓] IntelliJ IDEA Community Edition (version 2020.2)
• IntelliJ at /Applications/IntelliJ IDEA CE.app
• Flutter plugin installed
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
[✓] Connected device (2 available)
• iPhone von Daniel (mobile) • 8ee3fe031ab04f598ab8fc9e5011f2c91ca27d4f • ios • iOS 14.8 18H17
• macOS (desktop) • macos • darwin-x64 • macOS 11.6.4 20G417 darwin-x64
! Error: iPhone von Daniel is busy: Fetching debug symbols for iPhone von Daniel. Xcode will continue when iPhone von Daniel is finished. (code -10)
[✓] HTTP Host Availability
• All required HTTP hosts are available
! Doctor found issues in 3 categories.
I tried to use the version by @pedromassango, but upon compiling I got the following errors:
Yes, that is a problem with this PR, and I have mentioned in my previous comment what needs to be done to fix this before I can merge this:
I think this PR needs to use
#if TARGET_OS_OSX
instead ofif (os(macOS))
and it should also still keep the@available
checks since it is still only available on specific versions.
Just waiting for @pedromassango to provide instructions on how to reproduce the problem of audio not playing.
Hey, so sorry fo the late reply here. After a while I was able to find out that the issue is not related with this change. I will go ahead and close this PR as the problem I was facing as nothing to do with it!
Sorry y’all!
It is true that the audio is still heard and everything works, but I think it is better to remove this message in the console: [NowPlaying] [MRNowPlaying] Ignoring setPlaybackState because application does not contain entitlement com.apple.mediaremote.set-playback-state for platform
Yes I agree something should be done about that, but has anyone tested the changes @pedromassango proposed but using the #if TARGET_OS_OSX
code instead? I am not sure if it has the desired result on all platforms.
Reopening.
Yes I agree something should be done about that, but has anyone tested the changes @pedromassango proposed but using the
#if TARGET_OS_OSX
code instead? I am not sure if it has the desired result on all platforms.
Ok then, honestly I don't have much experience with native iOS 🐒 I will try to test this and give a feedback asap
Has anyone tried this solution and tested on both iOS and macOS?
Any updates on this? I ran into this issue (not sure if it's an entitlement or provisioning issue that I'm having) and I can't do background playback, although this plugin is working great for me on android :)
FYI: When I try to build this version of the source code on iOS I do get the same error:
/Volumes/Samsung_T5/projects/audio_service/audio_service/darwin/Classes
/AudioServicePlugin.m:291:9: error: implicit declaration of function 'os'
FYI I got this to work on iOS by adding
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
to my Info.plist. I guess I missewd that part of the documentation! Sorry! I still see the error though but it doesn't seem to matter. The play / pause buttons still work from the UI
Regarding the os
error, see this commment:
https://github.com/ryanheise/audio_service/pull/900#issuecomment-1031272743
I tried to read some iOS documentation and it seems to me that the problem might be related to: MPNowPlayingInfoCenter.default().playbackState
In fact, the solution proposed by the forums is this;
https://developer.apple.com/forums/thread/678108 Solution: don't use MPNowPlayingInfoCenter.default().playbackState Why: I only care about iOS. This doc shows that this is only for macOS https://developer.apple.com/documentation/mediaplayer/mpnowplayinginfocenter/2588243-playbackstate
So if you don't have macOS enabled in xCode you don't have the com.apple.mediaremote.set-playback-state entitlements for the macOS playback state, and so if the Audio Service plugin also supports macOS it is likely to use MPNowPlayingInfoCenter.default().playbackState and thus create the problem.
I have no interest in enabling MacOs for my app (is only for iOS and Android) so I can't verify this but I think @ryanheise could enable this command only if MacOs is enabled and instead disable it if MacOs is not enabled
This explains why in spite of this problem in iOS everything works correctly.
I hope it helps
That is why I referred readers to https://github.com/ryanheise/audio_service/pull/900#issuecomment-1031272743 which explains how to correctly "compile out" this code when it is not needed on iOS.
The main reason that this PR hasn't been merged yet is that it does not use the correct preprocessing instructions to do this. The secondary reason is that it needs to be tested and verified to ensure that people no longer get the warning/
@ryanheise I honestly think that this is not the fix for the problem I stated in the original post. I would suggest to close this!
I am getting this same error, everything is working except for custom click() in audio_service. In Android I am able to do custom action based on the headset clicks, but not on iOS at all. For iOS the headset does the default actions instead. Do you think this error is related to that somehow?
I saw this comment on one of Apple's forums:
playbackState is available for MacOS but also for CarPlay implementation. Only by using playbackState I got correct behaviour with CarPlay on simulator.
Can this be the cause of the issue? I don't have CarPlay entitlement for my app, and I do see this warning message. I am applying for CarPlay entitlement. I will test when I get approved.
I did a quick test of the proposed changes in this PR and confirmed the way @ryanheise proposes to fix it - works.
NSLog(@"### ENSURE THIS IS UPDATED CODE 0.18.12 Darwin");
#if TARGET_OS_OSX
if (@available(iOS 13.0, macOS 10.12.2, *)) {
center.playbackState = playing ? MPNowPlayingPlaybackStatePlaying : MPNowPlayingPlaybackStatePaused;
}
#endif
And then logs are clear when testing on iOS
2023-09-27 13:17:08.334248+0300 Sudor Staging[1347:69326] flutter: AUDIO MANAGER AUDIOSESSION CALL 8
flutter: AUDIO MANAGER AUDIOSESSION CALL 8
2023-09-27 13:17:08.439089+0300 Sudor Staging[1347:69278] ### ENSURE THIS IS UPDATED CODE 0.18.12 iOS
2023-09-27 13:17:08.444080+0300 Sudor Staging[1347:69278] ### ENSURE THIS IS UPDATED CODE 0.18.12 iOS
2023-09-27 13:17:08.457794+0300 Sudor Staging[1347:69278] ### ENSURE THIS IS UPDATED CODE 0.18.12 iOS
2023-09-27 13:17:08.644577+0300 Sudor Staging[1347:69278] ### ENSURE THIS IS UPDATED CODE 0.18.12 iOS
Important - not only darwin/Classes/AudioServicePlugin.m
file needs to be changed, but also:
ios/Classes/AudioServicePlugin.m
macos/Classes/AudioServicePlugin.m
I'm struggling with how to test it with macOS, but I will manage later this week, I hope.