3 Replies
      Latest reply on Oct 29, 2019 5:09 PM by weeto
      sockmonkey_liam Level 1 Level 1 (0 points)

        We're building a small Unity/iOS application with an Objective-C plug-in to provide access to MusicKit. I'm going through the announcement talk which takes you through the process to access each component of MusicKit.

         

        We've ticked off:

        • Authorization to Media Library
        • User Capabilities
        • Getting Storefront Access code

         

        Now we're onto the user token request and it's failing every time with the error SKErrorDomain Code=7, otherwise known as SKErrorCloudServiceNetworkConnectionFailed. The localised description written within the errors is 'Cannot connect to iTunes Store'. The final underlying error states that the HTTP status being returned is a 401 Unauthorized. See the full log of the response error here:

         

        Error Domain=SKErrorDomain Code=7 "(null)" UserInfo={NSUnderlyingError=0x283058c60 {Error Domain=SSErrorDomain Code=109 "(null)" UserInfo={NSUnderlyingError=0x2830589f0 {Error Domain=SSErrorDomain Code=109 "Cannot connect to iTunes Store" UserInfo={NSLocalizedDescription=Cannot connect to iTunes Store, SSErrorHTTPStatusCodeKey=401}}}}}

         

        I've found other responses to this particular error being cited as a bad developer token. This is potentially backed up as if I change the developer token in any way (replaced some random characters with 0s), I get the same response from the request, exactly as above with the same number of underlying errors.

         

        However, if I use 'Postman' go through the process of sending requests through the Web API instead, using the developer token as a Bearer Authorization token, I get valid 200 OK responses from a request to, for example:

         

        https://api.music.apple.com/v1/catalog/gb/songs/1161539476

         

        If I alter the token in any way, this GET request returns a 401 Unauthorized response.

         

        I've provided the relevant code below, redacted all irrelevant code. Any help would be really appreciated:

         

        #import <Foundation/Foundation.h>
        #import <StoreKit/StoreKit.h>
        
        @interface MusicKitPlugin : NSObject
        {
        }
        @end
        
        @implementation MusicKitPlugin
        
        static MusicKitPlugin *_sharedInstance;
        SKCloudServiceController *_csController;
        NSString *_developerToken;
        NSString *_userToken;
        
        +(MusicKitPlugin*) sharedInstance
        {
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{
                NSLog(@"Creating MusicKitPlugin shared instance");
                _sharedInstance = [[MusicKitPlugin alloc] init];
            });
            return _sharedInstance;
        }
        
        -(id)init
        {
            self = [super init];
            if (self)
            {
                _csController = [SKCloudServiceController new];
                _developerToken = @"{INSERT_DEV_TOKEN}";
                _userToken = @"";
            }
            return self;
        }
        
        -(void)requestUserToken
        {
            NSLog(@"Request user token called");
            [_csController requestUserTokenForDeveloperToken:_developerToken
                                           completionHandler:^(NSString *userToken, NSError *error)
             {
                 NSLog(@"User token request responded");
                 
                 if(userToken != NULL)
                 {
                     NSLog(@"User token: %@", userToken);
                      _userToken = userToken;
                 }
                 else if (error != NULL)
                 {
                     [self handleError:error];
                 }
             }];
        }
        
        -(void)handleError:(NSError *)error
        {
            NSLog(@"Error: %@", error);
            
            NSLog(@"Error domain: %@", [error domain]);
            NSLog(@"Error code: %ld", [error code]);
            NSLog(@"Error user info: %@", [error userInfo]);
            switch ([error code]) {
                  ...
                case SKErrorCloudServiceNetworkConnectionFailed:
                    NSLog(@"Cloud service network connection failed");
                    break;
                  ...
            }
        }
        
        @end
        
        extern "C"
        {
            void IOS_RequestUserToken()
            {
                [[MusicKitPlugin sharedInstance] requestUserToken];
            }
        }
        
        

         

        So I tap a button in Unity, that button calls the IOS_RequestUserToken method that is linked to in a MonoBehaviour in Unity from the Objective-C plug-in. That calls the requestUserToken function of the shared instance plug-in and it outputs:

         

        Request user token called
        
        User token request responded
        
        Error: Error Domain=SKErrorDomain Code=7 "(null)" UserInfo={NSUnderlyingError=0x283058c60 {Error Domain=SSErrorDomain Code=109 "(null)" UserInfo={NSUnderlyingError=0x2830589f0 {Error Domain=SSErrorDomain Code=109 "Cannot connect to iTunes Store" UserInfo={NSLocalizedDescription=Cannot connect to iTunes Store, SSErrorHTTPStatusCodeKey=401}}}}}
        
        Error domain: SKErrorDomain
        
        Error code: 7
        
        Error user info: {
            NSUnderlyingError = "Error Domain=SSErrorDomain Code=109 \"(null)\" UserInfo={NSUnderlyingError=0x2830589f0 {Error Domain=SSErrorDomain Code=109 \"Cannot connect to iTunes Store\" UserInfo={NSLocalizedDescription=Cannot connect to iTunes Store, SSErrorHTTPStatusCodeKey=401}}}";
        }
        
        Cloud service network connection failed
        
        
        • Re: [MusicKit] User Token request with Developer Token returns SKErrorCloudServiceNetworkConnectionFailed
          sockmonkey_liam Level 1 Level 1 (0 points)

          For the benefit of anyone who may run into this issue in the future, it turns out the same error returned by an invalid developer token is also returned in the scenario that a user is not an Apple Music subcriber.

           

          Makes sense when you think about it and a bit daft on my side but it's also an issue that you can't set up any sandbox accounts to purchase a subscription and you have to have a genuine subscription in order to test any MusicKit work.

          1 of 1 people found this helpful
          • Re: [MusicKit] User Token request with Developer Token returns SKErrorCloudServiceNetworkConnectionFailed
            weeto Level 1 Level 1 (0 points)

            In my case I was getting exactly the same error with 401 unauthorized. During the call to requestUserTokenForDeveloperToken the system opened an alert asking to enter password from my Apple account (the one connected to Music), but even that didn't help.

             

            I assume it was because I was developing on my daughter's iPhone. It has a child Apple ID set up, and Apple Music account is available to that account through Family Subscription, she is set up as a family member. That might explain the restricions and the errors.

             

            It might also be that somewhere in Apple ID there is a preference saying that it should always ask for a password whenever an operation is done regarding Store, not sure.

             

            Note, that even though music user token doesn't work, the app plays songs from Apple Music just fine, it is just user data that I cannot retrieve.

             

            Trying the same code and the same developer token generation with another "normal" "grown up" account works fine, music user token was successfully retrieved.