├── LICENSE ├── StorefrontAssistant.swift ├── README.md └── StorefrontCountries.plist /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /StorefrontAssistant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StorefrontAssistant.swift 3 | // StorefrontAssistant 4 | // 5 | // Created by Ben Dodson on 26/02/2016. 6 | // Copyright © 2016 Dodo Apps. All rights reserved. 7 | // 8 | 9 | import StoreKit 10 | 11 | class StorefrontAssistant: NSObject { 12 | 13 | class func countryCode(completionHandler: ((countryCode: String?, error: NSError?) -> Void)) { 14 | 15 | 16 | SKCloudServiceController.requestAuthorization { (status) in 17 | if status != SKCloudServiceAuthorizationStatus.Authorized { 18 | completionHandler(countryCode: nil, error: NSError(domain: "SKCloudServiceController", code: 401, userInfo: [NSLocalizedDescriptionKey: "Not authorized to access Apple Music.", "SKCloudServiceAuthorizationStatus": NSNumber(integer:status.rawValue)])) 19 | return 20 | } 21 | 22 | let controller = SKCloudServiceController() 23 | controller.requestStorefrontIdentifierWithCompletionHandler({ (identifier, error) in 24 | if let error = error { 25 | completionHandler(countryCode: nil, error: error) 26 | return 27 | } 28 | 29 | guard let identifier = identifier?.componentsSeparatedByString(",").first?.componentsSeparatedByString("-").first else { 30 | completionHandler(countryCode: nil, error: NSError(domain: "SKCloudServiceController", code: 404, userInfo: [NSLocalizedDescriptionKey: "No identifier returned from SKCloudServiceController"])) 31 | return 32 | } 33 | 34 | guard let url = NSBundle.mainBundle().URLForResource("StorefrontCountries", withExtension: "plist"), storefronts = NSDictionary(contentsOfURL: url) else { 35 | completionHandler(countryCode: nil, error: NSError(domain: "StorefrontAssistant", code: 500, userInfo: [NSLocalizedDescriptionKey: "Could not load StorefrontCountries.plist"])) 36 | return 37 | } 38 | 39 | guard let code = storefronts[identifier] as? String else { 40 | completionHandler(countryCode: nil, error: NSError(domain: "StorefrontAssistant", code: 500, userInfo: [NSLocalizedDescriptionKey: "Could not find a country code for \(identifier)"])) 41 | return 42 | } 43 | 44 | completionHandler(countryCode: code, error: nil) 45 | }) 46 | } 47 | 48 | 49 | 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Storefront Assistant 2 | 3 | This is a simple class to assist in the conversion of a Storefront Identifier (from SKCloudServiceController) into a standard ISO country code for use with the iTunes Search API. 4 | 5 | ## Installation 6 | 7 | Just include the `StorefrontAssistant.swift` and `StorefrontCountries.plist` in your iOS 9.3 compatible project. 8 | 9 | ## Example Usage 10 | 11 | StorefrontAssistant.countryCode { (countryCode, error) in 12 | if let error = error { 13 | NSLog("Error: \(error)") 14 | } 15 | if let countryCode = countryCode { 16 | NSLog("Country code: \(countryCode)") 17 | } 18 | } 19 | 20 | Storefront Assistant will automatically request permissions to access the Media Library and then fetch the current storefront identifier for the logged in user. If there are any issues (i.e. permissions denied, no connectivity, country code can't be found) then an `NSError` will be returned. 21 | 22 | ## Use case 23 | 24 | If you want to either play Apple Music or save an Apple Music track to the user's media library, you will need to know which country they are in so you can find the relevant track identifier via the [iTunes Search API](https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/). The only way to know which country the logged in user's Apple Music account is with is to use the `SKCloudServiceController` method `requestStorefrontIdentifierWithCompletionHandler:` which will give you an identifier to match up to the store. Using this class, you can do a simple compare against the list which was parsed from [Apple's iTunes Affliate Links website](https://affiliate.itunes.apple.com/resources/documentation/linking-to-the-itunes-music-store/). 25 | 26 | ## Learn more 27 | 28 | - [iOS 9.3 Music Library Additions](https://bendodson.com/weblog/2016/02/23/details-on-ios-9-3-media-library-additions/) 29 | - [Introducing Storefront Assistant](https://bendodson.com/weblog/2016/02/26/storefront-additions-skcloudservicecontroller-to-country-code/) 30 | - [Your iOS Music Library is a security and privacy risk](https://bendodson.com/weblog/2016/01/13/your-music-library-is-a-security-and-privacy-risk-on-ios/) 31 | 32 | ## JSON Implementation 33 | 34 | [Loreto Parisi](https://twitter.com/loretoparisi) has [put together some code](https://github.com/loretoparisi/itunes-countrycode-node) in order to provide the plist file as a JSON; he also has a [Node JS implementation](https://github.com/loretoparisi/itunes-countrycode-node) to scrape this information regularly from the iTunes Affiliate Link Website. The StorefrontAssistant class could be easily converted to use this JSON file or you may want to convert his scraper to export to plist. -------------------------------------------------------------------------------- /StorefrontCountries.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 143563 6 | DZ 7 | 143564 8 | AO 9 | 143538 10 | AI 11 | 143540 12 | AG 13 | 143505 14 | AR 15 | 143524 16 | AM 17 | 143460 18 | AU 19 | 143445 20 | AT 21 | 143568 22 | AZ 23 | 143559 24 | BH 25 | 143490 26 | BD 27 | 143541 28 | BB 29 | 143565 30 | BY 31 | 143446 32 | BE 33 | 143555 34 | BZ 35 | 143542 36 | BM 37 | 143556 38 | BO 39 | 143525 40 | BW 41 | 143503 42 | BR 43 | 143543 44 | VG 45 | 143560 46 | BN 47 | 143526 48 | BG 49 | 143455 50 | CA 51 | 143544 52 | KY 53 | 143483 54 | CL 55 | 143465 56 | CN 57 | 143501 58 | CO 59 | 143495 60 | CR 61 | 143527 62 | CI 63 | 143494 64 | HR 65 | 143557 66 | CY 67 | 143489 68 | CZ 69 | 143458 70 | DK 71 | 143545 72 | DM 73 | 143508 74 | DO 75 | 143509 76 | EC 77 | 143516 78 | EG 79 | 143506 80 | SV 81 | 143518 82 | EE 83 | 143447 84 | FI 85 | 143442 86 | FR 87 | 143443 88 | DE 89 | 143573 90 | GH 91 | 143448 92 | GR 93 | 143546 94 | GD 95 | 143504 96 | GT 97 | 143553 98 | GY 99 | 143510 100 | HN 101 | 143463 102 | HK 103 | 143482 104 | HU 105 | 143558 106 | IS 107 | 143467 108 | IN 109 | 143476 110 | ID 111 | 143449 112 | IE 113 | 143491 114 | IL 115 | 143450 116 | IT 117 | 143511 118 | JM 119 | 143462 120 | JP 121 | 143528 122 | JO 123 | 143517 124 | KZ 125 | 143529 126 | KE 127 | 143466 128 | KR 129 | 143493 130 | KW 131 | 143519 132 | LV 133 | 143497 134 | LB 135 | 143522 136 | LI 137 | 143520 138 | LT 139 | 143451 140 | LU 141 | 143515 142 | MO 143 | 143530 144 | MK 145 | 143531 146 | MG 147 | 143473 148 | MY 149 | 143488 150 | MV 151 | 143532 152 | ML 153 | 143521 154 | MT 155 | 143533 156 | MU 157 | 143468 158 | MX 159 | 143523 160 | MD 161 | 143547 162 | MS 163 | 143484 164 | NP 165 | 143452 166 | NL 167 | 143461 168 | NZ 169 | 143512 170 | NI 171 | 143534 172 | NE 173 | 143561 174 | NG 175 | 143457 176 | NO 177 | 143562 178 | OM 179 | 143477 180 | PK 181 | 143485 182 | PA 183 | 143513 184 | PY 185 | 143507 186 | PE 187 | 143474 188 | PH 189 | 143478 190 | PL 191 | 143453 192 | PT 193 | 143498 194 | QA 195 | 143487 196 | RO 197 | 143469 198 | RU 199 | 143479 200 | SA 201 | 143535 202 | SN 203 | 143500 204 | RS 205 | 143464 206 | SG 207 | 143496 208 | SK 209 | 143499 210 | SI 211 | 143472 212 | ZA 213 | 143454 214 | ES 215 | 143486 216 | LK 217 | 143548 218 | KN 219 | 143549 220 | LC 221 | 143550 222 | VC 223 | 143554 224 | SR 225 | 143456 226 | SE 227 | 143459 228 | CH 229 | 143470 230 | TW 231 | 143572 232 | TZ 233 | 143475 234 | TH 235 | 143539 236 | BS 237 | 143551 238 | TT 239 | 143536 240 | TN 241 | 143480 242 | TR 243 | 143552 244 | TC 245 | 143537 246 | UG 247 | 143444 248 | GB 249 | 143492 250 | UA 251 | 143481 252 | AE 253 | 143514 254 | UY 255 | 143441 256 | US 257 | 143566 258 | UZ 259 | 143502 260 | VE 261 | 143471 262 | VN 263 | 143571 264 | YE 265 | 266 | 267 | --------------------------------------------------------------------------------