presentMediaPlayerControllerWithURL -> Operation not permitted

I can't believe it's GM version..

I updated to GM version iOS9.0(13A340), WatchOS 2.0(13S343), and Xcode as well.

What I really wanted to do was Playing sound with WKAudioFilePlayer. However, everyone who has wrestled with the API knows that THE API DOES NOT WORK AT ALL EVEN ON GM VERSION.

Okay, now I just give up, and try workaround with presentMediaPlayerControllerWithURL. However, while it plays sound well on the simulator, it shows error log on the device as below:


Optional(Error Domain=com.apple.watchkit.errors Code=4 "The operation could not be completed" UserInfo={NSLocalizedFailureReason=An unknown error occurred (1), NSUnderlyingError=0x17d9bf50 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}, NSLocalizedDescription=The operation could not be completed})

Operation not permitted?? ARE YOU KIDDING ME?

Oy vey. Is there anyone who've got through with this problem?

Yep. Same thing, except these kind of messages in the Watch console too:


Sandbox: Watch(439) deny(1) file-issue-extension /private/var/mobile/Containers/Data/PluginKitPlugin/B43ECE11-F2DC-433D-9787-593B5939E18B/Documents

Sandbox: Watch(439) deny(1) file-read-data /private/var/mobile/Containers/Data/PluginKitPlugin/B43ECE11-F2DC-433D-9787-593B5939E18B/Documents/e4c5cf03-3a67-4c01-b6f4-5417c4816b32.mp3

Sandbox: Watch(439) deny(1) file-read-metadata /private/var/mobile/Containers/Data/PluginKitPlugin/B43ECE11-F2DC-433D-9787-593B5939E18B/Documents/e4c5cf03-3a67-4c01-b6f4-5417c4816b32.mp3

Sandbox: mediaserverd(36) deny(1) file-read-data /private/var/mobile/Containers/Data/PluginKitPlugin/B43ECE11-F2DC-433D-9787-593B5939E18B/Documents/e4c5cf03-3a67-4c01-b6f4-5417c4816b32.mp3

Accepted Answer

From doc:


  • Place media clips that ship with your app inside the bundle of your WatchKit extension. Your WatchKit extension is located inside your Watch app bundle, so your Watch app can access any files in the extension’s bundle directory. In your extension code, use the methods of the
    NSBundle
    class to locate the files inside your extension’s bundle.
  • Place media files that you download from the network (or transfer from your iOS app) in a shared group container. A shared group container provides common storage for your Watch app and WatchKit extension. In your extension code, create URLs for any media files inside the container, and use them to configure the media interfaces.

In the first case, have you checked in Xcode that the file belongs to the desired target (extension's bundle directory)?

In the second case (the console log shows that there is not that case, but anyway...), have you enabled app groups in the target?

In my case, I download files to a shared container, and all goes well.

Do you have any code that you could share?

Thanks!

For sure! (I suppose you are talking about the second case)


First, you have to create the shared container in the project or the provisioning portal. In Xcode you can do by selecting your target - capabilities - App Groups, activate the feature, and clicking in the plus sign. Use a new identifier (usually in the form group.yourcompany.yourapp).


Assuming you have downloaded a file using NSURLConnection (https://developer.apple.com/library/prerelease/watchos/documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html - listings 2.1 through 2.5, easy source code) you'll have a NSMutableData with the content of the file. After that, you need to store in the shared container you created.


The code that performs that is something like this:


    NSMutableData *soundFile=[yourDownloadedNSMutableData];

    NSURL *container= [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.yourcompany.yourapp"];
    NSURL *filePath = [container URLByAppendingPathComponent:@"yourFilename.mp3"];

    NSError *error;

    NSDictionary* options = @{WKMediaPlayerControllerOptionsAutoplayKey : @YES,
                              WKMediaPlayerControllerOptionsLoopsKey:@NO};

    [self presentMediaPlayerControllerWithURL:filePath
                                      options:options
                                   completion:^(BOOL didPlayToEnd, NSTimeInterval endTime, NSError * __nullable error) {
                                      if (error)
                                          NSLog(@"Error: %@", [error description]);
                                 
                                      NSLog(@"AC/DC should have sounded fine ;)");
                                  }];


Haven't checked the syntax, but anyway, it is easy to read.

Good luck!

i adding this codes form apple sample codes
- (IBAction)playLastRecording {


    NSURL *container= [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.Rec"];
    NSURL *filePath = [container URLByAppendingPathComponent:self.lastRecordingURL.path];



    NSDictionary* options = @{WKMediaPlayerControllerOptionsAutoplayKey : @YES,
                              WKMediaPlayerControllerOptionsLoopsKey:@NO};

    [self presentMediaPlayerControllerWithURL:filePath
                                      options:options
                                   completion:^(BOOL didPlayToEnd, NSTimeInterval endTime, NSError * __nullable error) {
                                       if (error)
                                           NSLog(@"Error: %@", [error description]);
                                 
                                       NSLog(@"AC/DC should have sounded fine ;)");
                                   }];


}


Error: Error Domain=com.apple.watchkit.errors Code=4 "The requested URL was not found on this server." UserInfo={NSUnderlyingError=0x14d9bc70 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}, NSLocalizedDescription=The requested URL was not found on this server.}

[198:17634] AC/DC should have sounded fine 😉
how to call correctly

strongSelf.lastRecordingURL = outputExtensionURL;

NSLog(@"lastRecordingURL: %@.", strongSelf.lastRecordingURL);

in - (IBAction)playLastRecording {}

presentMediaPlayerControllerWithURL -> Operation not permitted
 
 
Q